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  /// Returns the type UUID for this value.
190  ///
191  /// Primitives map to well-known UUIDs from `ty::mod`. Structures and enumerations
192  /// carry their own type ID. Arrays of structures/enumerations use the element type ID.
193  /// Other compound types (plain arrays, Option, KeyValue, Uuid) have their own well-known UUIDs.
194  pub fn type_uuid(&self) -> Uuid {
195    use crate::ty;
196    match self {
197      Value::Unit => *ty::UNIT_ID,
198      Value::Boolean(_) => *ty::BOOLEAN_ID,
199      Value::I8(_) => *ty::I8_ID,
200      Value::I16(_) => *ty::I16_ID,
201      Value::I32(_) => *ty::I32_ID,
202      Value::I64(_) => *ty::I64_ID,
203      Value::U8(_) => *ty::U8_ID,
204      Value::U16(_) => *ty::U16_ID,
205      Value::U32(_) => *ty::U32_ID,
206      Value::U64(_) => *ty::U64_ID,
207      Value::F32(_) => *ty::F32_ID,
208      Value::F64(_) => *ty::F64_ID,
209      Value::String(_) => *ty::STRING_ID,
210      Value::Option(_) => *ty::OPTION_ID,
211      Value::Structure(s) => s.id,
212      Value::Enumeration(e) => e.id,
213      Value::ArrayBoolean(_) => *ty::ARRAY_BOOLEAN_ID,
214      Value::ArrayU8(_) => *ty::ARRAY_U8_ID,
215      Value::ArrayU16(_) => *ty::ARRAY_U16_ID,
216      Value::ArrayU32(_) => *ty::ARRAY_U32_ID,
217      Value::ArrayU64(_) => *ty::ARRAY_U64_ID,
218      Value::ArrayI8(_) => *ty::ARRAY_I8_ID,
219      Value::ArrayI16(_) => *ty::ARRAY_I16_ID,
220      Value::ArrayI32(_) => *ty::ARRAY_I32_ID,
221      Value::ArrayI64(_) => *ty::ARRAY_I64_ID,
222      Value::ArrayF32(_) => *ty::ARRAY_F32_ID,
223      Value::ArrayF64(_) => *ty::ARRAY_F64_ID,
224      Value::ArrayString(_) => *ty::ARRAY_STRING_ID,
225      Value::ArrayValue(_) => *ty::ARRAY_VALUE_ID,
226      Value::ArrayStructure { id, .. } => *id,
227      Value::ArrayEnumeration { id, .. } => *id,
228      Value::KeyValue(_) => *ty::KEY_VALUE_ID,
229      Value::Uuid(_) => *ty::UUID_ID,
230    }
231  }
232}
233
234#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
235#[display("{}::{}({})", id, variant_id, value)]
236pub struct Enumeration {
237  pub id: Uuid,
238  pub variant_id: Uuid,
239  pub value: Box<Value>,
240}
241
242#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
243#[display("{}({:?})", id, fields)]
244pub struct Structure {
245  pub id: Uuid,
246  pub fields: Vec<StructureField>,
247}
248
249#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
250#[display("{}: {}", id, value)]
251pub struct StructureField {
252  pub id: Uuid,
253  pub value: Box<Value>,
254}
255
256#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
257#[display("({:?})", fields)]
258pub struct StructureWithoutId {
259  // #[serde(flatten)]
260  pub fields: Vec<StructureField>,
261}
262
263#[derive(Debug, Clone, Display, Serialize, Deserialize, PartialEq)]
264#[display("{}({})", variant_id, value)]
265pub struct EnumerationWithoutId {
266  pub variant_id: Uuid,
267  pub value: Box<Value>,
268}
269
270/// A common error type for conversion erros from and to [`Value`].
271#[derive(Display, Debug)]
272pub struct ConversionError {
273  pub message: String,
274}
275
276impl std::error::Error for ConversionError {}
277
278impl From<()> for Value {
279  fn from(_: ()) -> Self {
280    Value::Unit
281  }
282}
283
284impl From<bool> for Value {
285  fn from(v: bool) -> Self {
286    Value::Boolean(v)
287  }
288}
289
290impl From<u8> for Value {
291  fn from(v: u8) -> Self {
292    Value::U8(v)
293  }
294}
295
296impl From<u16> for Value {
297  fn from(v: u16) -> Self {
298    Value::U16(v)
299  }
300}
301
302impl From<u32> for Value {
303  fn from(v: u32) -> Self {
304    Value::U32(v)
305  }
306}
307
308impl From<u64> for Value {
309  fn from(v: u64) -> Self {
310    Value::U64(v)
311  }
312}
313
314impl From<i8> for Value {
315  fn from(v: i8) -> Self {
316    Value::I8(v)
317  }
318}
319
320impl From<i16> for Value {
321  fn from(v: i16) -> Self {
322    Value::I16(v)
323  }
324}
325
326impl From<i32> for Value {
327  fn from(v: i32) -> Self {
328    Value::I32(v)
329  }
330}
331
332impl From<i64> for Value {
333  fn from(v: i64) -> Self {
334    Value::I64(v)
335  }
336}
337
338impl From<f32> for Value {
339  fn from(v: f32) -> Self {
340    Value::F32(v)
341  }
342}
343
344impl From<f64> for Value {
345  fn from(v: f64) -> Self {
346    Value::F64(v)
347  }
348}
349
350impl From<String> for Value {
351  fn from(v: String) -> Self {
352    Value::String(v)
353  }
354}
355
356impl From<&str> for Value {
357  fn from(v: &str) -> Self {
358    Value::String(v.to_string())
359  }
360}
361
362impl From<Uuid> for Value {
363  fn from(v: Uuid) -> Self {
364    Value::Uuid(v)
365  }
366}
367
368// Option<T> -> Value::Option conversion
369impl<T> From<Option<T>> for Value
370where
371  T: Into<Value>,
372{
373  fn from(opt: Option<T>) -> Self {
374    match opt {
375      Some(value) => Value::Option(Some(Box::new(value.into()))),
376      None => Value::Option(None),
377    }
378  }
379}
380
381// Vec<Value> -> Value::ArrayValue conversion
382impl From<Vec<Value>> for Value {
383  fn from(vec: Vec<Value>) -> Self {
384    Value::ArrayValue(vec)
385  }
386}
387
388// &[Value] -> Value::ArrayValue conversion
389impl From<&[Value]> for Value {
390  fn from(slice: &[Value]) -> Self {
391    Value::ArrayValue(slice.to_vec())
392  }
393}
394
395// Macro to reduce repetition for Vec, slice, and HashSet conversions
396macro_rules! impl_array_conversions {
397    ($(($rust_type:ty, $variant:ident)),* $(,)?) => {
398        $(
399            // Vec<T> -> Value::Array*
400            impl From<Vec<$rust_type>> for Value {
401                fn from(vec: Vec<$rust_type>) -> Self {
402                    Value::$variant(vec)
403                }
404            }
405
406            // &[T] -> Value::Array*
407            impl From<&[$rust_type]> for Value {
408                fn from(slice: &[$rust_type]) -> Self {
409                    Value::$variant(slice.to_vec())
410                }
411            }
412
413            // HashSet<T> -> Value::Array* (for hashable types only)
414            impl From<std::collections::HashSet<$rust_type>> for Value {
415                fn from(set: std::collections::HashSet<$rust_type>) -> Self {
416                    Value::$variant(set.into_iter().collect())
417                }
418            }
419        )*
420    };
421}
422
423// Apply the macro for all supported array types
424impl_array_conversions! {
425    (bool, ArrayBoolean),
426    (u8, ArrayU8),
427    (u16, ArrayU16),
428    (u32, ArrayU32),
429    (u64, ArrayU64),
430    (i8, ArrayI8),
431    (i16, ArrayI16),
432    (i32, ArrayI32),
433    (i64, ArrayI64),
434    (String, ArrayString),
435}
436
437// Separate implementations for floating point types (no HashSet support)
438macro_rules! impl_float_array_conversions {
439    ($(($rust_type:ty, $variant:ident)),* $(,)?) => {
440        $(
441            // Vec<T> -> Value::Array*
442            impl From<Vec<$rust_type>> for Value {
443                fn from(vec: Vec<$rust_type>) -> Self {
444                    Value::$variant(vec)
445                }
446            }
447
448            // &[T] -> Value::Array*
449            impl From<&[$rust_type]> for Value {
450                fn from(slice: &[$rust_type]) -> Self {
451                    Value::$variant(slice.to_vec())
452                }
453            }
454        )*
455    };
456}
457
458// Apply the macro for floating point types (no HashSet due to Hash requirements)
459impl_float_array_conversions! {
460    (f32, ArrayF32),
461    (f64, ArrayF64),
462}
463
464// All slice and HashSet conversions are now generated by the macros above
465
466#[cfg(test)]
467mod tests {
468  use super::*;
469  use json5;
470  use pretty_assertions::assert_eq;
471
472  // Helper function for testing serialization/deserialization roundtrip
473  fn test_serde_roundtrip<T>(value: &T, name: &str)
474  where
475    T: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug + Clone,
476  {
477    // First with JSON
478    let json = json5::to_string(value).unwrap();
479    println!("{} JSON:\n{}", name, json);
480
481    let deserialized: T = json5::from_str(&json).unwrap();
482    assert_eq!(
483      value, &deserialized,
484      "Roundtrip JSON serialization failed for {name}"
485    );
486
487    // Then with RON
488    let ron = ron::to_string(value).unwrap();
489    println!("{} RON:\n{}", name, ron);
490    let deserialized: T = ron::from_str(&ron).unwrap();
491    assert_eq!(
492      value, &deserialized,
493      "Roundtrip RON serialization failed for {name}"
494    );
495  }
496
497  #[test]
498  fn test_type_serialization() {
499    // Test all variants of Type enum
500    for typ in [
501      Type::Unit,
502      Type::Boolean,
503      Type::U8,
504      Type::U16,
505      Type::U32,
506      Type::U64,
507      Type::I8,
508      Type::I16,
509      Type::I32,
510      Type::I64,
511      Type::F32,
512      Type::F64,
513      Type::String,
514      Type::Option,
515      Type::Structure,
516      Type::Enumeration,
517      Type::ArrayBoolean,
518      Type::ArrayU8,
519      Type::ArrayU16,
520      Type::ArrayU32,
521      Type::ArrayU64,
522      Type::ArrayI8,
523      Type::ArrayI16,
524      Type::ArrayI32,
525      Type::ArrayI64,
526      Type::ArrayF32,
527      Type::ArrayF64,
528      Type::ArrayString,
529      Type::ArrayValue,
530      Type::ArrayStructure,
531      Type::ArrayEnumeration,
532      Type::KeyValue,
533      Type::Uuid,
534    ] {
535      test_serde_roundtrip(&typ, &format!("Type::{:?}", typ));
536    }
537  }
538
539  #[test]
540  fn test_value_primitive_serialization() {
541    // Test primitive value variants
542    let primitives = vec![
543      ("Unit", Value::Unit),
544      ("Boolean_true", Value::Boolean(true)),
545      ("Boolean_false", Value::Boolean(false)),
546      ("U8_min", Value::U8(0)),
547      ("U8_max", Value::U8(u8::MAX)),
548      ("U16_max", Value::U16(u16::MAX)),
549      ("U32_max", Value::U32(u32::MAX)),
550      ("U64_max", Value::U64(u64::MAX)),
551      ("I8_min", Value::I8(i8::MIN)),
552      ("I8_max", Value::I8(i8::MAX)),
553      ("I16_min", Value::I16(i16::MIN)),
554      ("I32_min", Value::I32(i32::MIN)),
555      ("I64_min", Value::I64(i64::MIN)),
556      ("F32_zero", Value::F32(0.0)),
557      ("F32_inf", Value::F32(f32::INFINITY)),
558      ("F32_neg_inf", Value::F32(f32::NEG_INFINITY)),
559      ("F64_zero", Value::F64(0.0)),
560      ("F64_inf", Value::F64(f64::INFINITY)),
561      ("F64_neg_inf", Value::F64(f64::NEG_INFINITY)),
562      ("String_empty", Value::String("".to_string())),
563      ("String_hello", Value::String("Hello, world!".to_string())),
564      (
565        "String_special",
566        Value::String("Special chars: \n\t\r\"\\".to_string()),
567      ),
568    ];
569
570    for (name, value) in primitives {
571      test_serde_roundtrip(&value, name);
572    }
573
574    // Special handling for NaN values
575    let f32_nan = Value::F32(f32::NAN);
576    let f32_json = json5::to_string(&f32_nan).unwrap();
577    println!("F32_NaN JSON:\n{}", f32_json);
578    let deserialized_f32: Value = json5::from_str(&f32_json).unwrap();
579    if let Value::F32(val) = deserialized_f32 {
580      assert!(val.is_nan(), "Deserialized F32 should be NaN");
581    }
582
583    let f64_nan = Value::F64(f64::NAN);
584    let f64_json = json5::to_string(&f64_nan).unwrap();
585    println!("F64_NaN JSON:\n{}", f64_json);
586    let deserialized_f64: Value = json5::from_str(&f64_json).unwrap();
587    if let Value::F64(val) = deserialized_f64 {
588      assert!(val.is_nan(), "Deserialized F64 should be NaN");
589    }
590  }
591
592  #[test]
593  fn test_value_array_serialization() {
594    // Test array value variants
595    let arrays = vec![
596      ("ArrayBoolean_empty", Value::ArrayBoolean(vec![])),
597      ("ArrayBoolean", Value::ArrayBoolean(vec![true, false])),
598      ("ArrayU8", Value::ArrayU8(vec![0, 123, 255])),
599      ("ArrayI32", Value::ArrayI32(vec![i32::MIN, 0, i32::MAX])),
600      (
601        "ArrayF64",
602        Value::ArrayF64(vec![-1.0, 0.0, 1.0, f64::INFINITY]),
603      ),
604      (
605        "ArrayString",
606        Value::ArrayString(vec!["a".to_string(), "b".to_string()]),
607      ),
608    ];
609
610    for (name, value) in arrays {
611      test_serde_roundtrip(&value, name);
612    }
613  }
614
615  #[test]
616  fn test_structure_field_serialization() {
617    let field = StructureField {
618      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
619      value: Box::new(Value::String("test field".to_string())),
620    };
621
622    test_serde_roundtrip(&field, "StructureField");
623  }
624
625  #[test]
626  fn test_structure_serialization() {
627    // Test empty structure
628    let empty_structure = Structure {
629      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
630      fields: vec![],
631    };
632
633    test_serde_roundtrip(&empty_structure, "EmptyStructure");
634
635    // Test populated structure
636    let structure = Structure {
637      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
638      fields: vec![
639        StructureField {
640          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
641          value: Box::new(Value::String("field1".to_string())),
642        },
643        StructureField {
644          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
645          value: Box::new(Value::I32(42)),
646        },
647      ],
648    };
649
650    test_serde_roundtrip(&structure, "Structure");
651  }
652
653  #[test]
654  fn test_structure_without_id_serialization() {
655    let structure_without_id = StructureWithoutId {
656      fields: vec![StructureField {
657        id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
658        value: Box::new(Value::String("field1".to_string())),
659      }],
660    };
661
662    test_serde_roundtrip(&structure_without_id, "StructureWithoutId");
663  }
664
665  #[test]
666  fn test_enumeration_serialization() {
667    let enumeration = Enumeration {
668      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
669      variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
670      value: Box::new(Value::String("variant value".to_string())),
671    };
672
673    test_serde_roundtrip(&enumeration, "Enumeration");
674  }
675
676  #[test]
677  fn test_enumeration_without_id_serialization() {
678    let enumeration_without_id = EnumerationWithoutId {
679      variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
680      value: Box::new(Value::String("variant value".to_string())),
681    };
682
683    test_serde_roundtrip(&enumeration_without_id, "EnumerationWithoutId");
684  }
685
686  #[test]
687  fn test_complex_nested_values() {
688    // Complex nested structure with enumeration
689    let complex_value = Value::Structure(Structure {
690      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
691      fields: vec![
692        StructureField {
693          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
694          value: Box::new(Value::String("name".to_string())),
695        },
696        StructureField {
697          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
698          value: Box::new(Value::Enumeration(Enumeration {
699            id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440003").unwrap(),
700            variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440004").unwrap(),
701            value: Box::new(Value::Boolean(true)),
702          })),
703        },
704      ],
705    });
706
707    test_serde_roundtrip(&complex_value, "ComplexNestedValue");
708  }
709
710  #[test]
711  fn test_array_structure_and_enumeration() {
712    // Test array of structures
713    let array_structure = Value::ArrayStructure {
714      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
715      elements: vec![
716        StructureWithoutId {
717          fields: vec![StructureField {
718            id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
719            value: Box::new(Value::String("element1".to_string())),
720          }],
721        },
722        StructureWithoutId { fields: vec![] }, // Empty structure
723      ],
724    };
725
726    test_serde_roundtrip(&array_structure, "ArrayStructure");
727
728    // Test array of enumerations
729    let array_enumeration = Value::ArrayEnumeration {
730      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
731      elements: vec![
732        EnumerationWithoutId {
733          variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
734          value: Box::new(Value::String("variant1".to_string())),
735        },
736        EnumerationWithoutId {
737          variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
738          value: Box::new(Value::U32(42)),
739        },
740      ],
741    };
742
743    test_serde_roundtrip(&array_enumeration, "ArrayEnumeration");
744  }
745
746  #[test]
747  fn test_from_conversions_primitives() {
748    // Test From conversions for primitive types
749    assert_eq!(Value::from(()), Value::Unit);
750    assert_eq!(Value::from(true), Value::Boolean(true));
751    assert_eq!(Value::from(false), Value::Boolean(false));
752
753    assert_eq!(Value::from(42u8), Value::U8(42));
754    assert_eq!(Value::from(1234u16), Value::U16(1234));
755    assert_eq!(Value::from(123456u32), Value::U32(123456));
756    assert_eq!(Value::from(12345678901234u64), Value::U64(12345678901234));
757
758    assert_eq!(Value::from(-42i8), Value::I8(-42));
759    assert_eq!(Value::from(-1234i16), Value::I16(-1234));
760    assert_eq!(Value::from(-123456i32), Value::I32(-123456));
761    assert_eq!(Value::from(-12345678901234i64), Value::I64(-12345678901234));
762
763    assert_eq!(
764      Value::from(std::f32::consts::PI),
765      Value::F32(std::f32::consts::PI)
766    );
767    assert_eq!(
768      Value::from(std::f64::consts::PI),
769      Value::F64(std::f64::consts::PI)
770    );
771
772    assert_eq!(
773      Value::from("hello".to_string()),
774      Value::String("hello".to_string())
775    );
776    assert_eq!(Value::from("world"), Value::String("world".to_string()));
777
778    let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
779    assert_eq!(Value::from(uuid), Value::Uuid(uuid));
780  }
781
782  #[test]
783  fn test_from_conversions_arrays_vec() {
784    // Test Vec conversions
785    assert_eq!(
786      Value::from(vec![true, false, true]),
787      Value::ArrayBoolean(vec![true, false, true])
788    );
789    assert_eq!(
790      Value::from(vec![1u8, 2u8, 3u8]),
791      Value::ArrayU8(vec![1, 2, 3])
792    );
793    assert_eq!(
794      Value::from(vec![100u16, 200u16]),
795      Value::ArrayU16(vec![100, 200])
796    );
797    assert_eq!(
798      Value::from(vec![1000u32, 2000u32]),
799      Value::ArrayU32(vec![1000, 2000])
800    );
801    assert_eq!(
802      Value::from(vec![10000u64, 20000u64]),
803      Value::ArrayU64(vec![10000, 20000])
804    );
805
806    assert_eq!(Value::from(vec![-1i8, -2i8]), Value::ArrayI8(vec![-1, -2]));
807    assert_eq!(
808      Value::from(vec![-100i16, -200i16]),
809      Value::ArrayI16(vec![-100, -200])
810    );
811    assert_eq!(
812      Value::from(vec![-1000i32, -2000i32]),
813      Value::ArrayI32(vec![-1000, -2000])
814    );
815    assert_eq!(
816      Value::from(vec![-10000i64, -20000i64]),
817      Value::ArrayI64(vec![-10000, -20000])
818    );
819
820    assert_eq!(
821      Value::from(vec![1.5f32, 2.5f32]),
822      Value::ArrayF32(vec![1.5, 2.5])
823    );
824    assert_eq!(
825      Value::from(vec![1.5f64, 2.5f64]),
826      Value::ArrayF64(vec![1.5, 2.5])
827    );
828
829    assert_eq!(
830      Value::from(vec!["hello".to_string(), "world".to_string()]),
831      Value::ArrayString(vec!["hello".to_string(), "world".to_string()])
832    );
833  }
834
835  #[test]
836  fn test_from_conversions_arrays_slices() {
837    // Test slice conversions
838    let bool_slice = &[true, false, true][..];
839    assert_eq!(
840      Value::from(bool_slice),
841      Value::ArrayBoolean(vec![true, false, true])
842    );
843
844    let u32_slice = &[1u32, 2u32, 3u32][..];
845    assert_eq!(Value::from(u32_slice), Value::ArrayU32(vec![1, 2, 3]));
846
847    let string_slice = &["a".to_string(), "b".to_string()][..];
848    assert_eq!(
849      Value::from(string_slice),
850      Value::ArrayString(vec!["a".to_string(), "b".to_string()])
851    );
852  }
853
854  #[test]
855  fn test_from_conversions_hashset() {
856    use std::collections::HashSet;
857
858    // Test HashSet conversions (note: order is not guaranteed, so we check contents)
859    let bool_set: HashSet<bool> = [true, false].into_iter().collect();
860    if let Value::ArrayBoolean(vec) = Value::from(bool_set) {
861      assert_eq!(vec.len(), 2);
862      assert!(vec.contains(&true));
863      assert!(vec.contains(&false));
864    } else {
865      panic!("Expected ArrayBoolean");
866    }
867
868    let u32_set: HashSet<u32> = [1, 2, 3].into_iter().collect();
869    if let Value::ArrayU32(vec) = Value::from(u32_set) {
870      assert_eq!(vec.len(), 3);
871      assert!(vec.contains(&1));
872      assert!(vec.contains(&2));
873      assert!(vec.contains(&3));
874    } else {
875      panic!("Expected ArrayU32");
876    }
877
878    let string_set: HashSet<String> = ["a".to_string(), "b".to_string()].into_iter().collect();
879    if let Value::ArrayString(vec) = Value::from(string_set) {
880      assert_eq!(vec.len(), 2);
881      assert!(vec.contains(&"a".to_string()));
882      assert!(vec.contains(&"b".to_string()));
883    } else {
884      panic!("Expected ArrayString");
885    }
886
887    // Test empty HashSet
888    let empty_set: HashSet<u32> = HashSet::new();
889    assert_eq!(Value::from(empty_set), Value::ArrayU32(vec![]));
890  }
891
892  #[test]
893  fn test_from_conversions_empty_arrays() {
894    // Test empty array conversions
895    assert_eq!(Value::from(Vec::<bool>::new()), Value::ArrayBoolean(vec![]));
896    assert_eq!(Value::from(Vec::<u8>::new()), Value::ArrayU8(vec![]));
897    assert_eq!(Value::from(Vec::<u16>::new()), Value::ArrayU16(vec![]));
898    assert_eq!(Value::from(Vec::<u32>::new()), Value::ArrayU32(vec![]));
899    assert_eq!(Value::from(Vec::<u64>::new()), Value::ArrayU64(vec![]));
900    assert_eq!(Value::from(Vec::<i8>::new()), Value::ArrayI8(vec![]));
901    assert_eq!(Value::from(Vec::<i16>::new()), Value::ArrayI16(vec![]));
902    assert_eq!(Value::from(Vec::<i32>::new()), Value::ArrayI32(vec![]));
903    assert_eq!(Value::from(Vec::<i64>::new()), Value::ArrayI64(vec![]));
904    assert_eq!(Value::from(Vec::<f32>::new()), Value::ArrayF32(vec![]));
905    assert_eq!(Value::from(Vec::<f64>::new()), Value::ArrayF64(vec![]));
906    assert_eq!(
907      Value::from(Vec::<String>::new()),
908      Value::ArrayString(vec![])
909    );
910  }
911
912  #[test]
913  fn test_from_conversions_option() {
914    // Test Option<T> conversions for various primitive types
915
916    // Test Some variants
917    assert_eq!(
918      Value::from(Some(42u32)),
919      Value::Option(Some(Box::new(Value::U32(42))))
920    );
921    assert_eq!(
922      Value::from(Some(true)),
923      Value::Option(Some(Box::new(Value::Boolean(true))))
924    );
925    assert_eq!(
926      Value::from(Some("hello".to_string())),
927      Value::Option(Some(Box::new(Value::String("hello".to_string()))))
928    );
929    assert_eq!(
930      Value::from(Some(std::f64::consts::PI)),
931      Value::Option(Some(Box::new(Value::F64(std::f64::consts::PI))))
932    );
933
934    // Test None variants
935    assert_eq!(Value::from(None::<u32>), Value::Option(None));
936    assert_eq!(Value::from(None::<bool>), Value::Option(None));
937    assert_eq!(Value::from(None::<String>), Value::Option(None));
938    assert_eq!(Value::from(None::<f64>), Value::Option(None));
939
940    // Test nested Option with Value
941    let nested_value = Value::ArrayU32(vec![1, 2, 3]);
942    assert_eq!(
943      Value::from(Some(nested_value.clone())),
944      Value::Option(Some(Box::new(nested_value)))
945    );
946    assert_eq!(Value::from(None::<Value>), Value::Option(None));
947  }
948
949  #[test]
950  fn test_from_conversions_array_value() {
951    // Test Vec<Value> -> ArrayValue conversions
952
953    // Test empty Vec<Value>
954    assert_eq!(Value::from(Vec::<Value>::new()), Value::ArrayValue(vec![]));
955
956    // Test Vec<Value> with mixed types
957    let mixed_values = vec![
958      Value::U32(42),
959      Value::Boolean(true),
960      Value::String("test".to_string()),
961      Value::F64(std::f64::consts::PI),
962      Value::Unit,
963    ];
964    assert_eq!(
965      Value::from(mixed_values.clone()),
966      Value::ArrayValue(mixed_values.clone())
967    );
968
969    // Test slice conversion
970    let values_slice = &[
971      Value::I32(-10),
972      Value::Boolean(false),
973      Value::String("slice".to_string()),
974    ][..];
975    assert_eq!(
976      Value::from(values_slice),
977      Value::ArrayValue(vec![
978        Value::I32(-10),
979        Value::Boolean(false),
980        Value::String("slice".to_string()),
981      ])
982    );
983
984    // Test ArrayValue with nested arrays
985    let nested_array = vec![
986      Value::ArrayU32(vec![1, 2, 3]),
987      Value::ArrayString(vec!["a".to_string(), "b".to_string()]),
988      Value::ArrayBoolean(vec![true, false]),
989    ];
990    assert_eq!(
991      Value::from(nested_array.clone()),
992      Value::ArrayValue(nested_array)
993    );
994
995    // Test ArrayValue with Options
996    let option_array = vec![
997      Value::Option(Some(Box::new(Value::U32(1)))),
998      Value::Option(None),
999      Value::Option(Some(Box::new(Value::String("test".to_string())))),
1000    ];
1001    assert_eq!(
1002      Value::from(option_array.clone()),
1003      Value::ArrayValue(option_array)
1004    );
1005  }
1006
1007  #[test]
1008  fn test_type_uuid() {
1009    use crate::ty;
1010
1011    // Primitives → well-known UUIDs
1012    assert_eq!(Value::Unit.type_uuid(), *ty::UNIT_ID);
1013    assert_eq!(Value::Boolean(false).type_uuid(), *ty::BOOLEAN_ID);
1014    assert_eq!(Value::I8(0).type_uuid(), *ty::I8_ID);
1015    assert_eq!(Value::I16(0).type_uuid(), *ty::I16_ID);
1016    assert_eq!(Value::I32(0).type_uuid(), *ty::I32_ID);
1017    assert_eq!(Value::I64(0).type_uuid(), *ty::I64_ID);
1018    assert_eq!(Value::U8(0).type_uuid(), *ty::U8_ID);
1019    assert_eq!(Value::U16(0).type_uuid(), *ty::U16_ID);
1020    assert_eq!(Value::U32(0).type_uuid(), *ty::U32_ID);
1021    assert_eq!(Value::U64(0).type_uuid(), *ty::U64_ID);
1022    assert_eq!(Value::F32(0.0).type_uuid(), *ty::F32_ID);
1023    assert_eq!(Value::F64(0.0).type_uuid(), *ty::F64_ID);
1024    assert_eq!(Value::String("".into()).type_uuid(), *ty::STRING_ID);
1025
1026    // Typed compounds → embedded ID
1027    let test_id = uuid::Uuid::from_u128(0xdeadbeef);
1028    let variant_id = uuid::Uuid::from_u128(0xcafebabe);
1029
1030    assert_eq!(
1031      Value::Structure(Structure {
1032        id: test_id,
1033        fields: vec![],
1034      })
1035      .type_uuid(),
1036      test_id
1037    );
1038    assert_eq!(
1039      Value::Enumeration(Enumeration {
1040        id: test_id,
1041        variant_id,
1042        value: Box::new(Value::Unit),
1043      })
1044      .type_uuid(),
1045      test_id
1046    );
1047    assert_eq!(
1048      Value::ArrayStructure {
1049        id: test_id,
1050        elements: vec![],
1051      }
1052      .type_uuid(),
1053      test_id
1054    );
1055    assert_eq!(
1056      Value::ArrayEnumeration {
1057        id: test_id,
1058        elements: vec![],
1059      }
1060      .type_uuid(),
1061      test_id
1062    );
1063
1064    // Compound types → well-known UUIDs
1065    assert_eq!(Value::Option(None).type_uuid(), *ty::OPTION_ID);
1066    assert_eq!(
1067      Value::Option(Some(Box::new(Value::Unit))).type_uuid(),
1068      *ty::OPTION_ID
1069    );
1070    assert_eq!(
1071      Value::ArrayBoolean(vec![]).type_uuid(),
1072      *ty::ARRAY_BOOLEAN_ID
1073    );
1074    assert_eq!(Value::ArrayU8(vec![]).type_uuid(), *ty::ARRAY_U8_ID);
1075    assert_eq!(Value::ArrayU16(vec![]).type_uuid(), *ty::ARRAY_U16_ID);
1076    assert_eq!(Value::ArrayU32(vec![]).type_uuid(), *ty::ARRAY_U32_ID);
1077    assert_eq!(Value::ArrayU64(vec![]).type_uuid(), *ty::ARRAY_U64_ID);
1078    assert_eq!(Value::ArrayI8(vec![]).type_uuid(), *ty::ARRAY_I8_ID);
1079    assert_eq!(Value::ArrayI16(vec![]).type_uuid(), *ty::ARRAY_I16_ID);
1080    assert_eq!(Value::ArrayI32(vec![]).type_uuid(), *ty::ARRAY_I32_ID);
1081    assert_eq!(Value::ArrayI64(vec![]).type_uuid(), *ty::ARRAY_I64_ID);
1082    assert_eq!(Value::ArrayF32(vec![]).type_uuid(), *ty::ARRAY_F32_ID);
1083    assert_eq!(Value::ArrayF64(vec![]).type_uuid(), *ty::ARRAY_F64_ID);
1084    assert_eq!(Value::ArrayString(vec![]).type_uuid(), *ty::ARRAY_STRING_ID);
1085    assert_eq!(Value::ArrayValue(vec![]).type_uuid(), *ty::ARRAY_VALUE_ID);
1086    assert_eq!(
1087      Value::KeyValue(KeyValue::default()).type_uuid(),
1088      *ty::KEY_VALUE_ID
1089    );
1090    assert_eq!(Value::Uuid(uuid::Uuid::nil()).type_uuid(), *ty::UUID_ID);
1091
1092    // All well-known IDs are distinct
1093    let all_wellknown: Vec<uuid::Uuid> = ty::WELL_KNOWN_IDS.iter().copied().collect();
1094    assert_eq!(all_wellknown.len(), 29); // 13 primitives + 16 compounds
1095  }
1096}