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}