1use alloc::boxed::Box;
16use alloc::collections::BTreeMap;
17use alloc::string::String;
18use alloc::vec::Vec;
19
20use super::descriptor::{MemberId, TypeKind};
21use super::error::DynamicError;
22use super::type_::DynamicType;
23
24#[derive(Debug, Clone)]
32pub enum DynamicValue {
33 Bool(bool),
35 Byte(u8),
37 Int8(i8),
39 UInt8(u8),
41 Int16(i16),
43 UInt16(u16),
45 Int32(i32),
47 UInt32(u32),
49 Int64(i64),
51 UInt64(u64),
53 Float32(f32),
55 Float64(f64),
57 Char8(u8),
59 Char16(u16),
61 String(String),
63 WString(Vec<u16>),
65 Complex(Box<DynamicData>),
67 Sequence(Vec<DynamicData>),
70 None,
72}
73
74impl PartialEq for DynamicValue {
75 fn eq(&self, other: &Self) -> bool {
76 match (self, other) {
77 (Self::Bool(a), Self::Bool(b)) => a == b,
78 (Self::Byte(a), Self::Byte(b)) => a == b,
79 (Self::Int8(a), Self::Int8(b)) => a == b,
80 (Self::UInt8(a), Self::UInt8(b)) => a == b,
81 (Self::Int16(a), Self::Int16(b)) => a == b,
82 (Self::UInt16(a), Self::UInt16(b)) => a == b,
83 (Self::Int32(a), Self::Int32(b)) => a == b,
84 (Self::UInt32(a), Self::UInt32(b)) => a == b,
85 (Self::Int64(a), Self::Int64(b)) => a == b,
86 (Self::UInt64(a), Self::UInt64(b)) => a == b,
87 (Self::Float32(a), Self::Float32(b)) => a.to_bits() == b.to_bits(),
88 (Self::Float64(a), Self::Float64(b)) => a.to_bits() == b.to_bits(),
89 (Self::Char8(a), Self::Char8(b)) => a == b,
90 (Self::Char16(a), Self::Char16(b)) => a == b,
91 (Self::String(a), Self::String(b)) => a == b,
92 (Self::WString(a), Self::WString(b)) => a == b,
93 (Self::Complex(a), Self::Complex(b)) => a.equals(b),
94 (Self::Sequence(a), Self::Sequence(b)) => {
95 a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.equals(y))
96 }
97 (Self::None, Self::None) => true,
98 _ => false,
99 }
100 }
101}
102
103impl DynamicValue {
104 fn kind_str(&self) -> &'static str {
105 match self {
106 Self::Bool(_) => "bool",
107 Self::Byte(_) => "byte",
108 Self::Int8(_) => "int8",
109 Self::UInt8(_) => "uint8",
110 Self::Int16(_) => "int16",
111 Self::UInt16(_) => "uint16",
112 Self::Int32(_) => "int32",
113 Self::UInt32(_) => "uint32",
114 Self::Int64(_) => "int64",
115 Self::UInt64(_) => "uint64",
116 Self::Float32(_) => "float32",
117 Self::Float64(_) => "float64",
118 Self::Char8(_) => "char8",
119 Self::Char16(_) => "char16",
120 Self::String(_) => "string",
121 Self::WString(_) => "wstring",
122 Self::Complex(_) => "complex",
123 Self::Sequence(_) => "sequence",
124 Self::None => "none",
125 }
126 }
127}
128
129#[derive(Debug)]
138pub struct DataLoan {
139 member_id: MemberId,
140 handle: u32,
142}
143
144impl DataLoan {
145 #[must_use]
147 pub fn member_id(&self) -> MemberId {
148 self.member_id
149 }
150}
151
152#[derive(Debug, Clone)]
163pub struct DynamicData {
164 type_: DynamicType,
165 values: BTreeMap<MemberId, DynamicValue>,
166 active_loans: Vec<u32>,
168 next_loan_handle: u32,
170}
171
172impl DynamicData {
173 pub(super) fn new(type_: DynamicType) -> Self {
174 Self {
175 type_,
176 values: BTreeMap::new(),
177 active_loans: Vec::new(),
178 next_loan_handle: 1,
179 }
180 }
181
182 #[must_use]
184 pub fn dynamic_type(&self) -> &DynamicType {
185 &self.type_
186 }
187
188 #[must_use]
190 pub fn equals(&self, other: &Self) -> bool {
191 self.type_.equals(&other.type_) && self.values == other.values
192 }
193
194 #[must_use]
196 pub fn item_count(&self) -> u32 {
197 u32::try_from(self.values.len()).unwrap_or(u32::MAX)
198 }
199
200 fn validate_member(&self, member_id: MemberId) -> Result<(), DynamicError> {
202 if self.type_.member_by_id(member_id).is_none() {
203 return Err(DynamicError::bad_parameter(alloc::format!(
204 "no member with id {member_id} in type {}",
205 self.type_.name()
206 )));
207 }
208 Ok(())
209 }
210
211 fn set(&mut self, member_id: MemberId, value: DynamicValue) -> Result<(), DynamicError> {
219 self.validate_member(member_id)?;
220 let member = self.type_.member_by_id(member_id).cloned();
221 if let Some(ref m) = member {
222 check_value_kind_matches_type(&value, m.dynamic_type().kind())?;
223 }
224 if let Some(m) = member {
227 match crate::dynamic::try_construct::apply_try_construct(&m, value) {
228 crate::dynamic::TryConstructOutcome::Accept(v)
229 | crate::dynamic::TryConstructOutcome::UseDefault(v)
230 | crate::dynamic::TryConstructOutcome::Trim(v) => {
231 self.values.insert(member_id, v);
232 }
233 crate::dynamic::TryConstructOutcome::Discard => {
234 self.values.remove(&member_id);
236 }
237 }
238 } else {
239 self.values.insert(member_id, value);
240 }
241 Ok(())
242 }
243
244 fn get(&self, member_id: MemberId) -> Result<&DynamicValue, DynamicError> {
246 self.values.get(&member_id).ok_or_else(|| {
247 DynamicError::PreconditionNotMet(alloc::format!(
248 "member {member_id} not set in {}",
249 self.type_.name()
250 ))
251 })
252 }
253}
254
255macro_rules! primitive_accessor {
260 ($get_name:ident, $set_name:ident, $rust_ty:ty, $variant:ident) => {
261 impl DynamicData {
262 #[doc = concat!("Spec §7.5.6.3 `get_", stringify!($variant), "_value`.")]
263 pub fn $get_name(&self, member_id: MemberId) -> Result<$rust_ty, DynamicError> {
268 let v = self.get(member_id)?;
269 if let DynamicValue::$variant(x) = v {
270 Ok(x.clone())
271 } else {
272 Err(DynamicError::bad_parameter(alloc::format!(
273 "type mismatch: expected {} got {}",
274 stringify!($variant),
275 v.kind_str()
276 )))
277 }
278 }
279
280 #[doc = concat!("Spec §7.5.6.3 `set_", stringify!($variant), "_value`.")]
281 pub fn $set_name(
285 &mut self,
286 member_id: MemberId,
287 value: $rust_ty,
288 ) -> Result<(), DynamicError> {
289 self.set(member_id, DynamicValue::$variant(value))
290 }
291 }
292 };
293}
294
295primitive_accessor!(get_boolean_value, set_boolean_value, bool, Bool);
296primitive_accessor!(get_byte_value, set_byte_value, u8, Byte);
297primitive_accessor!(get_int8_value, set_int8_value, i8, Int8);
298primitive_accessor!(get_uint8_value, set_uint8_value, u8, UInt8);
299primitive_accessor!(get_int16_value, set_int16_value, i16, Int16);
300primitive_accessor!(get_uint16_value, set_uint16_value, u16, UInt16);
301primitive_accessor!(get_int32_value, set_int32_value, i32, Int32);
302primitive_accessor!(get_uint32_value, set_uint32_value, u32, UInt32);
303primitive_accessor!(get_int64_value, set_int64_value, i64, Int64);
304primitive_accessor!(get_uint64_value, set_uint64_value, u64, UInt64);
305primitive_accessor!(get_float32_value, set_float32_value, f32, Float32);
306primitive_accessor!(get_float64_value, set_float64_value, f64, Float64);
307primitive_accessor!(get_char8_value, set_char8_value, u8, Char8);
308primitive_accessor!(get_char16_value, set_char16_value, u16, Char16);
309
310impl DynamicData {
312 pub fn get_string_value(&self, member_id: MemberId) -> Result<String, DynamicError> {
317 let v = self.get(member_id)?;
318 if let DynamicValue::String(s) = v {
319 Ok(s.clone())
320 } else {
321 Err(DynamicError::bad_parameter(alloc::format!(
322 "type mismatch: expected string got {}",
323 v.kind_str()
324 )))
325 }
326 }
327
328 pub fn set_string_value(
333 &mut self,
334 member_id: MemberId,
335 value: impl Into<String>,
336 ) -> Result<(), DynamicError> {
337 self.set(member_id, DynamicValue::String(value.into()))
338 }
339
340 pub fn get_wstring_value(&self, member_id: MemberId) -> Result<Vec<u16>, DynamicError> {
345 let v = self.get(member_id)?;
346 if let DynamicValue::WString(s) = v {
347 Ok(s.clone())
348 } else {
349 Err(DynamicError::bad_parameter(alloc::format!(
350 "type mismatch: expected wstring got {}",
351 v.kind_str()
352 )))
353 }
354 }
355
356 pub fn set_wstring_value(
361 &mut self,
362 member_id: MemberId,
363 value: Vec<u16>,
364 ) -> Result<(), DynamicError> {
365 self.set(member_id, DynamicValue::WString(value))
366 }
367}
368
369impl DynamicData {
374 pub fn get_complex_value(&self, member_id: MemberId) -> Result<&DynamicData, DynamicError> {
381 let v = self.get(member_id)?;
382 if let DynamicValue::Complex(d) = v {
383 Ok(d)
384 } else {
385 Err(DynamicError::bad_parameter(alloc::format!(
386 "type mismatch: expected complex got {}",
387 v.kind_str()
388 )))
389 }
390 }
391
392 pub fn set_complex_value(
397 &mut self,
398 member_id: MemberId,
399 value: DynamicData,
400 ) -> Result<(), DynamicError> {
401 self.set(member_id, DynamicValue::Complex(Box::new(value)))
402 }
403
404 pub fn get_sequence_length(&self, member_id: MemberId) -> Result<u32, DynamicError> {
409 let v = self.get(member_id)?;
410 if let DynamicValue::Sequence(seq) = v {
411 Ok(u32::try_from(seq.len()).unwrap_or(u32::MAX))
412 } else {
413 Err(DynamicError::bad_parameter(alloc::format!(
414 "type mismatch: expected sequence got {}",
415 v.kind_str()
416 )))
417 }
418 }
419
420 pub fn set_sequence_value(
425 &mut self,
426 member_id: MemberId,
427 value: Vec<DynamicData>,
428 ) -> Result<(), DynamicError> {
429 self.set(member_id, DynamicValue::Sequence(value))
430 }
431
432 pub fn get_sequence_element(
437 &self,
438 member_id: MemberId,
439 index: u32,
440 ) -> Result<&DynamicData, DynamicError> {
441 let v = self.get(member_id)?;
442 if let DynamicValue::Sequence(seq) = v {
443 seq.get(index as usize).ok_or_else(|| {
444 DynamicError::bad_parameter(alloc::format!(
445 "sequence index {index} out of range (len={})",
446 seq.len()
447 ))
448 })
449 } else {
450 Err(DynamicError::bad_parameter(alloc::format!(
451 "type mismatch: expected sequence got {}",
452 v.kind_str()
453 )))
454 }
455 }
456}
457
458impl DynamicData {
463 pub fn loan_value(&mut self, member_id: MemberId) -> Result<DataLoan, DynamicError> {
472 self.validate_member(member_id)?;
473 if self.active_loans.contains(&member_id) {
474 return Err(DynamicError::loan(alloc::format!(
475 "member {member_id} is already on loan"
476 )));
477 }
478 self.active_loans.push(member_id);
479 let handle = self.next_loan_handle;
480 self.next_loan_handle = self.next_loan_handle.saturating_add(1);
481 Ok(DataLoan { member_id, handle })
482 }
483
484 pub fn return_loaned_value(&mut self, loan: DataLoan) -> Result<(), DynamicError> {
489 let pos = self
490 .active_loans
491 .iter()
492 .position(|m| *m == loan.member_id)
493 .ok_or_else(|| {
494 DynamicError::loan(alloc::format!(
495 "no active loan for member {}",
496 loan.member_id
497 ))
498 })?;
499 self.active_loans.swap_remove(pos);
500 let _ = loan.handle;
504 Ok(())
505 }
506}
507
508fn check_value_kind_matches_type(value: &DynamicValue, kind: TypeKind) -> Result<(), DynamicError> {
510 let ok = match (value, kind) {
511 (DynamicValue::Bool(_), TypeKind::Boolean) => true,
512 (DynamicValue::Byte(_), TypeKind::Byte) => true,
513 (DynamicValue::Int8(_), TypeKind::Int8) => true,
514 (DynamicValue::UInt8(_), TypeKind::UInt8) => true,
515 (DynamicValue::Int16(_), TypeKind::Int16) => true,
516 (DynamicValue::UInt16(_), TypeKind::UInt16) => true,
517 (DynamicValue::Int32(_), TypeKind::Int32 | TypeKind::Enumeration) => true,
518 (DynamicValue::UInt32(_), TypeKind::UInt32) => true,
519 (DynamicValue::Int64(_), TypeKind::Int64) => true,
520 (DynamicValue::UInt64(_), TypeKind::UInt64) => true,
521 (DynamicValue::Float32(_), TypeKind::Float32) => true,
522 (DynamicValue::Float64(_), TypeKind::Float64) => true,
523 (DynamicValue::Char8(_), TypeKind::Char8) => true,
524 (DynamicValue::Char16(_), TypeKind::Char16) => true,
525 (DynamicValue::String(_), TypeKind::String8) => true,
526 (DynamicValue::WString(_), TypeKind::String16) => true,
527 (DynamicValue::Complex(_), k) if k.is_aggregable() => true,
528 (DynamicValue::Sequence(_), TypeKind::Sequence | TypeKind::Array) => true,
529 (DynamicValue::None, _) => true,
530 _ => false,
531 };
532 if !ok {
533 return Err(DynamicError::bad_parameter(alloc::format!(
534 "value kind {} cannot be assigned to member kind {kind:?}",
535 value.kind_str()
536 )));
537 }
538 Ok(())
539}
540
541#[cfg(test)]
542#[allow(clippy::unwrap_used)]
543mod tests {
544 use super::*;
545 use crate::dynamic::DynamicTypeBuilderFactory;
546 use crate::dynamic::descriptor::{MemberDescriptor, TypeDescriptor};
547
548 fn struct_with_int32_member() -> DynamicType {
549 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
550 b.add_struct_member("x", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
551 .unwrap();
552 b.build().unwrap()
553 }
554
555 #[test]
556 fn set_get_int32_roundtrips() {
557 let t = struct_with_int32_member();
558 let mut d = DynamicData::new(t);
559 d.set_int32_value(1, 42).unwrap();
560 assert_eq!(d.get_int32_value(1).unwrap(), 42);
561 }
562
563 #[test]
564 fn set_int32_into_int64_member_rejected() {
565 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
566 b.add_struct_member("x", 1, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
567 .unwrap();
568 let t = b.build().unwrap();
569 let mut d = DynamicData::new(t);
570 let err = d.set_int32_value(1, 5).unwrap_err();
571 assert!(matches!(err, DynamicError::BadParameter(_)));
572 }
573
574 #[test]
575 fn unknown_member_id_rejected() {
576 let t = struct_with_int32_member();
577 let mut d = DynamicData::new(t);
578 let err = d.set_int32_value(999, 0).unwrap_err();
579 assert!(matches!(err, DynamicError::BadParameter(_)));
580 }
581
582 #[test]
583 fn loan_double_rejected() {
584 let t = struct_with_int32_member();
585 let mut d = DynamicData::new(t);
586 let _l = d.loan_value(1).unwrap();
587 let err = d.loan_value(1).unwrap_err();
588 assert!(matches!(err, DynamicError::LoanError(_)));
589 }
590
591 #[test]
592 fn loan_return_then_loan_again_works() {
593 let t = struct_with_int32_member();
594 let mut d = DynamicData::new(t);
595 let l = d.loan_value(1).unwrap();
596 d.return_loaned_value(l).unwrap();
597 let _l2 = d.loan_value(1).unwrap();
598 }
599
600 #[test]
601 fn return_unknown_loan_rejected() {
602 let t = struct_with_int32_member();
603 let mut d = DynamicData::new(t);
604 let fake = DataLoan {
605 member_id: 1,
606 handle: 99,
607 };
608 let err = d.return_loaned_value(fake).unwrap_err();
609 assert!(matches!(err, DynamicError::LoanError(_)));
610 }
611
612 #[test]
613 fn item_count_grows_with_sets() {
614 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
615 b.add_struct_member("a", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
616 .unwrap();
617 b.add_struct_member("b", 2, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
618 .unwrap();
619 let t = b.build().unwrap();
620 let mut d = DynamicData::new(t);
621 assert_eq!(d.item_count(), 0);
622 d.set_int32_value(1, 10).unwrap();
623 assert_eq!(d.item_count(), 1);
624 d.set_int64_value(2, 20).unwrap();
625 assert_eq!(d.item_count(), 2);
626 }
627
628 #[test]
629 fn equals_distinguishes_value_diffs() {
630 let t = struct_with_int32_member();
631 let mut a = DynamicData::new(t.clone());
632 let mut b = DynamicData::new(t);
633 a.set_int32_value(1, 5).unwrap();
634 b.set_int32_value(1, 6).unwrap();
635 assert!(!a.equals(&b));
636 b.set_int32_value(1, 5).unwrap();
637 assert!(a.equals(&b));
638 }
639
640 #[test]
641 fn complex_value_set_get() {
642 let mut inner = DynamicTypeBuilderFactory::create_struct("::Inner");
644 inner
645 .add_struct_member("v", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"))
646 .unwrap();
647 let inner_t = inner.build().unwrap();
648
649 let mut outer = DynamicTypeBuilderFactory::create_struct("::Outer");
650 outer
651 .add_member(MemberDescriptor::new(
652 "nested",
653 10,
654 TypeDescriptor::structure("::Inner"),
655 ))
656 .unwrap();
657 let outer_t = outer.build().unwrap();
658
659 let mut inner_data = DynamicData::new(inner_t);
660 inner_data.set_int32_value(1, 99).unwrap();
661
662 let mut outer_data = DynamicData::new(outer_t);
663 outer_data.set_complex_value(10, inner_data).unwrap();
664
665 let got = outer_data.get_complex_value(10).unwrap();
666 assert_eq!(got.get_int32_value(1).unwrap(), 99);
667 }
668
669 #[test]
670 fn sequence_length_and_element_access() {
671 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
672 b.add_struct_member(
673 "items",
674 1,
675 TypeDescriptor::sequence(
676 "items",
677 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
678 100,
679 ),
680 )
681 .unwrap();
682 let t = b.build().unwrap();
683
684 let elem_t = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
685 let mut e0 = DynamicData::new(elem_t.clone());
686 e0.values.insert(0, DynamicValue::Int32(7));
687 let mut e1 = DynamicData::new(elem_t);
688 e1.values.insert(0, DynamicValue::Int32(8));
689 let mut d = DynamicData::new(t);
690 d.set_sequence_value(1, alloc::vec![e0, e1]).unwrap();
691 assert_eq!(d.get_sequence_length(1).unwrap(), 2);
692 let _ = d.get_sequence_element(1, 0).unwrap();
693 assert!(d.get_sequence_element(1, 9).is_err());
694 }
695
696 #[test]
697 fn all_twelve_primitive_setters_work() {
698 let cases: alloc::vec::Vec<(&str, MemberId, TypeKind)> = alloc::vec![
700 ("b", 1, TypeKind::Boolean),
701 ("by", 2, TypeKind::Byte),
702 ("i8", 3, TypeKind::Int8),
703 ("u8", 4, TypeKind::UInt8),
704 ("i16", 5, TypeKind::Int16),
705 ("u16", 6, TypeKind::UInt16),
706 ("i32", 7, TypeKind::Int32),
707 ("u32", 8, TypeKind::UInt32),
708 ("i64", 9, TypeKind::Int64),
709 ("u64", 10, TypeKind::UInt64),
710 ("f32", 11, TypeKind::Float32),
711 ("f64", 12, TypeKind::Float64),
712 ("c8", 13, TypeKind::Char8),
713 ("c16", 14, TypeKind::Char16),
714 ];
715 let mut b = DynamicTypeBuilderFactory::create_struct("::S");
716 for (n, id, k) in &cases {
717 b.add_struct_member(
718 *n,
719 *id,
720 TypeDescriptor::primitive(*k, super::super::type_::primitive_name(*k)),
721 )
722 .unwrap();
723 }
724 b.add_struct_member("s", 100, TypeDescriptor::string8(64))
726 .unwrap();
727 b.add_struct_member("w", 101, TypeDescriptor::string16(64))
728 .unwrap();
729 let t = b.build().unwrap();
730 let mut d = DynamicData::new(t);
731 d.set_boolean_value(1, true).unwrap();
732 d.set_byte_value(2, 0xFF).unwrap();
733 d.set_int8_value(3, -1).unwrap();
734 d.set_uint8_value(4, 255).unwrap();
735 d.set_int16_value(5, -2).unwrap();
736 d.set_uint16_value(6, 2).unwrap();
737 d.set_int32_value(7, -3).unwrap();
738 d.set_uint32_value(8, 3).unwrap();
739 d.set_int64_value(9, -4).unwrap();
740 d.set_uint64_value(10, 4).unwrap();
741 d.set_float32_value(11, 1.5).unwrap();
742 d.set_float64_value(12, 2.5).unwrap();
743 d.set_char8_value(13, b'A').unwrap();
744 d.set_char16_value(14, 0x42).unwrap();
745 d.set_string_value(100, "abc").unwrap();
746 d.set_wstring_value(101, alloc::vec![0x41, 0x42]).unwrap();
747
748 assert!(d.get_boolean_value(1).unwrap());
749 assert_eq!(d.get_byte_value(2).unwrap(), 0xFF);
750 assert_eq!(d.get_int8_value(3).unwrap(), -1);
751 assert_eq!(d.get_uint8_value(4).unwrap(), 255);
752 assert_eq!(d.get_int16_value(5).unwrap(), -2);
753 assert_eq!(d.get_uint16_value(6).unwrap(), 2);
754 assert_eq!(d.get_int32_value(7).unwrap(), -3);
755 assert_eq!(d.get_uint32_value(8).unwrap(), 3);
756 assert_eq!(d.get_int64_value(9).unwrap(), -4);
757 assert_eq!(d.get_uint64_value(10).unwrap(), 4);
758 assert!((d.get_float32_value(11).unwrap() - 1.5).abs() < 1e-6);
759 assert!((d.get_float64_value(12).unwrap() - 2.5).abs() < 1e-9);
760 assert_eq!(d.get_char8_value(13).unwrap(), b'A');
761 assert_eq!(d.get_char16_value(14).unwrap(), 0x42);
762 assert_eq!(d.get_string_value(100).unwrap(), "abc");
763 assert_eq!(d.get_wstring_value(101).unwrap(), alloc::vec![0x41, 0x42]);
764 }
765}