1use std::collections::BTreeMap;
2
3use rust_decimal::Decimal;
4use surrealdb_protocol::fb::v1 as proto_fb;
5
6use super::{FromFlatbuffers, ToFlatbuffers};
7use crate::{Duration, GeometryKind, Kind, KindLiteral, Table};
8
9impl ToFlatbuffers for Kind {
10 type Output<'bldr> = flatbuffers::WIPOffset<proto_fb::Kind<'bldr>>;
11
12 #[inline]
13 fn to_fb<'bldr>(
14 &self,
15 builder: &mut flatbuffers::FlatBufferBuilder<'bldr>,
16 ) -> anyhow::Result<Self::Output<'bldr>> {
17 let args = match self {
18 Self::Any => proto_fb::KindArgs {
19 kind_type: proto_fb::KindType::Any,
20 kind: Some(
21 proto_fb::AnyKind::create(builder, &proto_fb::AnyKindArgs {}).as_union_value(),
22 ),
23 },
24 Self::None => proto_fb::KindArgs {
25 kind_type: proto_fb::KindType::NONE,
26 kind: None,
27 },
28 Self::Null => proto_fb::KindArgs {
29 kind_type: proto_fb::KindType::Null,
30 kind: Some(
31 proto_fb::NullKind::create(builder, &proto_fb::NullKindArgs {})
32 .as_union_value(),
33 ),
34 },
35 Self::Bool => proto_fb::KindArgs {
36 kind_type: proto_fb::KindType::Bool,
37 kind: Some(
38 proto_fb::BoolKind::create(builder, &proto_fb::BoolKindArgs {})
39 .as_union_value(),
40 ),
41 },
42 Self::Bytes => proto_fb::KindArgs {
43 kind_type: proto_fb::KindType::Bytes,
44 kind: Some(
45 proto_fb::BytesKind::create(builder, &proto_fb::BytesKindArgs {})
46 .as_union_value(),
47 ),
48 },
49 Self::Datetime => proto_fb::KindArgs {
50 kind_type: proto_fb::KindType::Datetime,
51 kind: Some(
52 proto_fb::DatetimeKind::create(builder, &proto_fb::DatetimeKindArgs {})
53 .as_union_value(),
54 ),
55 },
56 Self::Decimal => proto_fb::KindArgs {
57 kind_type: proto_fb::KindType::Decimal,
58 kind: Some(
59 proto_fb::DecimalKind::create(builder, &proto_fb::DecimalKindArgs {})
60 .as_union_value(),
61 ),
62 },
63 Self::Duration => proto_fb::KindArgs {
64 kind_type: proto_fb::KindType::Duration,
65 kind: Some(
66 proto_fb::DurationKind::create(builder, &proto_fb::DurationKindArgs {})
67 .as_union_value(),
68 ),
69 },
70 Self::Float => proto_fb::KindArgs {
71 kind_type: proto_fb::KindType::Float,
72 kind: Some(
73 proto_fb::FloatKind::create(builder, &proto_fb::FloatKindArgs {})
74 .as_union_value(),
75 ),
76 },
77 Self::Int => proto_fb::KindArgs {
78 kind_type: proto_fb::KindType::Int,
79 kind: Some(
80 proto_fb::IntKind::create(builder, &proto_fb::IntKindArgs {}).as_union_value(),
81 ),
82 },
83 Self::Number => proto_fb::KindArgs {
84 kind_type: proto_fb::KindType::Number,
85 kind: Some(
86 proto_fb::NumberKind::create(builder, &proto_fb::NumberKindArgs {})
87 .as_union_value(),
88 ),
89 },
90 Self::Object {
91 ..
92 } => proto_fb::KindArgs {
93 kind_type: proto_fb::KindType::Object,
94 kind: Some(
95 proto_fb::ObjectKind::create(builder, &proto_fb::ObjectKindArgs {})
96 .as_union_value(),
97 ),
98 },
99 Self::String => proto_fb::KindArgs {
100 kind_type: proto_fb::KindType::String,
101 kind: Some(
102 proto_fb::StringKind::create(builder, &proto_fb::StringKindArgs {})
103 .as_union_value(),
104 ),
105 },
106 Self::Uuid => proto_fb::KindArgs {
107 kind_type: proto_fb::KindType::Uuid,
108 kind: Some(
109 proto_fb::UuidKind::create(builder, &proto_fb::UuidKindArgs {})
110 .as_union_value(),
111 ),
112 },
113 Self::Regex => proto_fb::KindArgs {
114 kind_type: proto_fb::KindType::Regex,
115 kind: Some(
116 proto_fb::RegexKind::create(builder, &proto_fb::RegexKindArgs {})
117 .as_union_value(),
118 ),
119 },
120 Self::Table(tables) => {
121 let table_offsets: Vec<_> =
122 tables.iter().map(|t| builder.create_string(t.as_str())).collect::<Vec<_>>();
123 let tables = builder.create_vector(&table_offsets);
124
125 proto_fb::KindArgs {
126 kind_type: proto_fb::KindType::Table,
127 kind: Some(
128 proto_fb::TableKind::create(
129 builder,
130 &proto_fb::TableKindArgs {
131 tables: Some(tables),
132 },
133 )
134 .as_union_value(),
135 ),
136 }
137 }
138 Self::Record(tables) => {
139 let table_offsets: Vec<_> =
140 tables.iter().map(|t| builder.create_string(t.as_str())).collect::<Vec<_>>();
141 let tables = builder.create_vector(&table_offsets);
142 proto_fb::KindArgs {
143 kind_type: proto_fb::KindType::Record,
144 kind: Some(
145 proto_fb::RecordKind::create(
146 builder,
147 &proto_fb::RecordKindArgs {
148 tables: Some(tables),
149 },
150 )
151 .as_union_value(),
152 ),
153 }
154 }
155 Self::Geometry(types) => {
156 let type_offsets: Vec<_> =
157 types.iter().map(|t| t.to_fb(builder)).collect::<anyhow::Result<Vec<_>>>()?;
158 let types = builder.create_vector(&type_offsets);
159
160 proto_fb::KindArgs {
161 kind_type: proto_fb::KindType::Geometry,
162 kind: Some(
163 proto_fb::GeometryKind::create(
164 builder,
165 &proto_fb::GeometryKindArgs {
166 types: Some(types),
167 },
168 )
169 .as_union_value(),
170 ),
171 }
172 }
173 Self::Either(kinds) => {
174 let kind_offsets: Vec<_> =
175 kinds.iter().map(|k| k.to_fb(builder)).collect::<anyhow::Result<Vec<_>>>()?;
176 let kinds = builder.create_vector(&kind_offsets);
177
178 proto_fb::KindArgs {
179 kind_type: proto_fb::KindType::Either,
180 kind: Some(
181 proto_fb::EitherKind::create(
182 builder,
183 &proto_fb::EitherKindArgs {
184 kinds: Some(kinds),
185 },
186 )
187 .as_union_value(),
188 ),
189 }
190 }
191 Self::Set(inner, size) => {
192 let inner = inner.to_fb(builder)?;
193 let size = size.map(|len| len.to_fb(builder)).transpose()?;
194
195 proto_fb::KindArgs {
196 kind_type: proto_fb::KindType::Set,
197 kind: Some(
198 proto_fb::SetKind::create(
199 builder,
200 &proto_fb::SetKindArgs {
201 inner: Some(inner),
202 size,
203 },
204 )
205 .as_union_value(),
206 ),
207 }
208 }
209 Self::Array(inner, size) => {
210 let inner = inner.to_fb(builder)?;
211 let size = size.map(|len| len.to_fb(builder)).transpose()?;
212
213 proto_fb::KindArgs {
214 kind_type: proto_fb::KindType::Array,
215 kind: Some(
216 proto_fb::ArrayKind::create(
217 builder,
218 &proto_fb::ArrayKindArgs {
219 inner: Some(inner),
220 size,
221 },
222 )
223 .as_union_value(),
224 ),
225 }
226 }
227 Self::Function(args, return_type) => {
228 let args = args
229 .as_ref()
230 .map(|args| -> anyhow::Result<_> {
231 let arg_offsets: Vec<_> = args
232 .iter()
233 .map(|arg| arg.to_fb(builder))
234 .collect::<anyhow::Result<Vec<_>>>()?;
235 Ok(builder.create_vector(&arg_offsets))
236 })
237 .transpose()?;
238
239 let return_type = return_type
240 .as_ref()
241 .map(|return_type| return_type.to_fb(builder))
242 .transpose()?;
243
244 proto_fb::KindArgs {
245 kind_type: proto_fb::KindType::Function,
246 kind: Some(
247 proto_fb::FunctionKind::create(
248 builder,
249 &proto_fb::FunctionKindArgs {
250 args,
251 return_type,
252 },
253 )
254 .as_union_value(),
255 ),
256 }
257 }
258 Self::Range => proto_fb::KindArgs {
259 kind_type: proto_fb::KindType::Range,
260 kind: Some(
261 proto_fb::RangeKind::create(builder, &proto_fb::RangeKindArgs {})
262 .as_union_value(),
263 ),
264 },
265 Self::Literal(literal) => {
266 let literal = literal.to_fb(builder)?.as_union_value();
267 proto_fb::KindArgs {
268 kind_type: proto_fb::KindType::Literal,
269 kind: Some(literal),
270 }
271 }
272 Self::File(buckets) => {
273 let bucket_offsets: Vec<_> =
274 buckets.iter().map(|b| builder.create_string(b.as_str())).collect();
275 let buckets = builder.create_vector(&bucket_offsets);
276
277 proto_fb::KindArgs {
278 kind_type: proto_fb::KindType::File,
279 kind: Some(
280 proto_fb::FileKind::create(
281 builder,
282 &proto_fb::FileKindArgs {
283 buckets: Some(buckets),
284 },
285 )
286 .as_union_value(),
287 ),
288 }
289 }
290 };
291
292 Ok(proto_fb::Kind::create(builder, &args))
293 }
294}
295
296impl ToFlatbuffers for KindLiteral {
297 type Output<'bldr> = flatbuffers::WIPOffset<proto_fb::LiteralKind<'bldr>>;
298
299 fn to_fb<'bldr>(
300 &self,
301 builder: &mut flatbuffers::FlatBufferBuilder<'bldr>,
302 ) -> anyhow::Result<flatbuffers::WIPOffset<proto_fb::LiteralKind<'bldr>>> {
303 let args = match self {
304 Self::Bool(bool) => proto_fb::LiteralKindArgs {
305 literal_type: proto_fb::LiteralType::Bool,
306 literal: Some(
307 proto_fb::BoolValue::create(
308 builder,
309 &proto_fb::BoolValueArgs {
310 value: *bool,
311 },
312 )
313 .as_union_value(),
314 ),
315 },
316 Self::String(string) => {
317 let string_offset = builder.create_string(string);
318 proto_fb::LiteralKindArgs {
319 literal_type: proto_fb::LiteralType::String,
320 literal: Some(
321 proto_fb::StringValue::create(
322 builder,
323 &proto_fb::StringValueArgs {
324 value: Some(string_offset),
325 },
326 )
327 .as_union_value(),
328 ),
329 }
330 }
331 Self::Integer(i) => proto_fb::LiteralKindArgs {
332 literal_type: proto_fb::LiteralType::Int64,
333 literal: Some(
334 proto_fb::Int64Value::create(
335 builder,
336 &proto_fb::Int64ValueArgs {
337 value: *i,
338 },
339 )
340 .as_union_value(),
341 ),
342 },
343 Self::Float(f) => proto_fb::LiteralKindArgs {
344 literal_type: proto_fb::LiteralType::Float64,
345 literal: Some(
346 proto_fb::Float64Value::create(
347 builder,
348 &proto_fb::Float64ValueArgs {
349 value: *f,
350 },
351 )
352 .as_union_value(),
353 ),
354 },
355 Self::Decimal(d) => proto_fb::LiteralKindArgs {
356 literal_type: proto_fb::LiteralType::Decimal,
357 literal: Some(d.to_fb(builder)?.as_union_value()),
358 },
359 Self::Duration(duration) => proto_fb::LiteralKindArgs {
360 literal_type: proto_fb::LiteralType::Duration,
361 literal: Some(duration.to_fb(builder)?.as_union_value()),
362 },
363 Self::Array(array) => {
364 let array_items: Vec<_> = array
365 .iter()
366 .map(|item| item.to_fb(builder))
367 .collect::<anyhow::Result<Vec<_>>>()?;
368 let kinds_vector = builder.create_vector(&array_items);
369 let literal_array = proto_fb::LiteralArray::create(
370 builder,
371 &proto_fb::LiteralArrayArgs {
372 kinds: Some(kinds_vector),
373 },
374 );
375 proto_fb::LiteralKindArgs {
376 literal_type: proto_fb::LiteralType::Array,
377 literal: Some(literal_array.as_union_value()),
378 }
379 }
380 Self::Object(object) => proto_fb::LiteralKindArgs {
381 literal_type: proto_fb::LiteralType::Object,
382 literal: Some(object.to_fb(builder)?.as_union_value()),
383 },
384 };
385
386 Ok(proto_fb::LiteralKind::create(builder, &args))
387 }
388}
389
390impl FromFlatbuffers for Kind {
391 type Input<'a> = proto_fb::Kind<'a>;
392
393 #[inline]
394 fn from_fb(input: Self::Input<'_>) -> anyhow::Result<Self> {
395 use proto_fb::KindType;
396
397 let kind_type = input.kind_type();
398
399 match kind_type {
400 KindType::Any => Ok(Kind::Any),
401 KindType::NONE => Ok(Kind::None),
402 KindType::Null => Ok(Kind::Null),
403 KindType::Bool => Ok(Kind::Bool),
404 KindType::Int => Ok(Kind::Int),
405 KindType::Float => Ok(Kind::Float),
406 KindType::Decimal => Ok(Kind::Decimal),
407 KindType::Number => Ok(Kind::Number),
408 KindType::String => Ok(Kind::String),
409 KindType::Duration => Ok(Kind::Duration),
410 KindType::Datetime => Ok(Kind::Datetime),
411 KindType::Uuid => Ok(Kind::Uuid),
412 KindType::Bytes => Ok(Kind::Bytes),
413 KindType::Object => Ok(Kind::Object),
414 KindType::Table => {
415 let Some(table) = input.kind_as_table() else {
416 return Err(anyhow::anyhow!("Missing table kind"));
417 };
418 let tables = if let Some(tables) = table.tables() {
419 tables.iter().map(Table::from).collect::<Vec<_>>()
420 } else {
421 Vec::new()
422 };
423 Ok(Kind::Table(tables))
424 }
425 KindType::Record => {
426 let Some(record) = input.kind_as_record() else {
427 return Err(anyhow::anyhow!("Missing record kind"));
428 };
429 let tables = if let Some(tables) = record.tables() {
430 tables.iter().map(Table::from).collect::<Vec<_>>()
431 } else {
432 Vec::new()
433 };
434 Ok(Kind::Record(tables))
435 }
436 KindType::Geometry => {
437 let Some(geometry) = input.kind_as_geometry() else {
438 return Err(anyhow::anyhow!("Missing geometry kind"));
439 };
440 let types = if let Some(types) = geometry.types() {
441 types.iter().map(GeometryKind::from_fb).collect::<anyhow::Result<Vec<_>>>()?
442 } else {
443 Vec::new()
444 };
445 Ok(Kind::Geometry(types))
446 }
447 KindType::Set => {
448 let Some(set) = input.kind_as_set() else {
449 return Err(anyhow::anyhow!("Missing set kind"));
450 };
451 let Some(inner) = set.inner() else {
452 return Err(anyhow::anyhow!("Missing set item kind"));
453 };
454 let size = set.size().map(u64::from_fb).transpose()?;
455 Ok(Kind::Set(Box::new(Kind::from_fb(inner)?), size))
456 }
457 KindType::Array => {
458 let Some(array) = input.kind_as_array() else {
459 return Err(anyhow::anyhow!("Missing array kind"));
460 };
461 let Some(inner) = array.inner() else {
462 return Err(anyhow::anyhow!("Missing array item kind"));
463 };
464 let size = array.size().map(u64::from_fb).transpose()?;
465 Ok(Kind::Array(Box::new(Kind::from_fb(inner)?), size))
466 }
467 KindType::Either => {
468 let Some(either) = input.kind_as_either() else {
469 return Err(anyhow::anyhow!("Missing either kind"));
470 };
471 let kinds = if let Some(kinds) = either.kinds() {
472 kinds.iter().map(Kind::from_fb).collect::<anyhow::Result<Vec<_>>>()?
473 } else {
474 Vec::new()
475 };
476 Ok(Kind::either(kinds))
477 }
478 KindType::Function => {
479 let Some(function) = input.kind_as_function() else {
480 return Err(anyhow::anyhow!("Missing function kind"));
481 };
482 let args = if let Some(args) = function.args() {
483 Some(args.iter().map(Kind::from_fb).collect::<anyhow::Result<Vec<_>>>()?)
484 } else {
485 None
486 };
487 let return_type = if let Some(return_type) = function.return_type() {
488 Some(Box::new(Kind::from_fb(return_type)?))
489 } else {
490 None
491 };
492 Ok(Kind::Function(args, return_type))
493 }
494 KindType::File => {
495 let Some(file) = input.kind_as_file() else {
496 return Err(anyhow::anyhow!("Missing file kind"));
497 };
498 let buckets = if let Some(buckets) = file.buckets() {
499 buckets.iter().map(|x| x.to_string()).collect::<Vec<_>>()
500 } else {
501 Vec::new()
502 };
503 Ok(Kind::File(buckets))
504 }
505 KindType::Literal => {
506 let Some(literal) = input.kind_as_literal() else {
507 return Err(anyhow::anyhow!("Missing literal kind"));
508 };
509 Ok(Kind::Literal(KindLiteral::from_fb(literal)?))
510 }
511 KindType::Range => Ok(Kind::Range),
512 KindType::Option => {
513 let Some(option) = input.kind_as_option() else {
514 return Err(anyhow::anyhow!("Missing option kind"));
515 };
516 let Some(inner) = option.inner() else {
517 return Err(anyhow::anyhow!("Missing option item kind"));
518 };
519 Ok(Kind::option(Kind::from_fb(inner)?))
520 }
521 KindType::Regex => Ok(Kind::Regex),
522 _ => Err(anyhow::anyhow!("Unknown kind type")),
523 }
524 }
525}
526
527impl FromFlatbuffers for KindLiteral {
528 type Input<'a> = proto_fb::LiteralKind<'a>;
529
530 #[inline]
531 fn from_fb(input: Self::Input<'_>) -> anyhow::Result<Self> {
532 use proto_fb::LiteralType;
533
534 let literal_type = input.literal_type();
535
536 match literal_type {
537 LiteralType::Bool => {
538 let Some(bool_val) = input.literal_as_bool() else {
539 return Err(anyhow::anyhow!("Missing bool value"));
540 };
541 Ok(KindLiteral::Bool(bool_val.value()))
542 }
543 LiteralType::String => {
544 let Some(string_val) = input.literal_as_string() else {
545 return Err(anyhow::anyhow!("Missing string value"));
546 };
547 let Some(value) = string_val.value() else {
548 return Err(anyhow::anyhow!("Missing string content"));
549 };
550 Ok(KindLiteral::String(value.to_string()))
551 }
552 LiteralType::Int64 => {
553 let Some(int_val) = input.literal_as_int_64() else {
554 return Err(anyhow::anyhow!("Missing int64 value"));
555 };
556 Ok(KindLiteral::Integer(int_val.value()))
557 }
558 LiteralType::Float64 => {
559 let Some(float_val) = input.literal_as_float_64() else {
560 return Err(anyhow::anyhow!("Missing float64 value"));
561 };
562 Ok(KindLiteral::Float(float_val.value()))
563 }
564 LiteralType::Decimal => {
565 let Some(decimal) = input.literal_as_decimal() else {
566 return Err(anyhow::anyhow!("Missing decimal value"));
567 };
568 Ok(KindLiteral::Decimal(Decimal::from_fb(decimal)?))
569 }
570 LiteralType::Duration => {
571 let Some(duration_val) = input.literal_as_duration() else {
572 return Err(anyhow::anyhow!("Missing duration value"));
573 };
574 Ok(KindLiteral::Duration(Duration::from_fb(duration_val)?))
575 }
576 LiteralType::Array => {
577 let Some(array_val) = input.literal_as_array() else {
578 return Err(anyhow::anyhow!("Missing array value"));
579 };
580 let items = if let Some(items) = array_val.kinds() {
581 items.iter().map(Kind::from_fb).collect::<anyhow::Result<Vec<_>>>()?
582 } else {
583 Vec::new()
584 };
585 Ok(KindLiteral::Array(items))
586 }
587 LiteralType::Object => {
588 let Some(object_val) = input.literal_as_object() else {
589 return Err(anyhow::anyhow!("Missing object value"));
590 };
591 let map = BTreeMap::<String, Kind>::from_fb(object_val)?;
592 Ok(KindLiteral::Object(map))
593 }
594 _ => Err(anyhow::anyhow!("Unknown literal type")),
595 }
596 }
597}
598
599impl ToFlatbuffers for GeometryKind {
600 type Output<'bldr> = proto_fb::GeometryKindType;
601
602 fn to_fb<'bldr>(
603 &self,
604 _builder: &mut flatbuffers::FlatBufferBuilder<'bldr>,
605 ) -> anyhow::Result<Self::Output<'bldr>> {
606 Ok(match self {
607 GeometryKind::Point => proto_fb::GeometryKindType::Point,
608 GeometryKind::Line => proto_fb::GeometryKindType::Line,
609 GeometryKind::Polygon => proto_fb::GeometryKindType::Polygon,
610 GeometryKind::MultiPoint => proto_fb::GeometryKindType::MultiPoint,
611 GeometryKind::MultiLine => proto_fb::GeometryKindType::MultiLineString,
612 GeometryKind::MultiPolygon => proto_fb::GeometryKindType::MultiPolygon,
613 GeometryKind::Collection => proto_fb::GeometryKindType::Collection,
614 })
615 }
616}
617
618impl FromFlatbuffers for GeometryKind {
619 type Input<'a> = proto_fb::GeometryKindType;
620
621 #[inline]
622 fn from_fb(input: Self::Input<'_>) -> anyhow::Result<Self> {
623 match input {
624 proto_fb::GeometryKindType::Point => Ok(GeometryKind::Point),
625 proto_fb::GeometryKindType::Line => Ok(GeometryKind::Line),
626 proto_fb::GeometryKindType::Polygon => Ok(GeometryKind::Polygon),
627 proto_fb::GeometryKindType::MultiPoint => Ok(GeometryKind::MultiPoint),
628 proto_fb::GeometryKindType::MultiLineString => Ok(GeometryKind::MultiLine),
629 proto_fb::GeometryKindType::MultiPolygon => Ok(GeometryKind::MultiPolygon),
630 proto_fb::GeometryKindType::Collection => Ok(GeometryKind::Collection),
631 _ => Err(anyhow::anyhow!("Unknown geometry kind type: {:?}", input)),
632 }
633 }
634}
635
636#[cfg(test)]
637mod tests {
638 use std::collections::BTreeMap;
639
640 use rstest::rstest;
641 use rust_decimal::Decimal;
642 use surrealdb_protocol::fb::v1 as proto_fb;
643
644 use super::*;
645 use crate::{Duration, Kind, KindLiteral};
646
647 #[rstest]
648 #[case::any(Kind::Any)]
649 #[case::null(Kind::Null)]
650 #[case::bool(Kind::Bool)]
651 #[case::bytes(Kind::Bytes)]
652 #[case::datetime(Kind::Datetime)]
653 #[case::decimal(Kind::Decimal)]
654 #[case::duration(Kind::Duration)]
655 #[case::float(Kind::Float)]
656 #[case::int(Kind::Int)]
657 #[case::number(Kind::Number)]
658 #[case::object(Kind::Object)]
659 #[case::string(Kind::String)]
660 #[case::uuid(Kind::Uuid)]
661 #[case::regex(Kind::Regex)]
662 #[case::range(Kind::Range)]
663 #[case::table(Kind::Table(vec!["test_table".into()]))]
664 #[case::table_empty(Kind::Table(vec![]))]
665 #[case::table_multiple(Kind::Table(vec!["users".into(), "posts".into()]))]
666 #[case::record(Kind::Record(vec!["test_table".into()]))]
667 #[case::geometry(Kind::Geometry(vec![GeometryKind::Point, GeometryKind::Polygon]))]
668 #[case::either(Kind::Either(vec![Kind::String, Kind::Number]))]
669 #[case::set(Kind::Set(Box::new(Kind::String), Some(10)))]
670 #[case::array(Kind::Array(Box::new(Kind::String), Some(5)))]
671 #[case::function(Kind::Function(Some(vec![Kind::String, Kind::Number]), Some(Box::new(Kind::Bool))))]
672 #[case::file(Kind::File(vec!["bucket1".to_string(), "bucket2".to_string()]))]
673 #[case::literal_bool(Kind::Literal(KindLiteral::Bool(true)))]
675 #[case::literal_bool_false(Kind::Literal(KindLiteral::Bool(false)))]
676 #[case::literal_string(Kind::Literal(KindLiteral::String("test_string".to_string())))]
677 #[case::literal_integer(Kind::Literal(KindLiteral::Integer(42)))]
678 #[case::literal_integer_min(Kind::Literal(KindLiteral::Integer(i64::MIN)))]
679 #[case::literal_integer_max(Kind::Literal(KindLiteral::Integer(i64::MAX)))]
680 #[case::literal_float(Kind::Literal(KindLiteral::Float(std::f64::consts::PI)))]
681 #[case::literal_float_nan(Kind::Literal(KindLiteral::Float(f64::NAN)))]
682 #[case::literal_float_infinity(Kind::Literal(KindLiteral::Float(f64::INFINITY)))]
683 #[case::literal_float_neg_infinity(Kind::Literal(KindLiteral::Float(f64::NEG_INFINITY)))]
684 #[case::literal_decimal(Kind::Literal(KindLiteral::Decimal(Decimal::new(123, 2))))]
685 #[case::literal_duration(Kind::Literal(KindLiteral::Duration(Duration::default())))]
686 #[case::literal_array(Kind::Literal(KindLiteral::Array(vec![Kind::String, Kind::Number])))]
687 #[case::literal_array_empty(Kind::Literal(KindLiteral::Array(vec![])))]
688 #[case::literal_object(Kind::Literal(KindLiteral::Object(BTreeMap::from([
689 ("key1".to_string(), Kind::String),
690 ("key2".to_string(), Kind::Number)
691 ]))))]
692 #[case::literal_object_empty(Kind::Literal(KindLiteral::Object(BTreeMap::new())))]
693 fn test_flatbuffers_roundtrip_kind(#[case] input: Kind) {
694 let mut builder = flatbuffers::FlatBufferBuilder::new();
695 let input_fb = input.to_fb(&mut builder).expect("Failed to convert to FlatBuffer");
696 builder.finish_minimal(input_fb);
697 let buf = builder.finished_data();
698 let kind_fb = flatbuffers::root::<proto_fb::Kind>(buf).expect("Failed to read FlatBuffer");
699 let kind = Kind::from_fb(kind_fb).expect("Failed to convert from FlatBuffer");
700 assert_eq!(input, kind, "Roundtrip conversion failed for input: {:?}", input);
701 }
702}