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  // Value ⇄ YAML: the coverage `arora-buffers::serde_raw_id` used to duplicate
498  // now lives here, on the canonical `Value` (which is broader — it has option,
499  // map, uuid). A nested value exercises struct + array + string together.
500  #[test]
501  fn value_round_trips_through_yaml() {
502    let value = Value::Structure(Structure {
503      id: Uuid::from_u128(0x10),
504      fields: vec![
505        StructureField {
506          id: Uuid::from_u128(0x01),
507          value: Box::new(Value::ArrayF64(vec![1.0, -2.0, 3.5])),
508        },
509        StructureField {
510          id: Uuid::from_u128(0x02),
511          value: Box::new(Value::String("hi".to_string())),
512        },
513      ],
514    });
515    let yaml = serde_yaml::to_string(&value).unwrap();
516    let back: Value = serde_yaml::from_str(&yaml).unwrap();
517    assert_eq!(value, back, "Value did not round-trip through YAML");
518  }
519
520  #[test]
521  fn test_type_serialization() {
522    // Test all variants of Type enum
523    for typ in [
524      Type::Unit,
525      Type::Boolean,
526      Type::U8,
527      Type::U16,
528      Type::U32,
529      Type::U64,
530      Type::I8,
531      Type::I16,
532      Type::I32,
533      Type::I64,
534      Type::F32,
535      Type::F64,
536      Type::String,
537      Type::Option,
538      Type::Structure,
539      Type::Enumeration,
540      Type::ArrayBoolean,
541      Type::ArrayU8,
542      Type::ArrayU16,
543      Type::ArrayU32,
544      Type::ArrayU64,
545      Type::ArrayI8,
546      Type::ArrayI16,
547      Type::ArrayI32,
548      Type::ArrayI64,
549      Type::ArrayF32,
550      Type::ArrayF64,
551      Type::ArrayString,
552      Type::ArrayValue,
553      Type::ArrayStructure,
554      Type::ArrayEnumeration,
555      Type::KeyValue,
556      Type::Uuid,
557    ] {
558      test_serde_roundtrip(&typ, &format!("Type::{:?}", typ));
559    }
560  }
561
562  #[test]
563  fn test_value_primitive_serialization() {
564    // Test primitive value variants
565    let primitives = vec![
566      ("Unit", Value::Unit),
567      ("Boolean_true", Value::Boolean(true)),
568      ("Boolean_false", Value::Boolean(false)),
569      ("U8_min", Value::U8(0)),
570      ("U8_max", Value::U8(u8::MAX)),
571      ("U16_max", Value::U16(u16::MAX)),
572      ("U32_max", Value::U32(u32::MAX)),
573      ("U64_max", Value::U64(u64::MAX)),
574      ("I8_min", Value::I8(i8::MIN)),
575      ("I8_max", Value::I8(i8::MAX)),
576      ("I16_min", Value::I16(i16::MIN)),
577      ("I32_min", Value::I32(i32::MIN)),
578      ("I64_min", Value::I64(i64::MIN)),
579      ("F32_zero", Value::F32(0.0)),
580      ("F32_inf", Value::F32(f32::INFINITY)),
581      ("F32_neg_inf", Value::F32(f32::NEG_INFINITY)),
582      ("F64_zero", Value::F64(0.0)),
583      ("F64_inf", Value::F64(f64::INFINITY)),
584      ("F64_neg_inf", Value::F64(f64::NEG_INFINITY)),
585      ("String_empty", Value::String("".to_string())),
586      ("String_hello", Value::String("Hello, world!".to_string())),
587      (
588        "String_special",
589        Value::String("Special chars: \n\t\r\"\\".to_string()),
590      ),
591    ];
592
593    for (name, value) in primitives {
594      test_serde_roundtrip(&value, name);
595    }
596
597    // Special handling for NaN values
598    let f32_nan = Value::F32(f32::NAN);
599    let f32_json = json5::to_string(&f32_nan).unwrap();
600    println!("F32_NaN JSON:\n{}", f32_json);
601    let deserialized_f32: Value = json5::from_str(&f32_json).unwrap();
602    if let Value::F32(val) = deserialized_f32 {
603      assert!(val.is_nan(), "Deserialized F32 should be NaN");
604    }
605
606    let f64_nan = Value::F64(f64::NAN);
607    let f64_json = json5::to_string(&f64_nan).unwrap();
608    println!("F64_NaN JSON:\n{}", f64_json);
609    let deserialized_f64: Value = json5::from_str(&f64_json).unwrap();
610    if let Value::F64(val) = deserialized_f64 {
611      assert!(val.is_nan(), "Deserialized F64 should be NaN");
612    }
613  }
614
615  #[test]
616  fn test_value_array_serialization() {
617    // Test array value variants
618    let arrays = vec![
619      ("ArrayBoolean_empty", Value::ArrayBoolean(vec![])),
620      ("ArrayBoolean", Value::ArrayBoolean(vec![true, false])),
621      ("ArrayU8", Value::ArrayU8(vec![0, 123, 255])),
622      ("ArrayI32", Value::ArrayI32(vec![i32::MIN, 0, i32::MAX])),
623      (
624        "ArrayF64",
625        Value::ArrayF64(vec![-1.0, 0.0, 1.0, f64::INFINITY]),
626      ),
627      (
628        "ArrayString",
629        Value::ArrayString(vec!["a".to_string(), "b".to_string()]),
630      ),
631    ];
632
633    for (name, value) in arrays {
634      test_serde_roundtrip(&value, name);
635    }
636  }
637
638  #[test]
639  fn test_structure_field_serialization() {
640    let field = StructureField {
641      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
642      value: Box::new(Value::String("test field".to_string())),
643    };
644
645    test_serde_roundtrip(&field, "StructureField");
646  }
647
648  #[test]
649  fn test_structure_serialization() {
650    // Test empty structure
651    let empty_structure = Structure {
652      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
653      fields: vec![],
654    };
655
656    test_serde_roundtrip(&empty_structure, "EmptyStructure");
657
658    // Test populated structure
659    let structure = Structure {
660      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
661      fields: vec![
662        StructureField {
663          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
664          value: Box::new(Value::String("field1".to_string())),
665        },
666        StructureField {
667          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
668          value: Box::new(Value::I32(42)),
669        },
670      ],
671    };
672
673    test_serde_roundtrip(&structure, "Structure");
674  }
675
676  #[test]
677  fn test_structure_without_id_serialization() {
678    let structure_without_id = StructureWithoutId {
679      fields: vec![StructureField {
680        id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
681        value: Box::new(Value::String("field1".to_string())),
682      }],
683    };
684
685    test_serde_roundtrip(&structure_without_id, "StructureWithoutId");
686  }
687
688  #[test]
689  fn test_enumeration_serialization() {
690    let enumeration = Enumeration {
691      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
692      variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
693      value: Box::new(Value::String("variant value".to_string())),
694    };
695
696    test_serde_roundtrip(&enumeration, "Enumeration");
697  }
698
699  #[test]
700  fn test_enumeration_without_id_serialization() {
701    let enumeration_without_id = EnumerationWithoutId {
702      variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
703      value: Box::new(Value::String("variant value".to_string())),
704    };
705
706    test_serde_roundtrip(&enumeration_without_id, "EnumerationWithoutId");
707  }
708
709  #[test]
710  fn test_complex_nested_values() {
711    // Complex nested structure with enumeration
712    let complex_value = Value::Structure(Structure {
713      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
714      fields: vec![
715        StructureField {
716          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
717          value: Box::new(Value::String("name".to_string())),
718        },
719        StructureField {
720          id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
721          value: Box::new(Value::Enumeration(Enumeration {
722            id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440003").unwrap(),
723            variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440004").unwrap(),
724            value: Box::new(Value::Boolean(true)),
725          })),
726        },
727      ],
728    });
729
730    test_serde_roundtrip(&complex_value, "ComplexNestedValue");
731  }
732
733  #[test]
734  fn test_array_structure_and_enumeration() {
735    // Test array of structures
736    let array_structure = Value::ArrayStructure {
737      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
738      elements: vec![
739        StructureWithoutId {
740          fields: vec![StructureField {
741            id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
742            value: Box::new(Value::String("element1".to_string())),
743          }],
744        },
745        StructureWithoutId { fields: vec![] }, // Empty structure
746      ],
747    };
748
749    test_serde_roundtrip(&array_structure, "ArrayStructure");
750
751    // Test array of enumerations
752    let array_enumeration = Value::ArrayEnumeration {
753      id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(),
754      elements: vec![
755        EnumerationWithoutId {
756          variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440001").unwrap(),
757          value: Box::new(Value::String("variant1".to_string())),
758        },
759        EnumerationWithoutId {
760          variant_id: Uuid::parse_str("550e8400-e29b-41d4-a716-446655440002").unwrap(),
761          value: Box::new(Value::U32(42)),
762        },
763      ],
764    };
765
766    test_serde_roundtrip(&array_enumeration, "ArrayEnumeration");
767  }
768
769  #[test]
770  fn test_from_conversions_primitives() {
771    // Test From conversions for primitive types
772    assert_eq!(Value::from(()), Value::Unit);
773    assert_eq!(Value::from(true), Value::Boolean(true));
774    assert_eq!(Value::from(false), Value::Boolean(false));
775
776    assert_eq!(Value::from(42u8), Value::U8(42));
777    assert_eq!(Value::from(1234u16), Value::U16(1234));
778    assert_eq!(Value::from(123456u32), Value::U32(123456));
779    assert_eq!(Value::from(12345678901234u64), Value::U64(12345678901234));
780
781    assert_eq!(Value::from(-42i8), Value::I8(-42));
782    assert_eq!(Value::from(-1234i16), Value::I16(-1234));
783    assert_eq!(Value::from(-123456i32), Value::I32(-123456));
784    assert_eq!(Value::from(-12345678901234i64), Value::I64(-12345678901234));
785
786    assert_eq!(
787      Value::from(std::f32::consts::PI),
788      Value::F32(std::f32::consts::PI)
789    );
790    assert_eq!(
791      Value::from(std::f64::consts::PI),
792      Value::F64(std::f64::consts::PI)
793    );
794
795    assert_eq!(
796      Value::from("hello".to_string()),
797      Value::String("hello".to_string())
798    );
799    assert_eq!(Value::from("world"), Value::String("world".to_string()));
800
801    let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
802    assert_eq!(Value::from(uuid), Value::Uuid(uuid));
803  }
804
805  #[test]
806  fn test_from_conversions_arrays_vec() {
807    // Test Vec conversions
808    assert_eq!(
809      Value::from(vec![true, false, true]),
810      Value::ArrayBoolean(vec![true, false, true])
811    );
812    assert_eq!(
813      Value::from(vec![1u8, 2u8, 3u8]),
814      Value::ArrayU8(vec![1, 2, 3])
815    );
816    assert_eq!(
817      Value::from(vec![100u16, 200u16]),
818      Value::ArrayU16(vec![100, 200])
819    );
820    assert_eq!(
821      Value::from(vec![1000u32, 2000u32]),
822      Value::ArrayU32(vec![1000, 2000])
823    );
824    assert_eq!(
825      Value::from(vec![10000u64, 20000u64]),
826      Value::ArrayU64(vec![10000, 20000])
827    );
828
829    assert_eq!(Value::from(vec![-1i8, -2i8]), Value::ArrayI8(vec![-1, -2]));
830    assert_eq!(
831      Value::from(vec![-100i16, -200i16]),
832      Value::ArrayI16(vec![-100, -200])
833    );
834    assert_eq!(
835      Value::from(vec![-1000i32, -2000i32]),
836      Value::ArrayI32(vec![-1000, -2000])
837    );
838    assert_eq!(
839      Value::from(vec![-10000i64, -20000i64]),
840      Value::ArrayI64(vec![-10000, -20000])
841    );
842
843    assert_eq!(
844      Value::from(vec![1.5f32, 2.5f32]),
845      Value::ArrayF32(vec![1.5, 2.5])
846    );
847    assert_eq!(
848      Value::from(vec![1.5f64, 2.5f64]),
849      Value::ArrayF64(vec![1.5, 2.5])
850    );
851
852    assert_eq!(
853      Value::from(vec!["hello".to_string(), "world".to_string()]),
854      Value::ArrayString(vec!["hello".to_string(), "world".to_string()])
855    );
856  }
857
858  #[test]
859  fn test_from_conversions_arrays_slices() {
860    // Test slice conversions
861    let bool_slice = &[true, false, true][..];
862    assert_eq!(
863      Value::from(bool_slice),
864      Value::ArrayBoolean(vec![true, false, true])
865    );
866
867    let u32_slice = &[1u32, 2u32, 3u32][..];
868    assert_eq!(Value::from(u32_slice), Value::ArrayU32(vec![1, 2, 3]));
869
870    let string_slice = &["a".to_string(), "b".to_string()][..];
871    assert_eq!(
872      Value::from(string_slice),
873      Value::ArrayString(vec!["a".to_string(), "b".to_string()])
874    );
875  }
876
877  #[test]
878  fn test_from_conversions_hashset() {
879    use std::collections::HashSet;
880
881    // Test HashSet conversions (note: order is not guaranteed, so we check contents)
882    let bool_set: HashSet<bool> = [true, false].into_iter().collect();
883    if let Value::ArrayBoolean(vec) = Value::from(bool_set) {
884      assert_eq!(vec.len(), 2);
885      assert!(vec.contains(&true));
886      assert!(vec.contains(&false));
887    } else {
888      panic!("Expected ArrayBoolean");
889    }
890
891    let u32_set: HashSet<u32> = [1, 2, 3].into_iter().collect();
892    if let Value::ArrayU32(vec) = Value::from(u32_set) {
893      assert_eq!(vec.len(), 3);
894      assert!(vec.contains(&1));
895      assert!(vec.contains(&2));
896      assert!(vec.contains(&3));
897    } else {
898      panic!("Expected ArrayU32");
899    }
900
901    let string_set: HashSet<String> = ["a".to_string(), "b".to_string()].into_iter().collect();
902    if let Value::ArrayString(vec) = Value::from(string_set) {
903      assert_eq!(vec.len(), 2);
904      assert!(vec.contains(&"a".to_string()));
905      assert!(vec.contains(&"b".to_string()));
906    } else {
907      panic!("Expected ArrayString");
908    }
909
910    // Test empty HashSet
911    let empty_set: HashSet<u32> = HashSet::new();
912    assert_eq!(Value::from(empty_set), Value::ArrayU32(vec![]));
913  }
914
915  #[test]
916  fn test_from_conversions_empty_arrays() {
917    // Test empty array conversions
918    assert_eq!(Value::from(Vec::<bool>::new()), Value::ArrayBoolean(vec![]));
919    assert_eq!(Value::from(Vec::<u8>::new()), Value::ArrayU8(vec![]));
920    assert_eq!(Value::from(Vec::<u16>::new()), Value::ArrayU16(vec![]));
921    assert_eq!(Value::from(Vec::<u32>::new()), Value::ArrayU32(vec![]));
922    assert_eq!(Value::from(Vec::<u64>::new()), Value::ArrayU64(vec![]));
923    assert_eq!(Value::from(Vec::<i8>::new()), Value::ArrayI8(vec![]));
924    assert_eq!(Value::from(Vec::<i16>::new()), Value::ArrayI16(vec![]));
925    assert_eq!(Value::from(Vec::<i32>::new()), Value::ArrayI32(vec![]));
926    assert_eq!(Value::from(Vec::<i64>::new()), Value::ArrayI64(vec![]));
927    assert_eq!(Value::from(Vec::<f32>::new()), Value::ArrayF32(vec![]));
928    assert_eq!(Value::from(Vec::<f64>::new()), Value::ArrayF64(vec![]));
929    assert_eq!(
930      Value::from(Vec::<String>::new()),
931      Value::ArrayString(vec![])
932    );
933  }
934
935  #[test]
936  fn test_from_conversions_option() {
937    // Test Option<T> conversions for various primitive types
938
939    // Test Some variants
940    assert_eq!(
941      Value::from(Some(42u32)),
942      Value::Option(Some(Box::new(Value::U32(42))))
943    );
944    assert_eq!(
945      Value::from(Some(true)),
946      Value::Option(Some(Box::new(Value::Boolean(true))))
947    );
948    assert_eq!(
949      Value::from(Some("hello".to_string())),
950      Value::Option(Some(Box::new(Value::String("hello".to_string()))))
951    );
952    assert_eq!(
953      Value::from(Some(std::f64::consts::PI)),
954      Value::Option(Some(Box::new(Value::F64(std::f64::consts::PI))))
955    );
956
957    // Test None variants
958    assert_eq!(Value::from(None::<u32>), Value::Option(None));
959    assert_eq!(Value::from(None::<bool>), Value::Option(None));
960    assert_eq!(Value::from(None::<String>), Value::Option(None));
961    assert_eq!(Value::from(None::<f64>), Value::Option(None));
962
963    // Test nested Option with Value
964    let nested_value = Value::ArrayU32(vec![1, 2, 3]);
965    assert_eq!(
966      Value::from(Some(nested_value.clone())),
967      Value::Option(Some(Box::new(nested_value)))
968    );
969    assert_eq!(Value::from(None::<Value>), Value::Option(None));
970  }
971
972  #[test]
973  fn test_from_conversions_array_value() {
974    // Test Vec<Value> -> ArrayValue conversions
975
976    // Test empty Vec<Value>
977    assert_eq!(Value::from(Vec::<Value>::new()), Value::ArrayValue(vec![]));
978
979    // Test Vec<Value> with mixed types
980    let mixed_values = vec![
981      Value::U32(42),
982      Value::Boolean(true),
983      Value::String("test".to_string()),
984      Value::F64(std::f64::consts::PI),
985      Value::Unit,
986    ];
987    assert_eq!(
988      Value::from(mixed_values.clone()),
989      Value::ArrayValue(mixed_values.clone())
990    );
991
992    // Test slice conversion
993    let values_slice = &[
994      Value::I32(-10),
995      Value::Boolean(false),
996      Value::String("slice".to_string()),
997    ][..];
998    assert_eq!(
999      Value::from(values_slice),
1000      Value::ArrayValue(vec![
1001        Value::I32(-10),
1002        Value::Boolean(false),
1003        Value::String("slice".to_string()),
1004      ])
1005    );
1006
1007    // Test ArrayValue with nested arrays
1008    let nested_array = vec![
1009      Value::ArrayU32(vec![1, 2, 3]),
1010      Value::ArrayString(vec!["a".to_string(), "b".to_string()]),
1011      Value::ArrayBoolean(vec![true, false]),
1012    ];
1013    assert_eq!(
1014      Value::from(nested_array.clone()),
1015      Value::ArrayValue(nested_array)
1016    );
1017
1018    // Test ArrayValue with Options
1019    let option_array = vec![
1020      Value::Option(Some(Box::new(Value::U32(1)))),
1021      Value::Option(None),
1022      Value::Option(Some(Box::new(Value::String("test".to_string())))),
1023    ];
1024    assert_eq!(
1025      Value::from(option_array.clone()),
1026      Value::ArrayValue(option_array)
1027    );
1028  }
1029
1030  #[test]
1031  fn test_type_uuid() {
1032    use crate::ty;
1033
1034    // Primitives → well-known UUIDs
1035    assert_eq!(Value::Unit.type_uuid(), *ty::UNIT_ID);
1036    assert_eq!(Value::Boolean(false).type_uuid(), *ty::BOOLEAN_ID);
1037    assert_eq!(Value::I8(0).type_uuid(), *ty::I8_ID);
1038    assert_eq!(Value::I16(0).type_uuid(), *ty::I16_ID);
1039    assert_eq!(Value::I32(0).type_uuid(), *ty::I32_ID);
1040    assert_eq!(Value::I64(0).type_uuid(), *ty::I64_ID);
1041    assert_eq!(Value::U8(0).type_uuid(), *ty::U8_ID);
1042    assert_eq!(Value::U16(0).type_uuid(), *ty::U16_ID);
1043    assert_eq!(Value::U32(0).type_uuid(), *ty::U32_ID);
1044    assert_eq!(Value::U64(0).type_uuid(), *ty::U64_ID);
1045    assert_eq!(Value::F32(0.0).type_uuid(), *ty::F32_ID);
1046    assert_eq!(Value::F64(0.0).type_uuid(), *ty::F64_ID);
1047    assert_eq!(Value::String("".into()).type_uuid(), *ty::STRING_ID);
1048
1049    // Typed compounds → embedded ID
1050    let test_id = uuid::Uuid::from_u128(0xdeadbeef);
1051    let variant_id = uuid::Uuid::from_u128(0xcafebabe);
1052
1053    assert_eq!(
1054      Value::Structure(Structure {
1055        id: test_id,
1056        fields: vec![],
1057      })
1058      .type_uuid(),
1059      test_id
1060    );
1061    assert_eq!(
1062      Value::Enumeration(Enumeration {
1063        id: test_id,
1064        variant_id,
1065        value: Box::new(Value::Unit),
1066      })
1067      .type_uuid(),
1068      test_id
1069    );
1070    assert_eq!(
1071      Value::ArrayStructure {
1072        id: test_id,
1073        elements: vec![],
1074      }
1075      .type_uuid(),
1076      test_id
1077    );
1078    assert_eq!(
1079      Value::ArrayEnumeration {
1080        id: test_id,
1081        elements: vec![],
1082      }
1083      .type_uuid(),
1084      test_id
1085    );
1086
1087    // Compound types → well-known UUIDs
1088    assert_eq!(Value::Option(None).type_uuid(), *ty::OPTION_ID);
1089    assert_eq!(
1090      Value::Option(Some(Box::new(Value::Unit))).type_uuid(),
1091      *ty::OPTION_ID
1092    );
1093    assert_eq!(
1094      Value::ArrayBoolean(vec![]).type_uuid(),
1095      *ty::ARRAY_BOOLEAN_ID
1096    );
1097    assert_eq!(Value::ArrayU8(vec![]).type_uuid(), *ty::ARRAY_U8_ID);
1098    assert_eq!(Value::ArrayU16(vec![]).type_uuid(), *ty::ARRAY_U16_ID);
1099    assert_eq!(Value::ArrayU32(vec![]).type_uuid(), *ty::ARRAY_U32_ID);
1100    assert_eq!(Value::ArrayU64(vec![]).type_uuid(), *ty::ARRAY_U64_ID);
1101    assert_eq!(Value::ArrayI8(vec![]).type_uuid(), *ty::ARRAY_I8_ID);
1102    assert_eq!(Value::ArrayI16(vec![]).type_uuid(), *ty::ARRAY_I16_ID);
1103    assert_eq!(Value::ArrayI32(vec![]).type_uuid(), *ty::ARRAY_I32_ID);
1104    assert_eq!(Value::ArrayI64(vec![]).type_uuid(), *ty::ARRAY_I64_ID);
1105    assert_eq!(Value::ArrayF32(vec![]).type_uuid(), *ty::ARRAY_F32_ID);
1106    assert_eq!(Value::ArrayF64(vec![]).type_uuid(), *ty::ARRAY_F64_ID);
1107    assert_eq!(Value::ArrayString(vec![]).type_uuid(), *ty::ARRAY_STRING_ID);
1108    assert_eq!(Value::ArrayValue(vec![]).type_uuid(), *ty::ARRAY_VALUE_ID);
1109    assert_eq!(
1110      Value::KeyValue(KeyValue::default()).type_uuid(),
1111      *ty::KEY_VALUE_ID
1112    );
1113    assert_eq!(Value::Uuid(uuid::Uuid::nil()).type_uuid(), *ty::UUID_ID);
1114
1115    // All well-known IDs are distinct
1116    let all_wellknown: Vec<uuid::Uuid> = ty::WELL_KNOWN_IDS.iter().copied().collect();
1117    assert_eq!(all_wellknown.len(), 29); // 13 primitives + 16 compounds
1118  }
1119}