surrealdb_types/flatbuffers/
surrealism.rs1use std::ops::Bound;
2
3use anyhow::Context;
4use surrealdb_protocol::fb::v1 as proto_fb;
5
6use super::{FromFlatbuffers, ToFlatbuffers};
7use crate::{Kind, Value};
8
9pub fn encode_argument_list(args: &[(&str, Kind)]) -> anyhow::Result<Vec<u8>> {
11 let mut fbb = flatbuffers::FlatBufferBuilder::new();
12 let offsets: Vec<_> = args
13 .iter()
14 .map(|(name, kind)| -> anyhow::Result<_> {
15 let key_offset = fbb.create_string(name);
16 let kind_offset = kind.to_fb(&mut fbb)?;
17 Ok(proto_fb::Argument::create(
18 &mut fbb,
19 &proto_fb::ArgumentArgs {
20 key: Some(key_offset),
21 value: Some(kind_offset),
22 },
23 ))
24 })
25 .collect::<anyhow::Result<Vec<_>>>()?;
26 let vec = fbb.create_vector(&offsets);
27 let root = proto_fb::ArgumentList::create(
28 &mut fbb,
29 &proto_fb::ArgumentListArgs {
30 arguments: Some(vec),
31 },
32 );
33 fbb.finish(root, None);
34 Ok(fbb.finished_data().to_vec())
35}
36
37pub fn decode_argument_list(bytes: &[u8]) -> anyhow::Result<Vec<(String, Kind)>> {
39 let root = flatbuffers::root::<proto_fb::ArgumentList>(bytes)
40 .context("Failed to decode ArgumentList")?;
41 let arguments = root.arguments().context("Missing arguments in ArgumentList")?;
42 arguments
43 .iter()
44 .map(|arg| {
45 let key = arg.key().context("Missing key in Argument")?.to_string();
46 let kind_fb = arg.value().context("Missing value in Argument")?;
47 let kind = Kind::from_fb(kind_fb)?;
48 Ok((key, kind))
49 })
50 .collect()
51}
52
53pub fn encode_value_list(values: &[Value]) -> anyhow::Result<Vec<u8>> {
55 let mut fbb = flatbuffers::FlatBufferBuilder::new();
56 let offsets: Vec<_> =
57 values.iter().map(|v| v.to_fb(&mut fbb)).collect::<anyhow::Result<Vec<_>>>()?;
58 let vec = fbb.create_vector(&offsets);
59 let root = proto_fb::ValueList::create(
60 &mut fbb,
61 &proto_fb::ValueListArgs {
62 values: Some(vec),
63 },
64 );
65 fbb.finish(root, None);
66 Ok(fbb.finished_data().to_vec())
67}
68
69pub fn decode_value_list(bytes: &[u8]) -> anyhow::Result<Vec<Value>> {
71 let root =
72 flatbuffers::root::<proto_fb::ValueList>(bytes).context("Failed to decode ValueList")?;
73 let values = root.values().context("Missing values in ValueList")?;
74 values.iter().map(Value::from_fb).collect()
75}
76
77pub fn encode_kind_list(kinds: &[Kind]) -> anyhow::Result<Vec<u8>> {
79 let mut fbb = flatbuffers::FlatBufferBuilder::new();
80 let offsets: Vec<_> =
81 kinds.iter().map(|k| k.to_fb(&mut fbb)).collect::<anyhow::Result<Vec<_>>>()?;
82 let vec = fbb.create_vector(&offsets);
83 let root = proto_fb::KindList::create(
84 &mut fbb,
85 &proto_fb::KindListArgs {
86 kinds: Some(vec),
87 },
88 );
89 fbb.finish(root, None);
90 Ok(fbb.finished_data().to_vec())
91}
92
93pub fn decode_kind_list(bytes: &[u8]) -> anyhow::Result<Vec<Kind>> {
95 let root =
96 flatbuffers::root::<proto_fb::KindList>(bytes).context("Failed to decode KindList")?;
97 let kinds = root.kinds().context("Missing kinds in KindList")?;
98 kinds.iter().map(Kind::from_fb).collect()
99}
100
101pub fn encode_string_key_values(entries: &[(String, Value)]) -> anyhow::Result<Vec<u8>> {
103 let mut fbb = flatbuffers::FlatBufferBuilder::new();
104 let offsets: Vec<_> = entries
105 .iter()
106 .map(|(key, value)| -> anyhow::Result<_> {
107 let key_offset = fbb.create_string(key);
108 let value_offset = value.to_fb(&mut fbb)?;
109 Ok(proto_fb::StringKeyValue::create(
110 &mut fbb,
111 &proto_fb::StringKeyValueArgs {
112 key: Some(key_offset),
113 value: Some(value_offset),
114 },
115 ))
116 })
117 .collect::<anyhow::Result<Vec<_>>>()?;
118 let vec = fbb.create_vector(&offsets);
119 let root = proto_fb::StringKeyValueList::create(
120 &mut fbb,
121 &proto_fb::StringKeyValueListArgs {
122 entries: Some(vec),
123 },
124 );
125 fbb.finish(root, None);
126 Ok(fbb.finished_data().to_vec())
127}
128
129pub fn decode_string_key_values(bytes: &[u8]) -> anyhow::Result<Vec<(String, Value)>> {
131 let root = flatbuffers::root::<proto_fb::StringKeyValueList>(bytes)
132 .context("Failed to decode StringKeyValueList")?;
133 let entries = root.entries().context("Missing entries in StringKeyValueList")?;
134 entries
135 .iter()
136 .map(|entry| {
137 let key = entry.key().context("Missing key in StringKeyValue")?.to_string();
138 let value_fb = entry.value().context("Missing value in StringKeyValue")?;
139 let value = Value::from_fb(value_fb)?;
140 Ok((key, value))
141 })
142 .collect()
143}
144
145pub fn encode_optional_values(values: &[Option<Value>]) -> anyhow::Result<Vec<u8>> {
147 let mut fbb = flatbuffers::FlatBufferBuilder::new();
148 let offsets: Vec<_> = values
149 .iter()
150 .map(|opt| -> anyhow::Result<_> {
151 match opt {
152 Some(value) => {
153 let value_offset = value.to_fb(&mut fbb)?;
154 Ok(proto_fb::OptionalValue::create(
155 &mut fbb,
156 &proto_fb::OptionalValueArgs {
157 present: true,
158 value: Some(value_offset),
159 },
160 ))
161 }
162 None => Ok(proto_fb::OptionalValue::create(
163 &mut fbb,
164 &proto_fb::OptionalValueArgs {
165 present: false,
166 value: None,
167 },
168 )),
169 }
170 })
171 .collect::<anyhow::Result<Vec<_>>>()?;
172 let vec = fbb.create_vector(&offsets);
173 let root = proto_fb::OptionalValueList::create(
174 &mut fbb,
175 &proto_fb::OptionalValueListArgs {
176 values: Some(vec),
177 },
178 );
179 fbb.finish(root, None);
180 Ok(fbb.finished_data().to_vec())
181}
182
183pub fn decode_optional_values(bytes: &[u8]) -> anyhow::Result<Vec<Option<Value>>> {
185 let root = flatbuffers::root::<proto_fb::OptionalValueList>(bytes)
186 .context("Failed to decode OptionalValueList")?;
187 let values = root.values().context("Missing values in OptionalValueList")?;
188 values
189 .iter()
190 .map(|opt| {
191 if opt.present() {
192 let value_fb =
193 opt.value().context("OptionalValue marked present but missing value")?;
194 Ok(Some(Value::from_fb(value_fb)?))
195 } else {
196 Ok(None)
197 }
198 })
199 .collect()
200}
201
202fn bound_to_tag(bound: &Bound<String>) -> (proto_fb::StringBoundTag, Option<&str>) {
203 match bound {
204 Bound::Unbounded => (proto_fb::StringBoundTag::Unbounded, None),
205 Bound::Included(s) => (proto_fb::StringBoundTag::Included, Some(s.as_str())),
206 Bound::Excluded(s) => (proto_fb::StringBoundTag::Excluded, Some(s.as_str())),
207 }
208}
209
210fn tag_to_bound(
211 tag: proto_fb::StringBoundTag,
212 value: Option<&str>,
213) -> anyhow::Result<Bound<String>> {
214 match tag {
215 proto_fb::StringBoundTag::Unbounded => Ok(Bound::Unbounded),
216 proto_fb::StringBoundTag::Included => {
217 let s = value.context("Included bound missing value")?;
218 Ok(Bound::Included(s.to_string()))
219 }
220 proto_fb::StringBoundTag::Excluded => {
221 let s = value.context("Excluded bound missing value")?;
222 Ok(Bound::Excluded(s.to_string()))
223 }
224 _ => anyhow::bail!("Unknown StringBoundTag: {:?}", tag),
225 }
226}
227
228pub fn encode_string_range(start: &Bound<String>, end: &Bound<String>) -> anyhow::Result<Vec<u8>> {
230 let mut fbb = flatbuffers::FlatBufferBuilder::new();
231 let (start_tag, start_val) = bound_to_tag(start);
232 let (end_tag, end_val) = bound_to_tag(end);
233 let start_offset = start_val.map(|s| fbb.create_string(s));
234 let end_offset = end_val.map(|s| fbb.create_string(s));
235 let root = proto_fb::StringRange::create(
236 &mut fbb,
237 &proto_fb::StringRangeArgs {
238 start_tag,
239 start_value: start_offset,
240 end_tag,
241 end_value: end_offset,
242 },
243 );
244 fbb.finish(root, None);
245 Ok(fbb.finished_data().to_vec())
246}
247
248pub fn decode_string_range(bytes: &[u8]) -> anyhow::Result<(Bound<String>, Bound<String>)> {
250 let root = flatbuffers::root::<proto_fb::StringRange>(bytes)
251 .context("Failed to decode StringRange")?;
252 let start = tag_to_bound(root.start_tag(), root.start_value())?;
253 let end = tag_to_bound(root.end_tag(), root.end_value())?;
254 Ok((start, end))
255}
256
257#[cfg(test)]
258mod tests {
259 use std::ops::Bound;
260
261 use rstest::rstest;
262
263 use super::*;
264 use crate::{Kind, Number, Value};
265
266 #[test]
267 fn test_value_list_roundtrip() {
268 let values =
269 vec![Value::String("hello".into()), Value::Number(Number::Int(42)), Value::Bool(true)];
270 let bytes = encode_value_list(&values).unwrap();
271 let decoded = decode_value_list(&bytes).unwrap();
272 assert_eq!(values, decoded);
273 }
274
275 #[test]
276 fn test_value_list_empty() {
277 let values: Vec<Value> = vec![];
278 let bytes = encode_value_list(&values).unwrap();
279 let decoded = decode_value_list(&bytes).unwrap();
280 assert_eq!(values, decoded);
281 }
282
283 #[test]
284 fn test_kind_list_roundtrip() {
285 let kinds = vec![Kind::String, Kind::Int, Kind::Bool];
286 let bytes = encode_kind_list(&kinds).unwrap();
287 let decoded = decode_kind_list(&bytes).unwrap();
288 assert_eq!(kinds, decoded);
289 }
290
291 #[test]
292 fn test_kind_list_empty() {
293 let kinds: Vec<Kind> = vec![];
294 let bytes = encode_kind_list(&kinds).unwrap();
295 let decoded = decode_kind_list(&bytes).unwrap();
296 assert_eq!(kinds, decoded);
297 }
298
299 #[test]
300 fn test_argument_list_roundtrip() {
301 let args: Vec<(&str, Kind)> =
302 vec![("name", Kind::String), ("age", Kind::Int), ("active", Kind::Bool)];
303 let bytes = encode_argument_list(&args).unwrap();
304 let decoded = decode_argument_list(&bytes).unwrap();
305 let expected: Vec<(String, Kind)> =
306 args.into_iter().map(|(n, k)| (n.to_string(), k)).collect();
307 assert_eq!(expected, decoded);
308 }
309
310 #[test]
311 fn test_argument_list_empty() {
312 let args: Vec<(&str, Kind)> = vec![];
313 let bytes = encode_argument_list(&args).unwrap();
314 let decoded = decode_argument_list(&bytes).unwrap();
315 assert!(decoded.is_empty());
316 }
317
318 #[test]
319 fn test_string_key_values_roundtrip() {
320 let entries = vec![
321 ("key1".to_string(), Value::String("val1".into())),
322 ("key2".to_string(), Value::Number(Number::Int(99))),
323 ];
324 let bytes = encode_string_key_values(&entries).unwrap();
325 let decoded = decode_string_key_values(&bytes).unwrap();
326 assert_eq!(entries, decoded);
327 }
328
329 #[test]
330 fn test_string_key_values_empty() {
331 let entries: Vec<(String, Value)> = vec![];
332 let bytes = encode_string_key_values(&entries).unwrap();
333 let decoded = decode_string_key_values(&bytes).unwrap();
334 assert_eq!(entries, decoded);
335 }
336
337 #[test]
338 fn test_optional_values_roundtrip() {
339 let values = vec![
340 Some(Value::String("present".into())),
341 None,
342 Some(Value::Number(Number::Int(7))),
343 None,
344 ];
345 let bytes = encode_optional_values(&values).unwrap();
346 let decoded = decode_optional_values(&bytes).unwrap();
347 assert_eq!(values, decoded);
348 }
349
350 #[test]
351 fn test_optional_values_all_none() {
352 let values: Vec<Option<Value>> = vec![None, None, None];
353 let bytes = encode_optional_values(&values).unwrap();
354 let decoded = decode_optional_values(&bytes).unwrap();
355 assert_eq!(values, decoded);
356 }
357
358 #[rstest]
359 #[case::unbounded_unbounded(Bound::Unbounded, Bound::Unbounded)]
360 #[case::included_excluded(
361 Bound::Included("a".to_string()),
362 Bound::Excluded("z".to_string())
363 )]
364 #[case::included_unbounded(
365 Bound::Included("start".to_string()),
366 Bound::Unbounded
367 )]
368 #[case::unbounded_excluded(
369 Bound::Unbounded,
370 Bound::Excluded("end".to_string())
371 )]
372 #[case::included_included(
373 Bound::Included("a".to_string()),
374 Bound::Included("z".to_string())
375 )]
376 fn test_string_range_roundtrip(#[case] start: Bound<String>, #[case] end: Bound<String>) {
377 let bytes = encode_string_range(&start, &end).unwrap();
378 let (decoded_start, decoded_end) = decode_string_range(&bytes).unwrap();
379 assert_eq!(start, decoded_start);
380 assert_eq!(end, decoded_end);
381 }
382}