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}