Skip to main content

surrealdb_types/flatbuffers/
kind.rs

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	// KindLiteral variants
674	#[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}