Skip to main content

crux_kv/protocol/
mod.rs

1pub mod value;
2
3use crux_core::capability::Operation;
4use facet::Facet;
5use serde::{Deserialize, Serialize};
6
7use crate::error::KeyValueError;
8pub use value::*;
9
10/// Supported operations
11#[derive(Facet, Clone, Serialize, Deserialize, PartialEq, Eq)]
12#[repr(C)]
13pub enum KeyValueOperation {
14    /// Read bytes stored under a key
15    Get { key: String },
16    /// Write bytes under a key
17    Set {
18        key: String,
19        #[serde(with = "serde_bytes")]
20        value: Vec<u8>,
21    },
22    /// Remove a key and its value
23    Delete { key: String },
24    /// Test if a key exists
25    Exists { key: String },
26    // List keys that start with a prefix, starting at the cursor
27    ListKeys {
28        /// The prefix to list keys for, or an empty string to list all keys
29        prefix: String,
30        /// The cursor to start listing from, or 0 to start from the beginning.
31        /// If there are more keys to list, the response will include a new cursor.
32        /// If there are no more keys, the response will include a cursor of 0.
33        /// The cursor is opaque to the caller, and should be passed back to the
34        /// `ListKeys` operation to continue listing keys.
35        /// If the cursor is not found for the specified prefix, the response will include
36        /// a `KeyValueError::CursorNotFound` error.
37        cursor: u64,
38    },
39}
40
41impl std::fmt::Debug for KeyValueOperation {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        match self {
44            KeyValueOperation::Get { key } => f.debug_struct("Get").field("key", key).finish(),
45            KeyValueOperation::Set { key, value } => {
46                let body_repr = if let Ok(s) = std::str::from_utf8(value) {
47                    if s.len() < 50 {
48                        format!("\"{s}\"")
49                    } else {
50                        format!("\"{}\"...", s.chars().take(50).collect::<String>())
51                    }
52                } else {
53                    format!("<binary data - {} bytes>", value.len())
54                };
55                f.debug_struct("Set")
56                    .field("key", key)
57                    .field("value", &format_args!("{body_repr}"))
58                    .finish()
59            }
60            KeyValueOperation::Delete { key } => {
61                f.debug_struct("Delete").field("key", key).finish()
62            }
63            KeyValueOperation::Exists { key } => {
64                f.debug_struct("Exists").field("key", key).finish()
65            }
66            KeyValueOperation::ListKeys { prefix, cursor } => f
67                .debug_struct("ListKeys")
68                .field("prefix", prefix)
69                .field("cursor", cursor)
70                .finish(),
71        }
72    }
73}
74
75/// The result of an operation on the store.
76///
77/// Note: we can't use [`core::result::Result`] here because it is not currently
78/// supported across the FFI boundary, when using `typegen` or `facet_typegen`.
79#[derive(Facet, Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
80#[repr(C)]
81pub enum KeyValueResult {
82    Ok { response: KeyValueResponse },
83    Err { error: KeyValueError },
84}
85
86#[derive(Facet, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87#[repr(C)]
88pub enum KeyValueResponse {
89    /// Response to a `KeyValueOperation::Get`,
90    /// returning the value stored under the key, which may be empty
91    Get { value: Value },
92    /// Response to a `KeyValueOperation::Set`,
93    /// returning the value that was previously stored under the key, may be empty
94    Set { previous: Value },
95    /// Response to a `KeyValueOperation::Delete`,
96    /// returning the value that was previously stored under the key, may be empty
97    Delete { previous: Value },
98    /// Response to a `KeyValueOperation::Exists`,
99    /// returning whether the key is present in the store
100    Exists { is_present: bool },
101    /// Response to a `KeyValueOperation::ListKeys`,
102    /// returning a list of keys that start with the prefix, and a cursor to continue listing
103    /// if there are more keys
104    ///
105    /// Note: the cursor is 0 if there are no more keys
106    ListKeys {
107        keys: Vec<String>,
108        /// The cursor to continue listing keys, or 0 if there are no more keys.
109        /// If the cursor is not found for the specified prefix, the response should instead
110        /// include a `KeyValueError::CursorNotFound` error.
111        next_cursor: u64,
112    },
113}
114
115impl Operation for KeyValueOperation {
116    type Output = KeyValueResult;
117
118    #[cfg(feature = "typegen")]
119    fn register_types(
120        generator: &mut crux_core::type_generation::serde::TypeGen,
121    ) -> crux_core::type_generation::serde::Result {
122        generator.register_type::<KeyValueResponse>()?;
123        generator.register_type::<KeyValueError>()?;
124        generator.register_type::<Value>()?;
125        generator.register_type::<Self>()?;
126        generator.register_type::<Self::Output>()?;
127        Ok(())
128    }
129}
130
131impl KeyValueResult {
132    /// Converts a [`KeyValueResult`] into a [`Result`]
133    /// # Errors
134    /// Passes any errors from the underlying [`KeyValueError`] to the returned `Result`.
135    /// # Panics
136    /// Panics if the [`KeyValueResult`] is not a [`KeyValueResponse::Get`].
137    pub fn unwrap_get(self) -> Result<Option<Vec<u8>>, KeyValueError> {
138        match self {
139            KeyValueResult::Ok { response } => match response {
140                KeyValueResponse::Get { value } => Ok(value.into()),
141                _ => {
142                    panic!("attempt to convert KeyValueResponse other than Get to Option<Vec<u8>>")
143                }
144            },
145            KeyValueResult::Err { error } => Err(error.clone()),
146        }
147    }
148
149    /// Converts a [`KeyValueResult`] into a [`Result`]
150    /// # Errors
151    /// Passes any errors from the underlying [`KeyValueError`] to the returned `Result`.
152    /// # Panics
153    /// Panics if the [`KeyValueResult`] is not a [`KeyValueResponse::Set`].
154    pub fn unwrap_set(self) -> Result<Option<Vec<u8>>, KeyValueError> {
155        match self {
156            KeyValueResult::Ok { response } => match response {
157                KeyValueResponse::Set { previous } => Ok(previous.into()),
158                _ => {
159                    panic!("attempt to convert KeyValueResponse other than Set to Option<Vec<u8>>")
160                }
161            },
162            KeyValueResult::Err { error } => Err(error.clone()),
163        }
164    }
165
166    /// Converts a [`KeyValueResult`] into a [`Result`]
167    /// # Errors
168    /// Passes any errors from the underlying [`KeyValueError`] to the returned `Result`.
169    /// # Panics
170    /// Panics if the [`KeyValueResult`] is not a [`KeyValueResponse::Delete`].
171    pub fn unwrap_delete(self) -> Result<Option<Vec<u8>>, KeyValueError> {
172        match self {
173            KeyValueResult::Ok { response } => match response {
174                KeyValueResponse::Delete { previous } => Ok(previous.into()),
175                _ => panic!(
176                    "attempt to convert KeyValueResponse other than Delete to Option<Vec<u8>>"
177                ),
178            },
179            KeyValueResult::Err { error } => Err(error.clone()),
180        }
181    }
182
183    /// Converts a [`KeyValueResult`] into a [`Result`]
184    /// # Errors
185    /// Passes any errors from the underlying [`KeyValueError`] to the returned `Result`.
186    /// # Panics
187    /// Panics if the [`KeyValueResult`] is not a [`KeyValueResponse::Exists`].
188    pub fn unwrap_exists(self) -> Result<bool, KeyValueError> {
189        match self {
190            KeyValueResult::Ok { response } => match response {
191                KeyValueResponse::Exists { is_present } => Ok(is_present),
192                _ => panic!("attempt to convert KeyValueResponse other than Exists to bool"),
193            },
194            KeyValueResult::Err { error } => Err(error.clone()),
195        }
196    }
197
198    /// Converts a [`KeyValueResult`] into a [`Result`]
199    /// # Errors
200    /// Passes any errors from the underlying [`KeyValueError`] to the returned `Result`.
201    /// # Panics
202    /// Panics if the [`KeyValueResult`] is not a [`KeyValueResponse::ListKeys`].
203    pub fn unwrap_list_keys(self) -> Result<(Vec<String>, u64), KeyValueError> {
204        match self {
205            KeyValueResult::Ok { response } => match response {
206                KeyValueResponse::ListKeys {
207                    keys,
208                    next_cursor: cursor,
209                } => Ok((keys, cursor)),
210                _ => panic!(
211                    "attempt to convert KeyValueResponse other than ListKeys to (Vec<String>, u64)"
212                ),
213            },
214            KeyValueResult::Err { error } => Err(error.clone()),
215        }
216    }
217}