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