Skip to main content

arora_types/
value.rs

1/// This module provides the [`Value`] enum and related types for representing structured values,
2/// including conversions from primitive types, arrays, and collections.
3///
4/// Note: HashSet<f32> and HashSet<f64> are not implemented because floating point types don't implement Hash due to NaN issues.
5use derive_more::Display;
6use serde::{Deserialize, Serialize};
7use uuid::Uuid;
8
9use crate::keyvalue::KeyValue;
10
11#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
12pub enum Type {
13  #[serde(rename = "unit")]
14  Unit,
15  #[serde(rename = "bool")]
16  Boolean,
17  #[serde(rename = "u8")]
18  U8,
19  #[serde(rename = "u16")]
20  U16,
21  #[serde(rename = "u32")]
22  U32,
23  #[serde(rename = "u64")]
24  U64,
25  #[serde(rename = "i8")]
26  I8,
27  #[serde(rename = "i16")]
28  I16,
29  #[serde(rename = "i32")]
30  I32,
31  #[serde(rename = "i64")]
32  I64,
33  #[serde(rename = "f32")]
34  F32,
35  #[serde(rename = "f64")]
36  F64,
37  #[serde(rename = "str")]
38  String,
39  #[serde(rename = "option")]
40  Option,
41  #[serde(rename = "struct")]
42  Structure,
43  #[serde(rename = "enum")]
44  Enumeration,
45  #[serde(rename = "bools")]
46  ArrayBoolean,
47  #[serde(rename = "u8s")]
48  ArrayU8,
49  #[serde(rename = "u16s")]
50  ArrayU16,
51  #[serde(rename = "u32s")]
52  ArrayU32,
53  #[serde(rename = "u64s")]
54  ArrayU64,
55  #[serde(rename = "i8s")]
56  ArrayI8,
57  #[serde(rename = "i16s")]
58  ArrayI16,
59  #[serde(rename = "i32s")]
60  ArrayI32,
61  #[serde(rename = "i64s")]
62  ArrayI64,
63  #[serde(rename = "f32s")]
64  ArrayF32,
65  #[serde(rename = "f64s")]
66  ArrayF64,
67  #[serde(rename = "strs")]
68  ArrayString,
69  #[serde(rename = "values")]
70  ArrayValue,
71  #[serde(rename = "structs")]
72  ArrayStructure,
73  #[serde(rename = "enums")]
74  ArrayEnumeration,
75  #[serde(rename = "keyvalues")]
76  KeyValue,
77  #[serde(rename = "uuids")]
78  Uuid,
79}
80
81// Value representation for received parameters.
82//=====================================================================
83#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
84pub enum Value {
85  #[serde(rename = "unit")]
86  #[display("()")]
87  Unit,
88  #[serde(rename = "bool")]
89  Boolean(bool),
90  #[serde(rename = "u8")]
91  #[display("{}u8", _0)]
92  U8(u8),
93  #[serde(rename = "u16")]
94  #[display("{}u16", _0)]
95  U16(u16),
96  #[serde(rename = "u32")]
97  #[display("{}u32", _0)]
98  U32(u32),
99  #[serde(rename = "u64")]
100  #[display("{}u64", _0)]
101  U64(u64),
102  #[serde(rename = "i8")]
103  #[display("{}i8", _0)]
104  I8(i8),
105  #[serde(rename = "i16")]
106  #[display("{}i16", _0)]
107  I16(i16),
108  #[serde(rename = "i32")]
109  #[display("{}i32", _0)]
110  I32(i32),
111  #[serde(rename = "i64")]
112  #[display("{}i64", _0)]
113  I64(i64),
114  #[serde(rename = "f32")]
115  #[display("{}f32", _0)]
116  F32(f32),
117  #[serde(rename = "f64")]
118  #[display("{}f64", _0)]
119  F64(f64),
120  #[serde(rename = "str")]
121  #[display("\"{}\"", _0)]
122  String(String),
123  #[serde(rename = "option")]
124  #[display("[{}]", if let Some(v) = _0.as_ref() { format!("{}", v) } else { "null".to_string() })]
125  Option(Option<Box<Value>>),
126  #[serde(rename = "struct")]
127  Structure(Structure),
128  #[serde(rename = "enum")]
129  Enumeration(Enumeration),
130  #[serde(rename = "bools")]
131  #[display("[{:?}]", _0)]
132  ArrayBoolean(Vec<bool>),
133  #[serde(rename = "u8s")]
134  #[display("u8[{:?}]", _0)]
135  ArrayU8(Vec<u8>),
136  #[serde(rename = "u16s")]
137  #[display("u16[{:?}]", _0)]
138  ArrayU16(Vec<u16>),
139  #[serde(rename = "u32s")]
140  #[display("u32[{:?}]", _0)]
141  ArrayU32(Vec<u32>),
142  #[serde(rename = "u64s")]
143  #[display("u64[{:?}]", _0)]
144  ArrayU64(Vec<u64>),
145  #[serde(rename = "i8s")]
146  #[display("i8[{:?}]", _0)]
147  ArrayI8(Vec<i8>),
148  #[serde(rename = "i16s")]
149  #[display("i16[{:?}]", _0)]
150  ArrayI16(Vec<i16>),
151  #[serde(rename = "i32s")]
152  #[display("i32[{:?}]", _0)]
153  ArrayI32(Vec<i32>),
154  #[serde(rename = "i64s")]
155  #[display("i64[{:?}]", _0)]
156  ArrayI64(Vec<i64>),
157  #[serde(rename = "f32s")]
158  #[display("f32[{:?}]", _0)]
159  ArrayF32(Vec<f32>),
160  #[serde(rename = "f64s")]
161  #[display("f64[{:?}]", _0)]
162  ArrayF64(Vec<f64>),
163  #[serde(rename = "strs")]
164  #[display("[{:?}]", _0)]
165  ArrayString(Vec<String>),
166  #[serde(rename = "values")]
167  #[display("[{:?}]", _0)]
168  ArrayValue(Vec<Value>),
169  #[serde(rename = "structs")]
170  #[display("structs({}, {:?})", id, elements)]
171  ArrayStructure {
172    id: Uuid,
173    elements: Vec<StructureWithoutId>,
174  },
175  #[serde(rename = "enums")]
176  #[display("enums({}, {:?})", id, elements)]
177  ArrayEnumeration {
178    id: Uuid,
179    elements: Vec<EnumerationWithoutId>,
180  },
181  #[serde(rename = "keyvalue")]
182  KeyValue(KeyValue),
183  #[serde(rename = "uuid")]
184  #[display("uuid({})", _0)]
185  Uuid(Uuid),
186}
187
188impl Value {
189  /// The value's [`Type`]: which variant it is, which is what a consumer needs
190  /// to render it or to check that another value fits the same slot. A compound
191  /// value's own record is [`type_uuid`](Self::type_uuid); this is its shape.
192  pub fn kind(&self) -> Type {
193    match self {
194      Value::Unit => Type::Unit,
195      Value::Boolean(_) => Type::Boolean,
196      Value::U8(_) => Type::U8,
197      Value::U16(_) => Type::U16,
198      Value::U32(_) => Type::U32,
199      Value::U64(_) => Type::U64,
200      Value::I8(_) => Type::I8,
201      Value::I16(_) => Type::I16,
202      Value::I32(_) => Type::I32,
203      Value::I64(_) => Type::I64,
204      Value::F32(_) => Type::F32,
205      Value::F64(_) => Type::F64,
206      Value::String(_) => Type::String,
207      Value::Option(_) => Type::Option,
208      Value::Structure(_) => Type::Structure,
209      Value::Enumeration(_) => Type::Enumeration,
210      Value::ArrayBoolean(_) => Type::ArrayBoolean,
211      Value::ArrayU8(_) => Type::ArrayU8,
212      Value::ArrayU16(_) => Type::ArrayU16,
213      Value::ArrayU32(_) => Type::ArrayU32,
214      Value::ArrayU64(_) => Type::ArrayU64,
215      Value::ArrayI8(_) => Type::ArrayI8,
216      Value::ArrayI16(_) => Type::ArrayI16,
217      Value::ArrayI32(_) => Type::ArrayI32,
218      Value::ArrayI64(_) => Type::ArrayI64,
219      Value::ArrayF32(_) => Type::ArrayF32,
220      Value::ArrayF64(_) => Type::ArrayF64,
221      Value::ArrayString(_) => Type::ArrayString,
222      Value::ArrayValue(_) => Type::ArrayValue,
223      Value::ArrayStructure { .. } => Type::ArrayStructure,
224      Value::ArrayEnumeration { .. } => Type::ArrayEnumeration,
225      Value::KeyValue(_) => Type::KeyValue,
226      Value::Uuid(_) => Type::Uuid,
227    }
228  }
229
230  /// Returns the type UUID for this value.
231  ///
232  /// Primitives map to well-known UUIDs from `ty::mod`. Structures and enumerations
233  /// carry their own type ID. Arrays of structures/enumerations use the element type ID.
234  /// Other compound types (plain arrays, Option, KeyValue, Uuid) have their own well-known UUIDs.
235  pub fn type_uuid(&self) -> Uuid {
236    use crate::ty;
237    match self {
238      Value::Unit => *ty::UNIT_ID,
239      Value::Boolean(_) => *ty::BOOLEAN_ID,
240      Value::I8(_) => *ty::I8_ID,
241      Value::I16(_) => *ty::I16_ID,
242      Value::I32(_) => *ty::I32_ID,
243      Value::I64(_) => *ty::I64_ID,
244      Value::U8(_) => *ty::U8_ID,
245      Value::U16(_) => *ty::U16_ID,
246      Value::U32(_) => *ty::U32_ID,
247      Value::U64(_) => *ty::U64_ID,
248      Value::F32(_) => *ty::F32_ID,
249      Value::F64(_) => *ty::F64_ID,
250      Value::String(_) => *ty::STRING_ID,
251      Value::Option(_) => *ty::OPTION_ID,
252      Value::Structure(s) => s.id,
253      Value::Enumeration(e) => e.id,
254      Value::ArrayBoolean(_) => *ty::ARRAY_BOOLEAN_ID,
255      Value::ArrayU8(_) => *ty::ARRAY_U8_ID,
256      Value::ArrayU16(_) => *ty::ARRAY_U16_ID,
257      Value::ArrayU32(_) => *ty::ARRAY_U32_ID,
258      Value::ArrayU64(_) => *ty::ARRAY_U64_ID,
259      Value::ArrayI8(_) => *ty::ARRAY_I8_ID,
260      Value::ArrayI16(_) => *ty::ARRAY_I16_ID,
261      Value::ArrayI32(_) => *ty::ARRAY_I32_ID,
262      Value::ArrayI64(_) => *ty::ARRAY_I64_ID,
263      Value::ArrayF32(_) => *ty::ARRAY_F32_ID,
264      Value::ArrayF64(_) => *ty::ARRAY_F64_ID,
265      Value::ArrayString(_) => *ty::ARRAY_STRING_ID,
266      Value::ArrayValue(_) => *ty::ARRAY_VALUE_ID,
267      Value::ArrayStructure { id, .. } => *id,
268      Value::ArrayEnumeration { id, .. } => *id,
269      Value::KeyValue(_) => *ty::KEY_VALUE_ID,
270      Value::Uuid(_) => *ty::UUID_ID,
271    }
272  }
273}
274
275#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
276#[display("{}::{}({})", id, variant_id, value)]
277pub struct Enumeration {
278  pub id: Uuid,
279  pub variant_id: Uuid,
280  pub value: Box<Value>,
281}
282
283#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
284#[display("{}({:?})", id, fields)]
285pub struct Structure {
286  pub id: Uuid,
287  pub fields: Vec<StructureField>,
288}
289
290#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
291#[display("{}: {}", id, value)]
292pub struct StructureField {
293  pub id: Uuid,
294  pub value: Box<Value>,
295}
296
297#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
298#[display("({:?})", fields)]
299pub struct StructureWithoutId {
300  // #[serde(flatten)]
301  pub fields: Vec<StructureField>,
302}
303
304#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
305#[display("{}({})", variant_id, value)]
306pub struct EnumerationWithoutId {
307  pub variant_id: Uuid,
308  pub value: Box<Value>,
309}
310
311/// A common error type for conversion erros from and to [`Value`].
312#[derive(Display, Debug)]
313pub struct ConversionError {
314  pub message: String,
315}
316
317impl std::error::Error for ConversionError {}
318
319impl Value {
320  /// Pack `elements` — values of one type, `element_id` — into the array form
321  /// the value plane uses for that type: the typed array of a primitive
322  /// (`ArrayU8`, `ArrayString`, …), `ArrayStructure` for structures,
323  /// `ArrayEnumeration` for enumerations, `ArrayValue` otherwise. An empty
324  /// array of a user type is packed by [`array_of_type`](Self::array_of_type),
325  /// which can tell a structure from an enumeration; here it is a structure.
326  pub fn array_of(element_id: Uuid, elements: Vec<Value>) -> Value {
327    macro_rules! typed {
328      ($variant:ident, $array:ident) => {
329        if elements.iter().all(|v| matches!(v, Value::$variant(_))) {
330          return Value::$array(
331            elements
332              .into_iter()
333              .map(|v| match v {
334                Value::$variant(x) => x,
335                _ => unreachable!(),
336              })
337              .collect(),
338          );
339        }
340      };
341    }
342    if elements.is_empty() {
343      return Self::empty_array(element_id, false);
344    }
345    typed!(Boolean, ArrayBoolean);
346    typed!(U8, ArrayU8);
347    typed!(U16, ArrayU16);
348    typed!(U32, ArrayU32);
349    typed!(U64, ArrayU64);
350    typed!(I8, ArrayI8);
351    typed!(I16, ArrayI16);
352    typed!(I32, ArrayI32);
353    typed!(I64, ArrayI64);
354    typed!(F32, ArrayF32);
355    typed!(F64, ArrayF64);
356    typed!(String, ArrayString);
357    if elements.iter().all(|v| matches!(v, Value::Structure(_))) {
358      return Value::ArrayStructure {
359        id: element_id,
360        elements: elements
361          .into_iter()
362          .map(|v| match v {
363            Value::Structure(s) => StructureWithoutId { fields: s.fields },
364            _ => unreachable!(),
365          })
366          .collect(),
367      };
368    }
369    if elements.iter().all(|v| matches!(v, Value::Enumeration(_))) {
370      return Value::ArrayEnumeration {
371        id: element_id,
372        elements: elements
373          .into_iter()
374          .map(|v| match v {
375            Value::Enumeration(e) => EnumerationWithoutId {
376              variant_id: e.variant_id,
377              value: e.value,
378            },
379            _ => unreachable!(),
380          })
381          .collect(),
382      };
383    }
384    Value::ArrayValue(elements)
385  }
386
387  /// [`array_of`](Self::array_of) for elements of an [`AroraType`](crate::AroraType), which
388  /// settles the empty array's form from the type's definition.
389  pub fn array_of_type<T: crate::AroraType>(elements: Vec<Value>) -> Value {
390    if elements.is_empty() {
391      let enumeration = matches!(
392        T::arora_type().kind,
393        crate::ty::low::TypeKind::Enumeration(_)
394      );
395      return Self::empty_array(T::arora_type_id(), enumeration);
396    }
397    Self::array_of(T::arora_type_id(), elements)
398  }
399
400  fn empty_array(element_id: Uuid, enumeration: bool) -> Value {
401    let id = &element_id;
402    if id == &*crate::ty::BOOLEAN_ID {
403      Value::ArrayBoolean(vec![])
404    } else if id == &*crate::ty::U8_ID {
405      Value::ArrayU8(vec![])
406    } else if id == &*crate::ty::U16_ID {
407      Value::ArrayU16(vec![])
408    } else if id == &*crate::ty::U32_ID {
409      Value::ArrayU32(vec![])
410    } else if id == &*crate::ty::U64_ID {
411      Value::ArrayU64(vec![])
412    } else if id == &*crate::ty::I8_ID {
413      Value::ArrayI8(vec![])
414    } else if id == &*crate::ty::I16_ID {
415      Value::ArrayI16(vec![])
416    } else if id == &*crate::ty::I32_ID {
417      Value::ArrayI32(vec![])
418    } else if id == &*crate::ty::I64_ID {
419      Value::ArrayI64(vec![])
420    } else if id == &*crate::ty::F32_ID {
421      Value::ArrayF32(vec![])
422    } else if id == &*crate::ty::F64_ID {
423      Value::ArrayF64(vec![])
424    } else if id == &*crate::ty::STRING_ID {
425      Value::ArrayString(vec![])
426    } else if id == &*crate::ty::UUID_ID || id == &*crate::ty::KEY_VALUE_ID {
427      Value::ArrayValue(vec![])
428    } else if enumeration {
429      Value::ArrayEnumeration {
430        id: element_id,
431        elements: vec![],
432      }
433    } else {
434      Value::ArrayStructure {
435        id: element_id,
436        elements: vec![],
437      }
438    }
439  }
440
441  /// The elements of any array form, each as a standalone [`Value`] — the
442  /// inverse of [`array_of`](Self::array_of). Not an array: `Err` naming what
443  /// it was.
444  pub fn into_elements(self) -> Result<Vec<Value>, String> {
445    macro_rules! typed {
446      ($array:ident, $variant:ident, $v:expr) => {
447        $v.into_iter().map(Value::$variant).collect()
448      };
449    }
450    Ok(match self {
451      Value::ArrayBoolean(v) => typed!(ArrayBoolean, Boolean, v),
452      Value::ArrayU8(v) => typed!(ArrayU8, U8, v),
453      Value::ArrayU16(v) => typed!(ArrayU16, U16, v),
454      Value::ArrayU32(v) => typed!(ArrayU32, U32, v),
455      Value::ArrayU64(v) => typed!(ArrayU64, U64, v),
456      Value::ArrayI8(v) => typed!(ArrayI8, I8, v),
457      Value::ArrayI16(v) => typed!(ArrayI16, I16, v),
458      Value::ArrayI32(v) => typed!(ArrayI32, I32, v),
459      Value::ArrayI64(v) => typed!(ArrayI64, I64, v),
460      Value::ArrayF32(v) => typed!(ArrayF32, F32, v),
461      Value::ArrayF64(v) => typed!(ArrayF64, F64, v),
462      Value::ArrayString(v) => typed!(ArrayString, String, v),
463      Value::ArrayValue(v) => v,
464      Value::ArrayStructure { id, elements } => elements
465        .into_iter()
466        .map(|e| {
467          Value::Structure(Structure {
468            id,
469            fields: e.fields,
470          })
471        })
472        .collect(),
473      Value::ArrayEnumeration { id, elements } => elements
474        .into_iter()
475        .map(|e| {
476          Value::Enumeration(Enumeration {
477            id,
478            variant_id: e.variant_id,
479            value: e.value,
480          })
481        })
482        .collect(),
483      other => return Err(format!("expected an array, got {other}")),
484    })
485  }
486}
487
488impl From<()> for Value {
489  fn from(_: ()) -> Self {
490    Value::Unit
491  }
492}
493
494impl From<bool> for Value {
495  fn from(v: bool) -> Self {
496    Value::Boolean(v)
497  }
498}
499
500impl From<u8> for Value {
501  fn from(v: u8) -> Self {
502    Value::U8(v)
503  }
504}
505
506impl From<u16> for Value {
507  fn from(v: u16) -> Self {
508    Value::U16(v)
509  }
510}
511
512impl From<u32> for Value {
513  fn from(v: u32) -> Self {
514    Value::U32(v)
515  }
516}
517
518impl From<u64> for Value {
519  fn from(v: u64) -> Self {
520    Value::U64(v)
521  }
522}
523
524impl From<i8> for Value {
525  fn from(v: i8) -> Self {
526    Value::I8(v)
527  }
528}
529
530impl From<i16> for Value {
531  fn from(v: i16) -> Self {
532    Value::I16(v)
533  }
534}
535
536impl From<i32> for Value {
537  fn from(v: i32) -> Self {
538    Value::I32(v)
539  }
540}
541
542impl From<i64> for Value {
543  fn from(v: i64) -> Self {
544    Value::I64(v)
545  }
546}
547
548impl From<f32> for Value {
549  fn from(v: f32) -> Self {
550    Value::F32(v)
551  }
552}
553
554impl From<f64> for Value {
555  fn from(v: f64) -> Self {
556    Value::F64(v)
557  }
558}
559
560impl From<String> for Value {
561  fn from(v: String) -> Self {
562    Value::String(v)
563  }
564}
565
566impl From<&str> for Value {
567  fn from(v: &str) -> Self {
568    Value::String(v.to_string())
569  }
570}
571
572impl From<Uuid> for Value {
573  fn from(v: Uuid) -> Self {
574    Value::Uuid(v)
575  }
576}
577
578// Option<T> -> Value::Option conversion
579impl<T> From<Option<T>> for Value
580where
581  T: Into<Value>,
582{
583  fn from(opt: Option<T>) -> Self {
584    match opt {
585      Some(value) => Value::Option(Some(Box::new(value.into()))),
586      None => Value::Option(None),
587    }
588  }
589}
590
591// Vec<Value> -> Value::ArrayValue conversion
592impl From<Vec<Value>> for Value {
593  fn from(vec: Vec<Value>) -> Self {
594    Value::ArrayValue(vec)
595  }
596}
597
598// &[Value] -> Value::ArrayValue conversion
599impl From<&[Value]> for Value {
600  fn from(slice: &[Value]) -> Self {
601    Value::ArrayValue(slice.to_vec())
602  }
603}
604
605// Macro to reduce repetition for Vec, slice, and HashSet conversions
606macro_rules! impl_array_conversions {
607    ($(($rust_type:ty, $variant:ident)),* $(,)?) => {
608        $(
609            // Vec<T> -> Value::Array*
610            impl From<Vec<$rust_type>> for Value {
611                fn from(vec: Vec<$rust_type>) -> Self {
612                    Value::$variant(vec)
613                }
614            }
615
616            // &[T] -> Value::Array*
617            impl From<&[$rust_type]> for Value {
618                fn from(slice: &[$rust_type]) -> Self {
619                    Value::$variant(slice.to_vec())
620                }
621            }
622
623            // HashSet<T> -> Value::Array* (for hashable types only)
624            impl From<std::collections::HashSet<$rust_type>> for Value {
625                fn from(set: std::collections::HashSet<$rust_type>) -> Self {
626                    Value::$variant(set.into_iter().collect())
627                }
628            }
629        )*
630    };
631}
632
633// Apply the macro for all supported array types
634impl_array_conversions! {
635    (bool, ArrayBoolean),
636    (u8, ArrayU8),
637    (u16, ArrayU16),
638    (u32, ArrayU32),
639    (u64, ArrayU64),
640    (i8, ArrayI8),
641    (i16, ArrayI16),
642    (i32, ArrayI32),
643    (i64, ArrayI64),
644    (String, ArrayString),
645}
646
647// Separate implementations for floating point types (no HashSet support)
648macro_rules! impl_float_array_conversions {
649    ($(($rust_type:ty, $variant:ident)),* $(,)?) => {
650        $(
651            // Vec<T> -> Value::Array*
652            impl From<Vec<$rust_type>> for Value {
653                fn from(vec: Vec<$rust_type>) -> Self {
654                    Value::$variant(vec)
655                }
656            }
657
658            // &[T] -> Value::Array*
659            impl From<&[$rust_type]> for Value {
660                fn from(slice: &[$rust_type]) -> Self {
661                    Value::$variant(slice.to_vec())
662                }
663            }
664        )*
665    };
666}
667
668// Apply the macro for floating point types (no HashSet due to Hash requirements)
669impl_float_array_conversions! {
670    (f32, ArrayF32),
671    (f64, ArrayF64),
672}
673
674// All slice and HashSet conversions are now generated by the macros above
675
676#[cfg(test)]
677mod tests {
678  use super::*;
679  use json5;
680  use pretty_assertions::assert_eq;
681
682  // Helper function for testing serialization/deserialization roundtrip
683  fn test_serde_roundtrip<T>(value: &T, name: &str)
684  where
685    T: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug + Clone,
686  {
687    // First with JSON
688    let json = json5::to_string(value).unwrap();
689    println!("{} JSON:\n{}", name, json);
690
691    let deserialized: T = json5::from_str(&json).unwrap();
692    assert_eq!(
693      value, &deserialized,
694      "Roundtrip JSON serialization failed for {name}"
695    );
696
697    // Then with RON
698    let ron = ron::to_string(value).unwrap();
699    println!("{} RON:\n{}", name, ron);
700    let deserialized: T = ron::from_str(&ron).unwrap();
701    assert_eq!(
702      value, &deserialized,
703      "Roundtrip RON serialization failed for {name}"
704    );
705  }
706
707  // Value ⇄ YAML: the coverage `arora-buffers::serde_raw_id` used to duplicate
708  // now lives here, on the canonical `Value` (which is broader — it has option,
709  // map, uuid). A nested value exercises struct + array + string together.
710  #[test]
711  fn value_round_trips_through_yaml() {
712    let value = Value::Structure(Structure {
713      id: Uuid::from_u128(0x10),
714      fields: vec![
715        StructureField {
716          id: Uuid::from_u128(0x01),
717          value: Box::new(Value::ArrayF64(vec![1.0, -2.0, 3.5])),
718        },
719        StructureField {
720          id: Uuid::from_u128(0x02),
721          value: Box::new(Value::String("hi".to_string())),
722        },
723      ],
724    });
725    let yaml = serde_yaml::to_string(&value).unwrap();
726    let back: Value = serde_yaml::from_str(&yaml).unwrap();
727    assert_eq!(value, back, "Value did not round-trip through YAML");
728  }
729
730  #[test]
731  fn test_type_serialization() {
732    // Test all variants of Type enum
733    for typ in [
734      Type::Unit,
735      Type::Boolean,
736      Type::U8,
737      Type::U16,
738      Type::U32,
739      Type::U64,
740      Type::I8,
741      Type::I16,
742      Type::I32,
743      Type::I64,
744      Type::F32,
745      Type::F64,
746      Type::String,
747      Type::Option,
748      Type::Structure,
749      Type::Enumeration,
750      Type::ArrayBoolean,
751      Type::ArrayU8,
752      Type::ArrayU16,
753      Type::ArrayU32,
754      Type::ArrayU64,
755      Type::ArrayI8,
756      Type::ArrayI16,
757      Type::ArrayI32,
758      Type::ArrayI64,
759      Type::ArrayF32,
760      Type::ArrayF64,
761      Type::ArrayString,
762      Type::ArrayValue,
763      Type::ArrayStructure,
764      Type::ArrayEnumeration,
765      Type::KeyValue,
766      Type::Uuid,
767    ] {
768      test_serde_roundtrip(&typ, &format!("Type::{:?}", typ));
769    }
770  }
771
772  #[test]
773  fn test_value_primitive_serialization() {
774    // Test primitive value variants
775    let primitives = vec![
776      ("Unit", Value::Unit),
777      ("Boolean_true", Value::Boolean(true)),
778      ("Boolean_false", Value::Boolean(false)),
779      ("U8_min", Value::U8(0)),
780      ("U8_max", Value::U8(u8::MAX)),
781      ("U16_max", Value::U16(u16::MAX)),
782      ("U32_max", Value::U32(u32::MAX)),
783      ("U64_max", Value::U64(u64::MAX)),
784      ("I8_min", Value::I8(i8::MIN)),
785      ("I8_max", Value::I8(i8::MAX)),
786      ("I16_min", Value::I16(i16::MIN)),
787      ("I32_min", Value::I32(i32::MIN)),
788      ("I64_min", Value::I64(i64::MIN)),
789      ("F32_zero", Value::F32(0.0)),
790      ("F32_inf", Value::F32(f32::INFINITY)),
791      ("F32_neg_inf", Value::F32(f32::NEG_INFINITY)),
792      ("F64_zero", Value::F64(0.0)),
793      ("F64_inf", Value::F64(f64::INFINITY)),
794      ("F64_neg_inf", Value::F64(f64::NEG_INFINITY)),
795      ("String_empty", Value::String("".to_string())),
796      ("String_hello", Value::String("Hello, world!".to_string())),
797      (
798        "String_special",
799        Value::String("Special chars: \n\t\r\"\\".to_string()),
800      ),
801    ];
802
803    for (name, value) in primitives {
804      test_serde_roundtrip(&value, name);
805    }
806
807    // Special handling for NaN values
808    let f32_nan = Value::F32(f32::NAN);
809    let f32_json = json5::to_string(&f32_nan).unwrap();
810    println!("F32_NaN JSON:\n{}", f32_json);
811    let deserialized_f32: Value = json5::from_str(&f32_json).unwrap();
812    if let Value::F32(val) = deserialized_f32 {
813      assert!(val.is_nan(), "Deserialized F32 should be NaN");
814    }
815
816    let f64_nan = Value::F64(f64::NAN);
817    let f64_json = json5::to_string(&f64_nan).unwrap();
818    println!("F64_NaN JSON:\n{}", f64_json);
819    let deserialized_f64: Value = json5::from_str(&f64_json).unwrap();
820    if let Value::F64(val) = deserialized_f64 {
821      assert!(val.is_nan(), "Deserialized F64 should be NaN");
822    }
823  }
824
825  #[test]
826  fn test_value_array_serialization() {
827    // Test array value variants
828    let arrays = vec![
829      ("ArrayBoolean_empty", Value::ArrayBoolean(vec![])),
830      ("ArrayBoolean", Value::ArrayBoolean(vec![true, false])),
831      ("ArrayU8", Value::ArrayU8(vec![0, 123, 255])),
832      ("ArrayI32", Value::ArrayI32(vec![i32::MIN, 0, i32::MAX])),
833      (
834        "ArrayF64",
835        Value::ArrayF64(vec![-1.0, 0.0, 1.0, f64::INFINITY]),
836      ),
837      (
838        "ArrayString",
839        Value::ArrayString(vec!["a".to_string(), "b".to_string()]),
840      ),
841    ];
842
843    for (name, value) in arrays {
844      test_serde_roundtrip(&value, name);
845    }
846  }
847
848  #[test]
849  fn test_structure_field_serialization() {
850    let field = StructureField {
851      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
852      value: Box::new(Value::String("test field".to_string())),
853    };
854
855    test_serde_roundtrip(&field, "StructureField");
856  }
857
858  #[test]
859  fn test_structure_serialization() {
860    // Test empty structure
861    let empty_structure = Structure {
862      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
863      fields: vec![],
864    };
865
866    test_serde_roundtrip(&empty_structure, "EmptyStructure");
867
868    // Test populated structure
869    let structure = Structure {
870      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
871      fields: vec![
872        StructureField {
873          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
874          value: Box::new(Value::String("field1".to_string())),
875        },
876        StructureField {
877          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
878          value: Box::new(Value::I32(42)),
879        },
880      ],
881    };
882
883    test_serde_roundtrip(&structure, "Structure");
884  }
885
886  #[test]
887  fn test_structure_without_id_serialization() {
888    let structure_without_id = StructureWithoutId {
889      fields: vec![StructureField {
890        id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
891        value: Box::new(Value::String("field1".to_string())),
892      }],
893    };
894
895    test_serde_roundtrip(&structure_without_id, "StructureWithoutId");
896  }
897
898  #[test]
899  fn test_enumeration_serialization() {
900    let enumeration = Enumeration {
901      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
902      variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
903      value: Box::new(Value::String("variant value".to_string())),
904    };
905
906    test_serde_roundtrip(&enumeration, "Enumeration");
907  }
908
909  #[test]
910  fn test_enumeration_without_id_serialization() {
911    let enumeration_without_id = EnumerationWithoutId {
912      variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
913      value: Box::new(Value::String("variant value".to_string())),
914    };
915
916    test_serde_roundtrip(&enumeration_without_id, "EnumerationWithoutId");
917  }
918
919  #[test]
920  fn test_complex_nested_values() {
921    // Complex nested structure with enumeration
922    let complex_value = Value::Structure(Structure {
923      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
924      fields: vec![
925        StructureField {
926          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
927          value: Box::new(Value::String("name".to_string())),
928        },
929        StructureField {
930          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
931          value: Box::new(Value::Enumeration(Enumeration {
932            id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440003").unwrap(),
933            variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440004").unwrap(),
934            value: Box::new(Value::Boolean(true)),
935          })),
936        },
937      ],
938    });
939
940    test_serde_roundtrip(&complex_value, "ComplexNestedValue");
941  }
942
943  #[test]
944  fn test_array_structure_and_enumeration() {
945    // Test array of structures
946    let array_structure = Value::ArrayStructure {
947      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
948      elements: vec![
949        StructureWithoutId {
950          fields: vec![StructureField {
951            id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
952            value: Box::new(Value::String("element1".to_string())),
953          }],
954        },
955        StructureWithoutId { fields: vec![] }, // Empty structure
956      ],
957    };
958
959    test_serde_roundtrip(&array_structure, "ArrayStructure");
960
961    // Test array of enumerations
962    let array_enumeration = Value::ArrayEnumeration {
963      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
964      elements: vec![
965        EnumerationWithoutId {
966          variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
967          value: Box::new(Value::String("variant1".to_string())),
968        },
969        EnumerationWithoutId {
970          variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
971          value: Box::new(Value::U32(42)),
972        },
973      ],
974    };
975
976    test_serde_roundtrip(&array_enumeration, "ArrayEnumeration");
977  }
978
979  #[test]
980  fn test_from_conversions_primitives() {
981    // Test From conversions for primitive types
982    assert_eq!(Value::from(()), Value::Unit);
983    assert_eq!(Value::from(true), Value::Boolean(true));
984    assert_eq!(Value::from(false), Value::Boolean(false));
985
986    assert_eq!(Value::from(42u8), Value::U8(42));
987    assert_eq!(Value::from(1234u16), Value::U16(1234));
988    assert_eq!(Value::from(123456u32), Value::U32(123456));
989    assert_eq!(Value::from(12345678901234u64), Value::U64(12345678901234));
990
991    assert_eq!(Value::from(-42i8), Value::I8(-42));
992    assert_eq!(Value::from(-1234i16), Value::I16(-1234));
993    assert_eq!(Value::from(-123456i32), Value::I32(-123456));
994    assert_eq!(Value::from(-12345678901234i64), Value::I64(-12345678901234));
995
996    assert_eq!(
997      Value::from(std::f32::consts::PI),
998      Value::F32(std::f32::consts::PI)
999    );
1000    assert_eq!(
1001      Value::from(std::f64::consts::PI),
1002      Value::F64(std::f64::consts::PI)
1003    );
1004
1005    assert_eq!(
1006      Value::from("hello".to_string()),
1007      Value::String("hello".to_string())
1008    );
1009    assert_eq!(Value::from("world"), Value::String("world".to_string()));
1010
1011    let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
1012    assert_eq!(Value::from(uuid), Value::Uuid(uuid));
1013  }
1014
1015  #[test]
1016  fn test_from_conversions_arrays_vec() {
1017    // Test Vec conversions
1018    assert_eq!(
1019      Value::from(vec![true, false, true]),
1020      Value::ArrayBoolean(vec![true, false, true])
1021    );
1022    assert_eq!(
1023      Value::from(vec![1u8, 2u8, 3u8]),
1024      Value::ArrayU8(vec![1, 2, 3])
1025    );
1026    assert_eq!(
1027      Value::from(vec![100u16, 200u16]),
1028      Value::ArrayU16(vec![100, 200])
1029    );
1030    assert_eq!(
1031      Value::from(vec![1000u32, 2000u32]),
1032      Value::ArrayU32(vec![1000, 2000])
1033    );
1034    assert_eq!(
1035      Value::from(vec![10000u64, 20000u64]),
1036      Value::ArrayU64(vec![10000, 20000])
1037    );
1038
1039    assert_eq!(Value::from(vec![-1i8, -2i8]), Value::ArrayI8(vec![-1, -2]));
1040    assert_eq!(
1041      Value::from(vec![-100i16, -200i16]),
1042      Value::ArrayI16(vec![-100, -200])
1043    );
1044    assert_eq!(
1045      Value::from(vec![-1000i32, -2000i32]),
1046      Value::ArrayI32(vec![-1000, -2000])
1047    );
1048    assert_eq!(
1049      Value::from(vec![-10000i64, -20000i64]),
1050      Value::ArrayI64(vec![-10000, -20000])
1051    );
1052
1053    assert_eq!(
1054      Value::from(vec![1.5f32, 2.5f32]),
1055      Value::ArrayF32(vec![1.5, 2.5])
1056    );
1057    assert_eq!(
1058      Value::from(vec![1.5f64, 2.5f64]),
1059      Value::ArrayF64(vec![1.5, 2.5])
1060    );
1061
1062    assert_eq!(
1063      Value::from(vec!["hello".to_string(), "world".to_string()]),
1064      Value::ArrayString(vec!["hello".to_string(), "world".to_string()])
1065    );
1066  }
1067
1068  #[test]
1069  fn test_from_conversions_arrays_slices() {
1070    // Test slice conversions
1071    let bool_slice = &[true, false, true][..];
1072    assert_eq!(
1073      Value::from(bool_slice),
1074      Value::ArrayBoolean(vec![true, false, true])
1075    );
1076
1077    let u32_slice = &[1u32, 2u32, 3u32][..];
1078    assert_eq!(Value::from(u32_slice), Value::ArrayU32(vec![1, 2, 3]));
1079
1080    let string_slice = &["a".to_string(), "b".to_string()][..];
1081    assert_eq!(
1082      Value::from(string_slice),
1083      Value::ArrayString(vec!["a".to_string(), "b".to_string()])
1084    );
1085  }
1086
1087  #[test]
1088  fn test_from_conversions_hashset() {
1089    use std::collections::HashSet;
1090
1091    // Test HashSet conversions (note: order is not guaranteed, so we check contents)
1092    let bool_set: HashSet<bool> = [true, false].into_iter().collect();
1093    if let Value::ArrayBoolean(vec) = Value::from(bool_set) {
1094      assert_eq!(vec.len(), 2);
1095      assert!(vec.contains(&true));
1096      assert!(vec.contains(&false));
1097    } else {
1098      panic!("Expected ArrayBoolean");
1099    }
1100
1101    let u32_set: HashSet<u32> = [1, 2, 3].into_iter().collect();
1102    if let Value::ArrayU32(vec) = Value::from(u32_set) {
1103      assert_eq!(vec.len(), 3);
1104      assert!(vec.contains(&1));
1105      assert!(vec.contains(&2));
1106      assert!(vec.contains(&3));
1107    } else {
1108      panic!("Expected ArrayU32");
1109    }
1110
1111    let string_set: HashSet<String> = ["a".to_string(), "b".to_string()].into_iter().collect();
1112    if let Value::ArrayString(vec) = Value::from(string_set) {
1113      assert_eq!(vec.len(), 2);
1114      assert!(vec.contains(&"a".to_string()));
1115      assert!(vec.contains(&"b".to_string()));
1116    } else {
1117      panic!("Expected ArrayString");
1118    }
1119
1120    // Test empty HashSet
1121    let empty_set: HashSet<u32> = HashSet::new();
1122    assert_eq!(Value::from(empty_set), Value::ArrayU32(vec![]));
1123  }
1124
1125  #[test]
1126  fn test_from_conversions_empty_arrays() {
1127    // Test empty array conversions
1128    assert_eq!(Value::from(Vec::<bool>::new()), Value::ArrayBoolean(vec![]));
1129    assert_eq!(Value::from(Vec::<u8>::new()), Value::ArrayU8(vec![]));
1130    assert_eq!(Value::from(Vec::<u16>::new()), Value::ArrayU16(vec![]));
1131    assert_eq!(Value::from(Vec::<u32>::new()), Value::ArrayU32(vec![]));
1132    assert_eq!(Value::from(Vec::<u64>::new()), Value::ArrayU64(vec![]));
1133    assert_eq!(Value::from(Vec::<i8>::new()), Value::ArrayI8(vec![]));
1134    assert_eq!(Value::from(Vec::<i16>::new()), Value::ArrayI16(vec![]));
1135    assert_eq!(Value::from(Vec::<i32>::new()), Value::ArrayI32(vec![]));
1136    assert_eq!(Value::from(Vec::<i64>::new()), Value::ArrayI64(vec![]));
1137    assert_eq!(Value::from(Vec::<f32>::new()), Value::ArrayF32(vec![]));
1138    assert_eq!(Value::from(Vec::<f64>::new()), Value::ArrayF64(vec![]));
1139    assert_eq!(
1140      Value::from(Vec::<String>::new()),
1141      Value::ArrayString(vec![])
1142    );
1143  }
1144
1145  #[test]
1146  fn test_from_conversions_option() {
1147    // Test Option<T> conversions for various primitive types
1148
1149    // Test Some variants
1150    assert_eq!(
1151      Value::from(Some(42u32)),
1152      Value::Option(Some(Box::new(Value::U32(42))))
1153    );
1154    assert_eq!(
1155      Value::from(Some(true)),
1156      Value::Option(Some(Box::new(Value::Boolean(true))))
1157    );
1158    assert_eq!(
1159      Value::from(Some("hello".to_string())),
1160      Value::Option(Some(Box::new(Value::String("hello".to_string()))))
1161    );
1162    assert_eq!(
1163      Value::from(Some(std::f64::consts::PI)),
1164      Value::Option(Some(Box::new(Value::F64(std::f64::consts::PI))))
1165    );
1166
1167    // Test None variants
1168    assert_eq!(Value::from(None::<u32>), Value::Option(None));
1169    assert_eq!(Value::from(None::<bool>), Value::Option(None));
1170    assert_eq!(Value::from(None::<String>), Value::Option(None));
1171    assert_eq!(Value::from(None::<f64>), Value::Option(None));
1172
1173    // Test nested Option with Value
1174    let nested_value = Value::ArrayU32(vec![1, 2, 3]);
1175    assert_eq!(
1176      Value::from(Some(nested_value.clone())),
1177      Value::Option(Some(Box::new(nested_value)))
1178    );
1179    assert_eq!(Value::from(None::<Value>), Value::Option(None));
1180  }
1181
1182  #[test]
1183  fn test_from_conversions_array_value() {
1184    // Test Vec<Value> -> ArrayValue conversions
1185
1186    // Test empty Vec<Value>
1187    assert_eq!(Value::from(Vec::<Value>::new()), Value::ArrayValue(vec![]));
1188
1189    // Test Vec<Value> with mixed types
1190    let mixed_values = vec![
1191      Value::U32(42),
1192      Value::Boolean(true),
1193      Value::String("test".to_string()),
1194      Value::F64(std::f64::consts::PI),
1195      Value::Unit,
1196    ];
1197    assert_eq!(
1198      Value::from(mixed_values.clone()),
1199      Value::ArrayValue(mixed_values.clone())
1200    );
1201
1202    // Test slice conversion
1203    let values_slice = &[
1204      Value::I32(-10),
1205      Value::Boolean(false),
1206      Value::String("slice".to_string()),
1207    ][..];
1208    assert_eq!(
1209      Value::from(values_slice),
1210      Value::ArrayValue(vec![
1211        Value::I32(-10),
1212        Value::Boolean(false),
1213        Value::String("slice".to_string()),
1214      ])
1215    );
1216
1217    // Test ArrayValue with nested arrays
1218    let nested_array = vec![
1219      Value::ArrayU32(vec![1, 2, 3]),
1220      Value::ArrayString(vec!["a".to_string(), "b".to_string()]),
1221      Value::ArrayBoolean(vec![true, false]),
1222    ];
1223    assert_eq!(
1224      Value::from(nested_array.clone()),
1225      Value::ArrayValue(nested_array)
1226    );
1227
1228    // Test ArrayValue with Options
1229    let option_array = vec![
1230      Value::Option(Some(Box::new(Value::U32(1)))),
1231      Value::Option(None),
1232      Value::Option(Some(Box::new(Value::String("test".to_string())))),
1233    ];
1234    assert_eq!(
1235      Value::from(option_array.clone()),
1236      Value::ArrayValue(option_array)
1237    );
1238  }
1239
1240  #[test]
1241  fn test_type_uuid() {
1242    use crate::ty;
1243
1244    // Primitives → well-known UUIDs
1245    assert_eq!(Value::Unit.type_uuid(), *ty::UNIT_ID);
1246    assert_eq!(Value::Boolean(false).type_uuid(), *ty::BOOLEAN_ID);
1247    assert_eq!(Value::I8(0).type_uuid(), *ty::I8_ID);
1248    assert_eq!(Value::I16(0).type_uuid(), *ty::I16_ID);
1249    assert_eq!(Value::I32(0).type_uuid(), *ty::I32_ID);
1250    assert_eq!(Value::I64(0).type_uuid(), *ty::I64_ID);
1251    assert_eq!(Value::U8(0).type_uuid(), *ty::U8_ID);
1252    assert_eq!(Value::U16(0).type_uuid(), *ty::U16_ID);
1253    assert_eq!(Value::U32(0).type_uuid(), *ty::U32_ID);
1254    assert_eq!(Value::U64(0).type_uuid(), *ty::U64_ID);
1255    assert_eq!(Value::F32(0.0).type_uuid(), *ty::F32_ID);
1256    assert_eq!(Value::F64(0.0).type_uuid(), *ty::F64_ID);
1257    assert_eq!(Value::String("".into()).type_uuid(), *ty::STRING_ID);
1258
1259    // Typed compounds → embedded ID
1260    let test_id = uuid::Uuid::from_u128(0xdeadbeef);
1261    let variant_id = uuid::Uuid::from_u128(0xcafebabe);
1262
1263    assert_eq!(
1264      Value::Structure(Structure {
1265        id: test_id,
1266        fields: vec![],
1267      })
1268      .type_uuid(),
1269      test_id
1270    );
1271    assert_eq!(
1272      Value::Enumeration(Enumeration {
1273        id: test_id,
1274        variant_id,
1275        value: Box::new(Value::Unit),
1276      })
1277      .type_uuid(),
1278      test_id
1279    );
1280    assert_eq!(
1281      Value::ArrayStructure {
1282        id: test_id,
1283        elements: vec![],
1284      }
1285      .type_uuid(),
1286      test_id
1287    );
1288    assert_eq!(
1289      Value::ArrayEnumeration {
1290        id: test_id,
1291        elements: vec![],
1292      }
1293      .type_uuid(),
1294      test_id
1295    );
1296
1297    // Compound types → well-known UUIDs
1298    assert_eq!(Value::Option(None).type_uuid(), *ty::OPTION_ID);
1299    assert_eq!(
1300      Value::Option(Some(Box::new(Value::Unit))).type_uuid(),
1301      *ty::OPTION_ID
1302    );
1303    assert_eq!(
1304      Value::ArrayBoolean(vec![]).type_uuid(),
1305      *ty::ARRAY_BOOLEAN_ID
1306    );
1307    assert_eq!(Value::ArrayU8(vec![]).type_uuid(), *ty::ARRAY_U8_ID);
1308    assert_eq!(Value::ArrayU16(vec![]).type_uuid(), *ty::ARRAY_U16_ID);
1309    assert_eq!(Value::ArrayU32(vec![]).type_uuid(), *ty::ARRAY_U32_ID);
1310    assert_eq!(Value::ArrayU64(vec![]).type_uuid(), *ty::ARRAY_U64_ID);
1311    assert_eq!(Value::ArrayI8(vec![]).type_uuid(), *ty::ARRAY_I8_ID);
1312    assert_eq!(Value::ArrayI16(vec![]).type_uuid(), *ty::ARRAY_I16_ID);
1313    assert_eq!(Value::ArrayI32(vec![]).type_uuid(), *ty::ARRAY_I32_ID);
1314    assert_eq!(Value::ArrayI64(vec![]).type_uuid(), *ty::ARRAY_I64_ID);
1315    assert_eq!(Value::ArrayF32(vec![]).type_uuid(), *ty::ARRAY_F32_ID);
1316    assert_eq!(Value::ArrayF64(vec![]).type_uuid(), *ty::ARRAY_F64_ID);
1317    assert_eq!(Value::ArrayString(vec![]).type_uuid(), *ty::ARRAY_STRING_ID);
1318    assert_eq!(Value::ArrayValue(vec![]).type_uuid(), *ty::ARRAY_VALUE_ID);
1319    assert_eq!(
1320      Value::KeyValue(KeyValue::default()).type_uuid(),
1321      *ty::KEY_VALUE_ID
1322    );
1323    assert_eq!(Value::Uuid(uuid::Uuid::nil()).type_uuid(), *ty::UUID_ID);
1324
1325    // All well-known IDs are distinct
1326    let all_wellknown: Vec<uuid::Uuid> = ty::WELL_KNOWN_IDS.iter().copied().collect();
1327    assert_eq!(all_wellknown.len(), 29); // 13 primitives + 16 compounds
1328  }
1329}