1use alloc::format;
37use alloc::string::{String, ToString};
38use alloc::vec::Vec;
39
40use crate::type_identifier::{PrimitiveKind, TypeIdentifier};
41use crate::type_object::common::NameHash;
42use crate::type_object::common::{CommonStructMember, CommonUnionMember};
43use crate::type_object::complete::{
44 CompleteAliasBody, CompleteAliasHeader, CompleteAliasType, CompleteAnnotationParameter,
45 CompleteAnnotationType, CompleteArrayType, CompleteBitfield, CompleteBitflag,
46 CompleteBitmaskType, CompleteBitsetType, CompleteCollectionElement,
47 CompleteDiscriminatorMember, CompleteEnumeratedHeader, CompleteEnumeratedLiteral,
48 CompleteEnumeratedType, CompleteMapType, CompleteSequenceType, CompleteStructHeader,
49 CompleteStructMember, CompleteStructType, CompleteUnionHeader, CompleteUnionMember,
50 CompleteUnionType,
51};
52use crate::type_object::flags::{
53 AliasMemberFlag, AliasTypeFlag, AnnotationParameterFlag, AnnotationTypeFlag, BitfieldFlag,
54 BitflagFlag, BitmaskTypeFlag, BitsetTypeFlag, CollectionElementFlag, CollectionTypeFlag,
55 EnumLiteralFlag, EnumTypeFlag, StructMemberFlag, StructTypeFlag, UnionDiscriminatorFlag,
56 UnionMemberFlag, UnionTypeFlag,
57};
58use crate::type_object::minimal::CommonDiscriminatorMember;
59use crate::type_object::minimal::{
60 CommonBitfield, CommonBitflag, CommonCollectionElement, CommonEnumeratedHeader,
61 CommonEnumeratedLiteral, MinimalTypeObject,
62};
63use crate::type_object::{CompleteTypeObject, TypeObject};
64
65use super::builder::{DynamicTypeBuilder, DynamicTypeBuilderFactory};
66use super::collection;
67use super::descriptor::{ExtensibilityKind, MemberDescriptor, TypeDescriptor, TypeKind};
68use super::error::DynamicError;
69use super::type_::DynamicType;
70
71impl DynamicType {
76 pub fn to_type_object(&self) -> Result<TypeObject, DynamicError> {
88 match self.kind() {
89 TypeKind::Structure => Ok(TypeObject::Complete(CompleteTypeObject::Struct(
90 self.to_complete_struct()?,
91 ))),
92 TypeKind::Union => Ok(TypeObject::Complete(CompleteTypeObject::Union(
93 self.to_complete_union()?,
94 ))),
95 TypeKind::Enumeration => Ok(TypeObject::Complete(CompleteTypeObject::Enumerated(
96 self.to_complete_enum()?,
97 ))),
98 TypeKind::Bitmask => Ok(TypeObject::Complete(CompleteTypeObject::Bitmask(
99 self.to_complete_bitmask()?,
100 ))),
101 TypeKind::Alias => Ok(TypeObject::Complete(CompleteTypeObject::Alias(
102 self.to_complete_alias()?,
103 ))),
104 TypeKind::Sequence => Ok(TypeObject::Complete(CompleteTypeObject::Sequence(
105 self.to_complete_sequence()?,
106 ))),
107 TypeKind::Array => Ok(TypeObject::Complete(CompleteTypeObject::Array(
108 self.to_complete_array()?,
109 ))),
110 TypeKind::Map => Ok(TypeObject::Complete(CompleteTypeObject::Map(
111 self.to_complete_map()?,
112 ))),
113 TypeKind::Bitset => Ok(TypeObject::Complete(CompleteTypeObject::Bitset(
114 self.to_complete_bitset()?,
115 ))),
116 TypeKind::Annotation => Ok(TypeObject::Complete(CompleteTypeObject::Annotation(
117 self.to_complete_annotation()?,
118 ))),
119 other => Err(DynamicError::unsupported(format!(
120 "to_type_object: {other:?} is a primitive/no-type kind without TypeObject",
121 ))),
122 }
123 }
124
125 fn to_complete_sequence(&self) -> Result<CompleteSequenceType, DynamicError> {
128 use crate::type_object::common::{
129 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
130 };
131 let element = self
132 .descriptor()
133 .element_type
134 .as_ref()
135 .ok_or_else(|| DynamicError::inconsistent("sequence type missing element_type"))?;
136 let bound = self.descriptor().bound.first().copied().unwrap_or(0);
137 Ok(CompleteSequenceType {
138 collection_flag: CollectionTypeFlag(0),
139 bound,
140 detail: CompleteTypeDetail {
141 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
142 ann_custom: OptionalAppliedAnnotationSeq::default(),
143 type_name: self.descriptor().name.clone(),
144 },
145 element: complete_collection_element(element)?,
146 })
147 }
148
149 fn to_complete_array(&self) -> Result<CompleteArrayType, DynamicError> {
152 use crate::type_object::common::{
153 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
154 };
155 let element = self
156 .descriptor()
157 .element_type
158 .as_ref()
159 .ok_or_else(|| DynamicError::inconsistent("array type missing element_type"))?;
160 let bound_seq = self.descriptor().bound.clone();
161 if bound_seq.is_empty() {
162 return Err(DynamicError::inconsistent(
163 "array type missing dimensions (bound)",
164 ));
165 }
166 Ok(CompleteArrayType {
167 collection_flag: CollectionTypeFlag(0),
168 bound_seq,
169 detail: CompleteTypeDetail {
170 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
171 ann_custom: OptionalAppliedAnnotationSeq::default(),
172 type_name: self.descriptor().name.clone(),
173 },
174 element: complete_collection_element(element)?,
175 })
176 }
177
178 fn to_complete_map(&self) -> Result<CompleteMapType, DynamicError> {
181 use crate::type_object::common::{
182 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
183 };
184 let value =
185 self.descriptor().element_type.as_ref().ok_or_else(|| {
186 DynamicError::inconsistent("map type missing element_type (value)")
187 })?;
188 let key = self
189 .descriptor()
190 .key_element_type
191 .as_ref()
192 .ok_or_else(|| DynamicError::inconsistent("map type missing key_element_type"))?;
193 let bound = self.descriptor().bound.first().copied().unwrap_or(0);
194 Ok(CompleteMapType {
195 collection_flag: CollectionTypeFlag(0),
196 bound,
197 detail: CompleteTypeDetail {
198 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
199 ann_custom: OptionalAppliedAnnotationSeq::default(),
200 type_name: self.descriptor().name.clone(),
201 },
202 key: complete_collection_element(key)?,
203 element: complete_collection_element(value)?,
204 })
205 }
206
207 fn to_complete_alias(&self) -> Result<CompleteAliasType, DynamicError> {
208 use crate::type_object::common::{
209 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteTypeDetail,
210 OptionalAppliedAnnotationSeq,
211 };
212 let header = CompleteAliasHeader {
213 detail: CompleteTypeDetail {
214 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
215 ann_custom: OptionalAppliedAnnotationSeq::default(),
216 type_name: self.descriptor().name.clone(),
217 },
218 };
219 let element = self.descriptor().element_type.as_ref().ok_or_else(|| {
220 DynamicError::inconsistent("alias type missing element_type (target)")
221 })?;
222 let related_type = descriptor_to_type_identifier(element)?;
223 let body = CompleteAliasBody {
224 related_flags: AliasMemberFlag(0),
225 related_type,
226 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
227 ann_custom: OptionalAppliedAnnotationSeq::default(),
228 };
229 Ok(CompleteAliasType {
230 alias_flags: AliasTypeFlag(0),
231 header,
232 body,
233 })
234 }
235
236 fn to_complete_enum(&self) -> Result<CompleteEnumeratedType, DynamicError> {
237 use crate::type_object::common::{
238 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
239 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
240 };
241 let bit_bound = self.descriptor().bound.first().copied().unwrap_or(32);
242 let bit_bound_u16 = u16::try_from(bit_bound).unwrap_or(32);
243 let header = CompleteEnumeratedHeader {
244 common: CommonEnumeratedHeader {
245 bit_bound: bit_bound_u16,
246 },
247 detail: CompleteTypeDetail {
248 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
249 ann_custom: OptionalAppliedAnnotationSeq::default(),
250 type_name: self.descriptor().name.clone(),
251 },
252 };
253 let mut literal_seq: Vec<CompleteEnumeratedLiteral> =
254 Vec::with_capacity(self.member_count() as usize);
255 for m in self.members() {
256 let mut flags_bits: u16 = 0;
257 if m.descriptor().is_default_label {
258 flags_bits |= EnumLiteralFlag::IS_DEFAULT_LITERAL;
259 }
260 let value = i32::try_from(m.id()).map_err(|_| {
262 DynamicError::inconsistent(format!("enum literal id {} exceeds i32 range", m.id()))
263 })?;
264 literal_seq.push(CompleteEnumeratedLiteral {
265 common: CommonEnumeratedLiteral {
266 value,
267 flags: EnumLiteralFlag(flags_bits),
268 },
269 detail: CompleteMemberDetail {
270 name: m.name().to_string(),
271 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
272 ann_custom: OptionalAppliedAnnotationSeq::default(),
273 },
274 });
275 }
276 Ok(CompleteEnumeratedType {
277 enum_flags: EnumTypeFlag(0),
278 header,
279 literal_seq,
280 })
281 }
282
283 fn to_complete_bitmask(&self) -> Result<CompleteBitmaskType, DynamicError> {
284 use crate::type_object::common::{
285 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
286 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
287 };
288 let bit_bound = self.descriptor().bound.first().copied().unwrap_or(32);
289 let bit_bound_u16 = u16::try_from(bit_bound).unwrap_or(32);
290 let detail = CompleteTypeDetail {
291 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
292 ann_custom: OptionalAppliedAnnotationSeq::default(),
293 type_name: self.descriptor().name.clone(),
294 };
295 let mut flag_seq: Vec<CompleteBitflag> = Vec::with_capacity(self.member_count() as usize);
296 for m in self.members() {
297 let position = u16::try_from(m.id()).map_err(|_| {
298 DynamicError::inconsistent(format!(
299 "bitmask flag position {} exceeds u16 range",
300 m.id()
301 ))
302 })?;
303 flag_seq.push(CompleteBitflag {
304 common: CommonBitflag {
305 position,
306 flags: BitflagFlag(0),
307 },
308 detail: CompleteMemberDetail {
309 name: m.name().to_string(),
310 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
311 ann_custom: OptionalAppliedAnnotationSeq::default(),
312 },
313 });
314 }
315 Ok(CompleteBitmaskType {
316 bitmask_flags: BitmaskTypeFlag(0),
317 bit_bound: bit_bound_u16,
318 detail,
319 flag_seq,
320 })
321 }
322
323 fn to_complete_bitset(&self) -> Result<CompleteBitsetType, DynamicError> {
328 use crate::type_object::common::{
329 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
330 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
331 };
332 let detail = CompleteTypeDetail {
333 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
334 ann_custom: OptionalAppliedAnnotationSeq::default(),
335 type_name: self.descriptor().name.clone(),
336 };
337 let mut field_seq: Vec<CompleteBitfield> = Vec::with_capacity(self.member_count() as usize);
338 for m in self.members() {
339 let position = u16::try_from(m.id()).map_err(|_| {
340 DynamicError::inconsistent(format!(
341 "bitset field position {} exceeds u16 range",
342 m.id()
343 ))
344 })?;
345 let holder_type = match descriptor_to_type_identifier(
346 m.descriptor().member_type.as_ref(),
347 )? {
348 TypeIdentifier::Primitive(pk) => pk.to_u8(),
349 other => {
350 return Err(DynamicError::inconsistent(format!(
351 "bitset field {:?} holder must be a primitive integer type, got {other:?}",
352 m.name()
353 )));
354 }
355 };
356 let bitcount = m.descriptor().bit_bound.ok_or_else(|| {
357 DynamicError::inconsistent(format!(
358 "bitset field {:?} missing bit_bound (bitfield width)",
359 m.name()
360 ))
361 })?;
362 field_seq.push(CompleteBitfield {
363 common: CommonBitfield {
364 position,
365 flags: BitfieldFlag(0),
366 bitcount,
367 holder_type,
368 },
369 detail: CompleteMemberDetail {
370 name: m.name().to_string(),
371 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
372 ann_custom: OptionalAppliedAnnotationSeq::default(),
373 },
374 });
375 }
376 Ok(CompleteBitsetType {
377 bitset_flags: BitsetTypeFlag(0),
378 detail,
379 field_seq,
380 })
381 }
382
383 fn to_complete_annotation(&self) -> Result<CompleteAnnotationType, DynamicError> {
388 use crate::type_object::common::{
389 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
390 };
391 let detail = CompleteTypeDetail {
392 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
393 ann_custom: OptionalAppliedAnnotationSeq::default(),
394 type_name: self.descriptor().name.clone(),
395 };
396 let mut member_seq: Vec<CompleteAnnotationParameter> =
397 Vec::with_capacity(self.member_count() as usize);
398 for m in self.members() {
399 let member_type_id =
400 descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?;
401 let default_value = m
402 .descriptor()
403 .default_value
404 .as_deref()
405 .map(|s| s.as_bytes().to_vec())
406 .unwrap_or_default();
407 member_seq.push(CompleteAnnotationParameter {
408 member_id: m.id(),
409 member_flags: AnnotationParameterFlag(0),
410 member_type_id,
411 name: m.name().to_string(),
412 default_value,
413 });
414 }
415 Ok(CompleteAnnotationType {
416 annotation_flag: AnnotationTypeFlag(0),
417 detail,
418 member_seq,
419 })
420 }
421
422 fn to_complete_union(&self) -> Result<CompleteUnionType, DynamicError> {
423 use crate::type_object::common::{
424 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
425 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
426 };
427 let union_flags = UnionTypeFlag(extensibility_to_flag_bits(
428 self.descriptor().extensibility_kind,
429 ));
430 let header = CompleteUnionHeader {
431 detail: CompleteTypeDetail {
432 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
433 ann_custom: OptionalAppliedAnnotationSeq::default(),
434 type_name: self.descriptor().name.clone(),
435 },
436 };
437 let disc_descriptor = self
438 .descriptor()
439 .discriminator_type
440 .as_ref()
441 .ok_or_else(|| DynamicError::inconsistent("union type missing discriminator_type"))?;
442 let disc_type = descriptor_to_type_identifier(disc_descriptor)?;
443 let discriminator = CompleteDiscriminatorMember {
444 common: CommonDiscriminatorMember {
445 member_flags: UnionDiscriminatorFlag(0),
446 type_id: disc_type,
447 },
448 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
449 ann_custom: OptionalAppliedAnnotationSeq::default(),
450 };
451 let mut member_seq: Vec<CompleteUnionMember> =
452 Vec::with_capacity(self.member_count() as usize);
453 for m in self.members() {
454 let mut flags_bits: u16 = 0;
455 if m.descriptor().is_default_label {
456 flags_bits |= UnionMemberFlag::IS_DEFAULT;
457 }
458 let label_seq: Vec<i32> = m
460 .descriptor()
461 .label
462 .iter()
463 .map(|&v| i32::try_from(v).unwrap_or_default())
464 .collect();
465 let common = CommonUnionMember {
466 member_id: m.id(),
467 member_flags: UnionMemberFlag(flags_bits),
468 type_id: descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?,
469 label_seq,
470 };
471 let detail = CompleteMemberDetail {
472 name: m.name().to_string(),
473 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
474 ann_custom: OptionalAppliedAnnotationSeq::default(),
475 };
476 member_seq.push(CompleteUnionMember { common, detail });
477 }
478 Ok(CompleteUnionType {
479 union_flags,
480 header,
481 discriminator,
482 member_seq,
483 })
484 }
485
486 fn to_complete_struct(&self) -> Result<CompleteStructType, DynamicError> {
487 use crate::type_object::common::{
488 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
489 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
490 };
491 let struct_flags = StructTypeFlag(extensibility_to_flag_bits(
492 self.descriptor().extensibility_kind,
493 ));
494 let header = CompleteStructHeader {
495 base_type: TypeIdentifier::None,
496 detail: CompleteTypeDetail {
497 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
498 ann_custom: OptionalAppliedAnnotationSeq::default(),
499 type_name: self.descriptor().name.clone(),
500 },
501 };
502 let mut member_seq: Vec<CompleteStructMember> =
503 Vec::with_capacity(self.member_count() as usize);
504 for m in self.members() {
505 let mut flags_bits: u16 = 0;
506 if m.descriptor().is_key {
507 flags_bits |= StructMemberFlag::IS_KEY;
508 }
509 if m.descriptor().is_optional {
510 flags_bits |= StructMemberFlag::IS_OPTIONAL;
511 }
512 if m.descriptor().is_must_understand {
513 flags_bits |= StructMemberFlag::IS_MUST_UNDERSTAND;
514 }
515 if m.descriptor().is_shared {
516 flags_bits |= StructMemberFlag::IS_EXTERNAL;
517 }
518 let common = CommonStructMember {
519 member_id: m.id(),
520 member_flags: StructMemberFlag(flags_bits),
521 member_type_id: descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?,
522 };
523 let detail = CompleteMemberDetail {
524 name: m.name().to_string(),
525 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
526 ann_custom: OptionalAppliedAnnotationSeq::default(),
527 };
528 member_seq.push(CompleteStructMember { common, detail });
529 }
530 Ok(CompleteStructType {
531 struct_flags,
532 header,
533 member_seq,
534 })
535 }
536}
537
538const fn extensibility_to_flag_bits(ext: ExtensibilityKind) -> u16 {
539 match ext {
540 ExtensibilityKind::Final => StructTypeFlag::IS_FINAL,
541 ExtensibilityKind::Appendable => StructTypeFlag::IS_APPENDABLE,
542 ExtensibilityKind::Mutable => StructTypeFlag::IS_MUTABLE,
543 }
544}
545
546const fn flag_bits_to_extensibility(flags: u16) -> ExtensibilityKind {
547 if flags & StructTypeFlag::IS_FINAL != 0 {
548 ExtensibilityKind::Final
549 } else if flags & StructTypeFlag::IS_MUTABLE != 0 {
550 ExtensibilityKind::Mutable
551 } else {
552 ExtensibilityKind::Appendable
553 }
554}
555
556fn complete_collection_element(
559 desc: &TypeDescriptor,
560) -> Result<CompleteCollectionElement, DynamicError> {
561 use crate::type_object::common::{
562 AppliedBuiltinMemberAnnotations, OptionalAppliedAnnotationSeq,
563 };
564 Ok(CompleteCollectionElement {
565 common: CommonCollectionElement {
566 element_flags: CollectionElementFlag(0),
567 type_id: descriptor_to_type_identifier(desc)?,
568 },
569 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
570 ann_custom: OptionalAppliedAnnotationSeq::default(),
571 })
572}
573
574fn descriptor_to_type_identifier(desc: &TypeDescriptor) -> Result<TypeIdentifier, DynamicError> {
579 match desc.kind {
580 TypeKind::Boolean => Ok(TypeIdentifier::Primitive(PrimitiveKind::Boolean)),
581 TypeKind::Byte => Ok(TypeIdentifier::Primitive(PrimitiveKind::Byte)),
582 TypeKind::Int8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int8)),
583 TypeKind::UInt8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt8)),
584 TypeKind::Int16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int16)),
585 TypeKind::UInt16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt16)),
586 TypeKind::Int32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int32)),
587 TypeKind::UInt32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt32)),
588 TypeKind::Int64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int64)),
589 TypeKind::UInt64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt64)),
590 TypeKind::Float32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float32)),
591 TypeKind::Float64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float64)),
592 TypeKind::Float128 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float128)),
593 TypeKind::Char8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Char8)),
594 TypeKind::Char16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Char16)),
595 TypeKind::String8 => {
596 let bound = desc.bound.first().copied().unwrap_or(0);
597 if bound <= u32::from(u8::MAX) {
598 Ok(TypeIdentifier::String8Small { bound: bound as u8 })
599 } else {
600 Ok(TypeIdentifier::String8Large { bound })
601 }
602 }
603 TypeKind::String16 => {
604 let bound = desc.bound.first().copied().unwrap_or(0);
605 if bound <= u32::from(u8::MAX) {
606 Ok(TypeIdentifier::String16Small { bound: bound as u8 })
607 } else {
608 Ok(TypeIdentifier::String16Large { bound })
609 }
610 }
611 TypeKind::Structure | TypeKind::Union | TypeKind::Enumeration | TypeKind::Alias => {
612 Ok(TypeIdentifier::None)
617 }
618 kind => Err(DynamicError::unsupported(format!(
619 "descriptor_to_type_identifier: {kind:?} not yet covered"
620 ))),
621 }
622}
623
624impl DynamicTypeBuilderFactory {
629 pub fn create_type_w_type_object(
639 type_obj: &TypeObject,
640 ) -> Result<DynamicTypeBuilder, DynamicError> {
641 match type_obj {
642 TypeObject::Complete(c) => match c {
643 CompleteTypeObject::Struct(s) => complete_struct_to_builder(s),
644 other => Err(DynamicError::unsupported(format!(
645 "complete-typeobject kind {} not yet supported",
646 other_kind_name(other)
647 ))),
648 },
649 TypeObject::Minimal(_) => Err(DynamicError::unsupported(
650 "minimal-typeobject → dynamic-type pending C4.2 TypeRegistry",
651 )),
652 }
653 }
654
655 pub fn create_type_w_type_object_in(
673 type_obj: &TypeObject,
674 registry: &crate::resolve::TypeRegistry,
675 ) -> Result<DynamicType, DynamicError> {
676 match type_obj {
677 TypeObject::Complete(c) => resolve_complete(c, registry),
678 TypeObject::Minimal(m) => resolve_minimal(m, registry, "MinimalType"),
679 }
680 }
681}
682
683fn resolve_type_id(
689 ti: &TypeIdentifier,
690 registry: &crate::resolve::TypeRegistry,
691) -> Result<DynamicType, DynamicError> {
692 use super::builder::DynamicTypeBuilderFactory as F;
693 match ti {
694 TypeIdentifier::Primitive(p) => {
695 let kind = primitive_kind_to_type_kind(*p);
696 F::get_primitive_type(kind)
697 }
698 TypeIdentifier::String8Small { bound } => Ok(F::create_string_type(u32::from(*bound))),
699 TypeIdentifier::String8Large { bound } => Ok(F::create_string_type(*bound)),
700 TypeIdentifier::String16Small { bound } => Ok(F::create_wstring_type(u32::from(*bound))),
701 TypeIdentifier::String16Large { bound } => Ok(F::create_wstring_type(*bound)),
702 TypeIdentifier::PlainSequenceSmall { bound, element, .. } => {
709 let elem = resolve_type_id(element, registry)?;
710 Ok(collection::sequence_of(elem, u32::from(*bound)))
711 }
712 TypeIdentifier::PlainSequenceLarge { bound, element, .. } => {
713 let elem = resolve_type_id(element, registry)?;
714 Ok(collection::sequence_of(elem, *bound))
715 }
716 TypeIdentifier::PlainArraySmall {
717 array_bounds,
718 element,
719 ..
720 } => {
721 let elem = resolve_type_id(element, registry)?;
722 let dims = array_bounds.iter().map(|b| u32::from(*b)).collect();
723 Ok(collection::array_of(elem, dims, "<arr>"))
724 }
725 TypeIdentifier::PlainArrayLarge {
726 array_bounds,
727 element,
728 ..
729 } => {
730 let elem = resolve_type_id(element, registry)?;
731 Ok(collection::array_of(elem, array_bounds.clone(), "<arr>"))
732 }
733 TypeIdentifier::PlainMapSmall {
736 bound,
737 key,
738 element,
739 ..
740 } => {
741 let k = resolve_type_id(key, registry)?;
742 let v = resolve_type_id(element, registry)?;
743 Ok(collection::map_of(k, v, u32::from(*bound), "<map>"))
744 }
745 TypeIdentifier::PlainMapLarge {
746 bound,
747 key,
748 element,
749 ..
750 } => {
751 let k = resolve_type_id(key, registry)?;
752 let v = resolve_type_id(element, registry)?;
753 Ok(collection::map_of(k, v, *bound, "<map>"))
754 }
755 TypeIdentifier::EquivalenceHashComplete(h) => {
756 let c = registry.get_complete(h).ok_or_else(|| {
757 DynamicError::unsupported("composite member: EquivalenceHash not in TypeRegistry")
758 })?;
759 resolve_complete(c, registry)
760 }
761 TypeIdentifier::EquivalenceHashMinimal(h) => {
762 let m = registry.get_minimal(h).ok_or_else(|| {
763 DynamicError::unsupported(
764 "minimal composite member: EquivalenceHash not in registry",
765 )
766 })?;
767 let name = format!(
768 "T_{:08x}",
769 u32::from_be_bytes([h.0[0], h.0[1], h.0[2], h.0[3]])
770 );
771 resolve_minimal(m, registry, &name)
772 }
773 other => Err(DynamicError::unsupported(format!(
774 "resolve_type_id: {other:?} not yet supported"
775 ))),
776 }
777}
778
779fn resolve_complete(
783 c: &CompleteTypeObject,
784 registry: &crate::resolve::TypeRegistry,
785) -> Result<DynamicType, DynamicError> {
786 use super::builder::DynamicTypeBuilderFactory as F;
787 match c {
788 CompleteTypeObject::Struct(s) => complete_struct_to_builder_in(s, registry)?.build(),
789 CompleteTypeObject::Union(u) => {
790 let disc_kind = type_id_to_kind(&u.discriminator.common.type_id)?;
791 let disc_desc = type_id_to_descriptor(&u.discriminator.common.type_id, disc_kind)?;
792 let mut b = F::create_type(TypeDescriptor::union(
793 u.header.detail.type_name.clone(),
794 disc_desc,
795 ))?;
796 for m in &u.member_seq {
797 let mt = resolve_type_id(&m.common.type_id, registry)?;
798 let mut md = MemberDescriptor::new(
799 m.detail.name.clone(),
800 m.common.member_id,
801 mt.descriptor().clone(),
802 );
803 md.label = m.common.label_seq.iter().map(|&v| i64::from(v)).collect();
804 md.is_default_label = (m.common.member_flags.0 & UnionMemberFlag::IS_DEFAULT) != 0;
805 b.add_member_resolved(md, mt)?;
806 }
807 b.build()
808 }
809 CompleteTypeObject::Enumerated(e) => {
810 let mut desc = TypeDescriptor::enumeration(e.header.detail.type_name.clone());
811 desc.bound = alloc::vec![u32::from(e.header.common.bit_bound)];
812 let mut b = F::create_type(desc)?;
813 for lit in &e.literal_seq {
814 let id = u32::try_from(lit.common.value).unwrap_or(0);
815 let mut md = MemberDescriptor::new(
816 lit.detail.name.clone(),
817 id,
818 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
819 );
820 md.is_default_label =
821 (lit.common.flags.0 & EnumLiteralFlag::IS_DEFAULT_LITERAL) != 0;
822 b.add_member(md)?;
823 }
824 b.build()
825 }
826 CompleteTypeObject::Bitmask(bm) => {
827 let mut desc = bare_descriptor(TypeKind::Bitmask, bm.detail.type_name.clone());
828 desc.bound = alloc::vec![u32::from(bm.bit_bound)];
829 let mut b = F::create_type(desc)?;
830 for f in &bm.flag_seq {
831 let md = MemberDescriptor::new(
832 f.detail.name.clone(),
833 u32::from(f.common.position),
834 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
835 );
836 b.add_member(md)?;
837 }
838 b.build()
839 }
840 CompleteTypeObject::Bitset(bs) => {
841 let desc = bare_descriptor(TypeKind::Bitset, bs.detail.type_name.clone());
842 let mut b = F::create_type(desc)?;
843 for f in &bs.field_seq {
844 let holder = PrimitiveKind::from_u8(f.common.holder_type).ok_or_else(|| {
845 DynamicError::inconsistent(format!(
846 "bitset field holder_type {} is not a primitive",
847 f.common.holder_type
848 ))
849 })?;
850 let mut md = MemberDescriptor::new(
851 f.detail.name.clone(),
852 u32::from(f.common.position),
853 TypeDescriptor::primitive(primitive_kind_to_type_kind(holder), "holder"),
854 );
855 md.bit_bound = Some(f.common.bitcount);
856 b.add_member(md)?;
857 }
858 b.build()
859 }
860 CompleteTypeObject::Alias(a) => {
861 let target_kind = type_id_to_kind(&a.body.related_type)?;
862 if matches!(
863 target_kind,
864 TypeKind::Structure
865 | TypeKind::Union
866 | TypeKind::Sequence
867 | TypeKind::Array
868 | TypeKind::Map
869 ) {
870 resolve_type_id(&a.body.related_type, registry)
874 } else {
875 let target = type_id_to_descriptor(&a.body.related_type, target_kind)?;
878 let mut desc = bare_descriptor(TypeKind::Alias, a.header.detail.type_name.clone());
879 desc.element_type = Some(alloc::boxed::Box::new(target));
880 F::create_type(desc)?.build()
881 }
882 }
883 CompleteTypeObject::Sequence(_)
884 | CompleteTypeObject::Array(_)
885 | CompleteTypeObject::Map(_) => {
886 resolve_named_collection(c, registry)
889 }
890 CompleteTypeObject::Annotation(an) => {
891 let desc = bare_descriptor(TypeKind::Annotation, an.detail.type_name.clone());
892 let mut b = F::create_type(desc)?;
893 for m in &an.member_seq {
894 let mk = type_id_to_kind(&m.member_type_id)?;
895 let mt = type_id_to_descriptor(&m.member_type_id, mk)?;
896 let mut md = MemberDescriptor::new(m.name.clone(), m.member_id, mt);
897 if !m.default_value.is_empty() {
898 md.default_value = Some(String::from_utf8_lossy(&m.default_value).into_owned());
899 }
900 b.add_member(md)?;
901 }
902 b.build()
903 }
904 }
905}
906
907fn hash_name(prefix: &str, h: &NameHash) -> String {
912 format!("{prefix}_{:08x}", u32::from_be_bytes(h.0))
913}
914
915fn resolve_minimal(
923 m: &MinimalTypeObject,
924 registry: &crate::resolve::TypeRegistry,
925 type_name: &str,
926) -> Result<DynamicType, DynamicError> {
927 use super::builder::DynamicTypeBuilderFactory as F;
928 match m {
929 MinimalTypeObject::Struct(s) => {
930 let mut desc = TypeDescriptor::structure(type_name.to_string());
931 desc.extensibility_kind = flag_bits_to_extensibility(s.struct_flags.0);
932 if (s.struct_flags.0 & StructTypeFlag::IS_NESTED) != 0 {
933 desc.is_nested = true;
934 }
935 let mut b = F::create_type(desc)?;
936 for (idx, mem) in s.member_seq.iter().enumerate() {
937 let mt = resolve_type_id(&mem.common.member_type_id, registry)?;
938 let mut md = MemberDescriptor::new(
939 hash_name("m", &mem.detail),
940 mem.common.member_id,
941 mt.descriptor().clone(),
942 );
943 md.index = u32::try_from(idx).unwrap_or(u32::MAX);
944 md.is_key = (mem.common.member_flags.0 & StructMemberFlag::IS_KEY) != 0;
945 md.is_optional = (mem.common.member_flags.0 & StructMemberFlag::IS_OPTIONAL) != 0;
946 md.is_must_understand =
947 (mem.common.member_flags.0 & StructMemberFlag::IS_MUST_UNDERSTAND) != 0;
948 md.is_shared = (mem.common.member_flags.0 & StructMemberFlag::IS_EXTERNAL) != 0;
949 b.add_member_resolved(md, mt)?;
950 }
951 b.build()
952 }
953 MinimalTypeObject::Union(u) => {
954 let disc_kind = type_id_to_kind(&u.discriminator.common.type_id)?;
955 let disc_desc = type_id_to_descriptor(&u.discriminator.common.type_id, disc_kind)?;
956 let mut b = F::create_type(TypeDescriptor::union(type_name.to_string(), disc_desc))?;
957 for mem in &u.member_seq {
958 let mt = resolve_type_id(&mem.common.type_id, registry)?;
959 let mut md = MemberDescriptor::new(
960 hash_name("m", &mem.detail),
961 mem.common.member_id,
962 mt.descriptor().clone(),
963 );
964 md.label = mem.common.label_seq.iter().map(|&v| i64::from(v)).collect();
965 md.is_default_label =
966 (mem.common.member_flags.0 & UnionMemberFlag::IS_DEFAULT) != 0;
967 b.add_member_resolved(md, mt)?;
968 }
969 b.build()
970 }
971 MinimalTypeObject::Enumerated(e) => {
972 let mut desc = TypeDescriptor::enumeration(type_name.to_string());
973 desc.bound = alloc::vec![u32::from(e.header.common.bit_bound)];
974 let mut b = F::create_type(desc)?;
975 for lit in &e.literal_seq {
976 let id = u32::try_from(lit.common.value).unwrap_or(0);
977 let mut md = MemberDescriptor::new(
978 hash_name("e", &lit.detail),
979 id,
980 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
981 );
982 md.is_default_label =
983 (lit.common.flags.0 & EnumLiteralFlag::IS_DEFAULT_LITERAL) != 0;
984 b.add_member(md)?;
985 }
986 b.build()
987 }
988 MinimalTypeObject::Bitmask(bm) => {
989 let mut desc = bare_descriptor(TypeKind::Bitmask, type_name.to_string());
990 desc.bound = alloc::vec![u32::from(bm.bit_bound)];
991 let mut b = F::create_type(desc)?;
992 for f in &bm.flag_seq {
993 let md = MemberDescriptor::new(
994 hash_name("f", &f.detail),
995 u32::from(f.common.position),
996 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
997 );
998 b.add_member(md)?;
999 }
1000 b.build()
1001 }
1002 MinimalTypeObject::Bitset(bs) => {
1003 let desc = bare_descriptor(TypeKind::Bitset, type_name.to_string());
1004 let mut b = F::create_type(desc)?;
1005 for f in &bs.field_seq {
1006 let holder = PrimitiveKind::from_u8(f.common.holder_type).ok_or_else(|| {
1007 DynamicError::inconsistent(format!(
1008 "bitset field holder_type {} is not a primitive",
1009 f.common.holder_type
1010 ))
1011 })?;
1012 let mut md = MemberDescriptor::new(
1013 hash_name("f", &f.name_hash),
1014 u32::from(f.common.position),
1015 TypeDescriptor::primitive(primitive_kind_to_type_kind(holder), "holder"),
1016 );
1017 md.bit_bound = Some(f.common.bitcount);
1018 b.add_member(md)?;
1019 }
1020 b.build()
1021 }
1022 MinimalTypeObject::Alias(a) => {
1023 resolve_type_id(&a.body.common.related_type, registry)
1025 }
1026 MinimalTypeObject::Sequence(s) => {
1027 let elem = resolve_type_id(&s.element.common.type_id, registry)?;
1028 Ok(collection::sequence_named(type_name, elem, s.bound))
1029 }
1030 MinimalTypeObject::Array(a) => {
1031 let elem = resolve_type_id(&a.element.common.type_id, registry)?;
1032 Ok(collection::array_of(elem, a.bound_seq.clone(), type_name))
1033 }
1034 MinimalTypeObject::Map(mp) => {
1035 let key = resolve_type_id(&mp.key.common.type_id, registry)?;
1036 let value = resolve_type_id(&mp.element.common.type_id, registry)?;
1037 Ok(collection::map_of(key, value, mp.bound, type_name))
1038 }
1039 MinimalTypeObject::Annotation(_) => Err(DynamicError::unsupported(
1040 "minimal annotation type → dynamic-type (annotations are metadata, not data members)",
1041 )),
1042 }
1043}
1044
1045fn complete_struct_to_builder_in(
1049 s: &CompleteStructType,
1050 registry: &crate::resolve::TypeRegistry,
1051) -> Result<DynamicTypeBuilder, DynamicError> {
1052 let mut desc = TypeDescriptor::structure(s.header.detail.type_name.clone());
1053 desc.extensibility_kind = flag_bits_to_extensibility(s.struct_flags.0);
1054 if (s.struct_flags.0 & StructTypeFlag::IS_NESTED) != 0 {
1055 desc.is_nested = true;
1056 }
1057 let mut b = DynamicTypeBuilderFactory::create_type(desc)?;
1058 for (idx, m) in s.member_seq.iter().enumerate() {
1059 let mt = resolve_type_id(&m.common.member_type_id, registry)?;
1060 let mut md = MemberDescriptor::new(
1061 m.detail.name.clone(),
1062 m.common.member_id,
1063 mt.descriptor().clone(),
1064 );
1065 md.index = u32::try_from(idx).unwrap_or(u32::MAX);
1066 md.is_key = (m.common.member_flags.0 & StructMemberFlag::IS_KEY) != 0;
1067 md.is_optional = (m.common.member_flags.0 & StructMemberFlag::IS_OPTIONAL) != 0;
1068 md.is_must_understand =
1069 (m.common.member_flags.0 & StructMemberFlag::IS_MUST_UNDERSTAND) != 0;
1070 md.is_shared = (m.common.member_flags.0 & StructMemberFlag::IS_EXTERNAL) != 0;
1071 b.add_member_resolved(md, mt)?;
1072 }
1073 Ok(b)
1074}
1075
1076fn resolve_named_collection(
1081 c: &CompleteTypeObject,
1082 registry: &crate::resolve::TypeRegistry,
1083) -> Result<DynamicType, DynamicError> {
1084 match c {
1085 CompleteTypeObject::Sequence(s) => {
1086 let elem = resolve_type_id(&s.element.common.type_id, registry)?;
1087 Ok(collection::sequence_named(
1088 &s.detail.type_name,
1089 elem,
1090 s.bound,
1091 ))
1092 }
1093 CompleteTypeObject::Array(a) => {
1094 let elem = resolve_type_id(&a.element.common.type_id, registry)?;
1095 Ok(collection::array_of(
1096 elem,
1097 a.bound_seq.clone(),
1098 &a.detail.type_name,
1099 ))
1100 }
1101 CompleteTypeObject::Map(m) => {
1102 let key = resolve_type_id(&m.key.common.type_id, registry)?;
1103 let value = resolve_type_id(&m.element.common.type_id, registry)?;
1104 Ok(collection::map_of(key, value, m.bound, &m.detail.type_name))
1105 }
1106 other => Err(DynamicError::unsupported(format!(
1107 "resolve_named_collection called on non-collection: {other:?}"
1108 ))),
1109 }
1110}
1111
1112fn bare_descriptor(kind: TypeKind, name: impl Into<String>) -> TypeDescriptor {
1117 TypeDescriptor {
1118 kind,
1119 name: name.into(),
1120 base_type: None,
1121 discriminator_type: None,
1122 bound: Vec::new(),
1123 element_type: None,
1124 key_element_type: None,
1125 extensibility_kind: ExtensibilityKind::default(),
1126 is_nested: false,
1127 }
1128}
1129
1130fn complete_struct_to_builder(s: &CompleteStructType) -> Result<DynamicTypeBuilder, DynamicError> {
1131 let mut desc = TypeDescriptor::structure(s.header.detail.type_name.clone());
1132 desc.extensibility_kind = flag_bits_to_extensibility(s.struct_flags.0);
1133 if (s.struct_flags.0 & StructTypeFlag::IS_NESTED) != 0 {
1134 desc.is_nested = true;
1135 }
1136 let mut b = DynamicTypeBuilderFactory::create_type(desc)?;
1137 for (idx, m) in s.member_seq.iter().enumerate() {
1138 let kind = type_id_to_kind(&m.common.member_type_id)?;
1139 let member_type = type_id_to_descriptor(&m.common.member_type_id, kind)?;
1140 let mut md = MemberDescriptor::new(m.detail.name.clone(), m.common.member_id, member_type);
1141 md.index = u32::try_from(idx).unwrap_or(u32::MAX);
1142 md.is_key = (m.common.member_flags.0 & StructMemberFlag::IS_KEY) != 0;
1143 md.is_optional = (m.common.member_flags.0 & StructMemberFlag::IS_OPTIONAL) != 0;
1144 md.is_must_understand =
1145 (m.common.member_flags.0 & StructMemberFlag::IS_MUST_UNDERSTAND) != 0;
1146 md.is_shared = (m.common.member_flags.0 & StructMemberFlag::IS_EXTERNAL) != 0;
1147 b.add_member(md)?;
1148 }
1149 Ok(b)
1150}
1151
1152const fn other_kind_name(c: &CompleteTypeObject) -> &'static str {
1153 match c {
1154 CompleteTypeObject::Alias(_) => "alias",
1155 CompleteTypeObject::Annotation(_) => "annotation",
1156 CompleteTypeObject::Struct(_) => "struct",
1157 CompleteTypeObject::Union(_) => "union",
1158 CompleteTypeObject::Bitset(_) => "bitset",
1159 CompleteTypeObject::Sequence(_) => "sequence",
1160 CompleteTypeObject::Array(_) => "array",
1161 CompleteTypeObject::Map(_) => "map",
1162 CompleteTypeObject::Enumerated(_) => "enum",
1163 CompleteTypeObject::Bitmask(_) => "bitmask",
1164 }
1165}
1166
1167fn type_id_to_kind(ti: &TypeIdentifier) -> Result<TypeKind, DynamicError> {
1168 Ok(match ti {
1169 TypeIdentifier::None => TypeKind::NoType,
1170 TypeIdentifier::Primitive(p) => primitive_kind_to_type_kind(*p),
1171 TypeIdentifier::String8Small { .. } | TypeIdentifier::String8Large { .. } => {
1172 TypeKind::String8
1173 }
1174 TypeIdentifier::String16Small { .. } | TypeIdentifier::String16Large { .. } => {
1175 TypeKind::String16
1176 }
1177 TypeIdentifier::PlainSequenceSmall { .. } | TypeIdentifier::PlainSequenceLarge { .. } => {
1178 TypeKind::Sequence
1179 }
1180 TypeIdentifier::PlainArraySmall { .. } | TypeIdentifier::PlainArrayLarge { .. } => {
1181 TypeKind::Array
1182 }
1183 TypeIdentifier::PlainMapSmall { .. } | TypeIdentifier::PlainMapLarge { .. } => {
1184 TypeKind::Map
1185 }
1186 TypeIdentifier::EquivalenceHashMinimal(_) | TypeIdentifier::EquivalenceHashComplete(_) => {
1187 TypeKind::Structure
1190 }
1191 other => {
1192 return Err(DynamicError::unsupported(format!(
1193 "type_id_to_kind: {other:?} not yet supported"
1194 )));
1195 }
1196 })
1197}
1198
1199const fn primitive_kind_to_type_kind(p: PrimitiveKind) -> TypeKind {
1200 match p {
1201 PrimitiveKind::Boolean => TypeKind::Boolean,
1202 PrimitiveKind::Byte => TypeKind::Byte,
1203 PrimitiveKind::Int8 => TypeKind::Int8,
1204 PrimitiveKind::UInt8 => TypeKind::UInt8,
1205 PrimitiveKind::Int16 => TypeKind::Int16,
1206 PrimitiveKind::UInt16 => TypeKind::UInt16,
1207 PrimitiveKind::Int32 => TypeKind::Int32,
1208 PrimitiveKind::UInt32 => TypeKind::UInt32,
1209 PrimitiveKind::Int64 => TypeKind::Int64,
1210 PrimitiveKind::UInt64 => TypeKind::UInt64,
1211 PrimitiveKind::Float32 => TypeKind::Float32,
1212 PrimitiveKind::Float64 => TypeKind::Float64,
1213 PrimitiveKind::Float128 => TypeKind::Float128,
1214 PrimitiveKind::Char8 => TypeKind::Char8,
1215 PrimitiveKind::Char16 => TypeKind::Char16,
1216 }
1217}
1218
1219fn type_id_to_descriptor(
1226 ti: &TypeIdentifier,
1227 kind: TypeKind,
1228) -> Result<TypeDescriptor, DynamicError> {
1229 if kind.is_primitive() {
1230 return Ok(TypeDescriptor::primitive(
1231 kind,
1232 super::type_::primitive_name(kind).to_string(),
1233 ));
1234 }
1235 Ok(match ti {
1236 TypeIdentifier::String8Small { bound } => TypeDescriptor::string8(u32::from(*bound)),
1237 TypeIdentifier::String8Large { bound } => TypeDescriptor::string8(*bound),
1238 TypeIdentifier::String16Small { bound } => TypeDescriptor::string16(u32::from(*bound)),
1239 TypeIdentifier::String16Large { bound } => TypeDescriptor::string16(*bound),
1240 TypeIdentifier::None => TypeDescriptor {
1241 kind: TypeKind::Structure,
1242 name: String::from("<unresolved>"),
1243 base_type: None,
1244 discriminator_type: None,
1245 bound: Vec::new(),
1246 element_type: None,
1247 key_element_type: None,
1248 extensibility_kind: ExtensibilityKind::default(),
1249 is_nested: false,
1250 },
1251 TypeIdentifier::EquivalenceHashMinimal(_) | TypeIdentifier::EquivalenceHashComplete(_) => {
1252 TypeDescriptor {
1255 kind: TypeKind::Structure,
1256 name: String::from("<typeref>"),
1257 base_type: None,
1258 discriminator_type: None,
1259 bound: Vec::new(),
1260 element_type: None,
1261 key_element_type: None,
1262 extensibility_kind: ExtensibilityKind::default(),
1263 is_nested: false,
1264 }
1265 }
1266 TypeIdentifier::PlainSequenceSmall { bound, element, .. } => {
1267 let elem_kind = type_id_to_kind(element)?;
1268 TypeDescriptor::sequence(
1269 "<seq>".to_string(),
1270 type_id_to_descriptor(element, elem_kind)?,
1271 u32::from(*bound),
1272 )
1273 }
1274 TypeIdentifier::PlainSequenceLarge { bound, element, .. } => {
1275 let elem_kind = type_id_to_kind(element)?;
1276 TypeDescriptor::sequence(
1277 "<seq>".to_string(),
1278 type_id_to_descriptor(element, elem_kind)?,
1279 *bound,
1280 )
1281 }
1282 TypeIdentifier::PlainArraySmall {
1283 array_bounds,
1284 element,
1285 ..
1286 } => {
1287 let elem_kind = type_id_to_kind(element)?;
1288 TypeDescriptor::array(
1289 "<arr>".to_string(),
1290 type_id_to_descriptor(element, elem_kind)?,
1291 array_bounds.iter().map(|b| u32::from(*b)).collect(),
1292 )
1293 }
1294 TypeIdentifier::PlainArrayLarge {
1295 array_bounds,
1296 element,
1297 ..
1298 } => {
1299 let elem_kind = type_id_to_kind(element)?;
1300 TypeDescriptor::array(
1301 "<arr>".to_string(),
1302 type_id_to_descriptor(element, elem_kind)?,
1303 array_bounds.clone(),
1304 )
1305 }
1306 other => {
1307 return Err(DynamicError::unsupported(format!(
1308 "type_id_to_descriptor: {other:?} not yet supported"
1309 )));
1310 }
1311 })
1312}
1313
1314#[cfg(test)]
1315#[allow(
1316 clippy::unwrap_used,
1317 clippy::expect_used,
1318 clippy::panic,
1319 clippy::unreachable
1320)]
1321mod tests {
1322 use super::*;
1323 use crate::dynamic::DynamicTypeBuilderFactory;
1324
1325 fn build_int_struct() -> DynamicType {
1326 let mut b = DynamicTypeBuilderFactory::create_struct("::Sensor");
1327 b.add_struct_member("id", 1, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
1328 .unwrap();
1329 b.add_struct_member(
1330 "temp",
1331 2,
1332 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1333 )
1334 .unwrap();
1335 b.add_struct_member("name", 3, TypeDescriptor::string8(64))
1336 .unwrap();
1337 b.build().unwrap()
1338 }
1339
1340 #[test]
1341 fn dynamic_struct_to_typeobject_complete() {
1342 let t = build_int_struct();
1343 let to = t.to_type_object().unwrap();
1344 match to {
1345 TypeObject::Complete(CompleteTypeObject::Struct(s)) => {
1346 assert_eq!(s.header.detail.type_name, "::Sensor");
1347 assert_eq!(s.member_seq.len(), 3);
1348 assert_eq!(s.member_seq[0].detail.name, "id");
1349 }
1350 _ => panic!("to_type_object on Structure must return Complete::Struct"),
1351 }
1352 }
1353
1354 #[test]
1355 fn typeobject_complete_struct_back_to_dynamic_type() {
1356 let t = build_int_struct();
1357 let to = t.to_type_object().unwrap();
1358 let b = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap();
1359 let t2 = b.build().unwrap();
1360 assert_eq!(t2.name(), "::Sensor");
1361 assert_eq!(t2.member_count(), 3);
1362 assert_eq!(t2.member_by_id(1).unwrap().name(), "id");
1363 assert_eq!(t2.member_by_id(2).unwrap().name(), "temp");
1364 assert_eq!(t2.member_by_id(3).unwrap().name(), "name");
1365 }
1366
1367 #[test]
1368 fn roundtrip_dynamic_to_typeobject_to_dynamic_equals_logically() {
1369 let t = build_int_struct();
1370 let to = t.to_type_object().unwrap();
1371 let b = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap();
1372 let t2 = b.build().unwrap();
1373 assert!(t.equals(&t2), "roundtrip failed: {t:?} vs {t2:?}");
1375 }
1376
1377 #[test]
1378 fn unsupported_kind_to_typeobject_yields_unsupported_error() {
1379 let prim = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
1380 let err = prim.to_type_object().unwrap_err();
1381 assert!(matches!(err, DynamicError::Unsupported(_)));
1382 }
1383
1384 #[test]
1385 fn dynamic_alias_to_typeobject_complete() {
1386 let mut desc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
1388 desc.kind = TypeKind::Alias;
1389 desc.name = "::SensorId".to_string();
1390 desc.element_type = Some(alloc::boxed::Box::new(TypeDescriptor::primitive(
1391 TypeKind::Int32,
1392 "int32",
1393 )));
1394 let t = DynamicTypeBuilderFactory::create_type(desc)
1395 .unwrap()
1396 .build()
1397 .unwrap();
1398 let to = t.to_type_object().expect("alias bridge ok");
1399 match to {
1400 TypeObject::Complete(CompleteTypeObject::Alias(a)) => {
1401 assert_eq!(a.header.detail.type_name, "::SensorId");
1402 assert!(matches!(a.body.related_type, TypeIdentifier::Primitive(_)));
1403 }
1404 other => panic!("expected Alias, got {other:?}"),
1405 }
1406 }
1407
1408 #[test]
1409 fn dynamic_enum_to_typeobject_complete() {
1410 let mut desc = TypeDescriptor::primitive(TypeKind::Enumeration, "::Color");
1411 desc.kind = TypeKind::Enumeration;
1412 desc.bound = alloc::vec![32];
1413 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1414 for (id, name) in [(0u32, "RED"), (1u32, "GREEN"), (2u32, "BLUE")] {
1415 let m = MemberDescriptor::new(
1416 name,
1417 id,
1418 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1419 );
1420 b.add_member(m).unwrap();
1421 }
1422 let t = b.build().unwrap();
1423 let to = t.to_type_object().expect("enum bridge ok");
1424 match to {
1425 TypeObject::Complete(CompleteTypeObject::Enumerated(e)) => {
1426 assert_eq!(e.literal_seq.len(), 3);
1427 assert_eq!(e.literal_seq[0].detail.name, "RED");
1428 assert_eq!(e.literal_seq[2].common.value, 2);
1429 }
1430 other => panic!("expected Enumerated, got {other:?}"),
1431 }
1432 }
1433
1434 #[test]
1435 fn dynamic_bitmask_to_typeobject_complete() {
1436 let mut desc = TypeDescriptor::primitive(TypeKind::Bitmask, "::Flags");
1437 desc.kind = TypeKind::Bitmask;
1438 desc.bound = alloc::vec![8];
1439 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1440 for (pos, name) in [(0u32, "A"), (3u32, "D"), (7u32, "H")] {
1441 let m = MemberDescriptor::new(
1442 name,
1443 pos,
1444 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
1445 );
1446 b.add_member(m).unwrap();
1447 }
1448 let t = b.build().unwrap();
1449 let to = t.to_type_object().expect("bitmask bridge ok");
1450 match to {
1451 TypeObject::Complete(CompleteTypeObject::Bitmask(bm)) => {
1452 assert_eq!(bm.bit_bound, 8);
1453 assert_eq!(bm.flag_seq.len(), 3);
1454 assert_eq!(bm.flag_seq[1].common.position, 3);
1455 }
1456 other => panic!("expected Bitmask, got {other:?}"),
1457 }
1458 }
1459
1460 #[test]
1461 fn dynamic_bitset_to_typeobject_complete() {
1462 let mut desc = TypeDescriptor::primitive(TypeKind::Bitset, "::Reg");
1463 desc.kind = TypeKind::Bitset;
1464 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1465 for (pos, name, width) in [(0u32, "lo", 3u8), (3u32, "hi", 5u8)] {
1466 let mut m = MemberDescriptor::new(
1467 name,
1468 pos,
1469 TypeDescriptor::primitive(TypeKind::UInt8, "uint8"),
1470 );
1471 m.bit_bound = Some(width);
1472 b.add_member(m).unwrap();
1473 }
1474 let t = b.build().unwrap();
1475 let to = t.to_type_object().expect("bitset bridge ok");
1476 match to {
1477 TypeObject::Complete(CompleteTypeObject::Bitset(bs)) => {
1478 assert_eq!(bs.field_seq.len(), 2);
1479 assert_eq!(bs.field_seq[0].common.position, 0);
1480 assert_eq!(bs.field_seq[0].common.bitcount, 3);
1481 assert_eq!(bs.field_seq[0].detail.name, "lo");
1482 assert_eq!(bs.field_seq[1].common.position, 3);
1483 assert_eq!(bs.field_seq[1].common.bitcount, 5);
1484 assert_eq!(
1485 bs.field_seq[1].common.holder_type,
1486 PrimitiveKind::UInt8.to_u8()
1487 );
1488 }
1489 other => panic!("expected Bitset, got {other:?}"),
1490 }
1491 }
1492
1493 #[test]
1494 fn dynamic_annotation_to_typeobject_complete() {
1495 let mut desc = TypeDescriptor::primitive(TypeKind::Annotation, "::Range");
1496 desc.kind = TypeKind::Annotation;
1497 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1498 let mut m = MemberDescriptor::new(
1499 "max",
1500 1,
1501 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1502 );
1503 m.default_value = Some("100".into());
1504 b.add_member(m).unwrap();
1505 let t = b.build().unwrap();
1506 let to = t.to_type_object().expect("annotation bridge ok");
1507 match to {
1508 TypeObject::Complete(CompleteTypeObject::Annotation(a)) => {
1509 assert_eq!(a.member_seq.len(), 1);
1510 assert_eq!(a.member_seq[0].name, "max");
1511 assert_eq!(a.member_seq[0].member_id, 1);
1512 assert_eq!(a.member_seq[0].default_value, b"100".to_vec());
1513 assert!(matches!(
1514 a.member_seq[0].member_type_id,
1515 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1516 ));
1517 }
1518 other => panic!("expected Annotation, got {other:?}"),
1519 }
1520 }
1521
1522 #[test]
1523 fn dynamic_sequence_to_typeobject_complete() {
1524 let desc = TypeDescriptor::sequence(
1525 "::Seq",
1526 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1527 10,
1528 );
1529 let t = DynamicTypeBuilderFactory::create_type(desc)
1530 .unwrap()
1531 .build()
1532 .unwrap();
1533 match t.to_type_object().expect("sequence bridge ok") {
1534 TypeObject::Complete(CompleteTypeObject::Sequence(s)) => {
1535 assert_eq!(s.bound, 10);
1536 assert_eq!(s.detail.type_name, "::Seq");
1537 assert!(matches!(
1538 s.element.common.type_id,
1539 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1540 ));
1541 }
1542 other => panic!("expected Sequence, got {other:?}"),
1543 }
1544 }
1545
1546 #[test]
1547 fn dynamic_array_to_typeobject_complete() {
1548 let desc = TypeDescriptor::array(
1549 "::Arr",
1550 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1551 alloc::vec![3, 4],
1552 );
1553 let t = DynamicTypeBuilderFactory::create_type(desc)
1554 .unwrap()
1555 .build()
1556 .unwrap();
1557 match t.to_type_object().expect("array bridge ok") {
1558 TypeObject::Complete(CompleteTypeObject::Array(a)) => {
1559 assert_eq!(a.bound_seq, alloc::vec![3, 4]);
1560 assert!(matches!(
1561 a.element.common.type_id,
1562 TypeIdentifier::Primitive(PrimitiveKind::Float64)
1563 ));
1564 }
1565 other => panic!("expected Array, got {other:?}"),
1566 }
1567 }
1568
1569 #[test]
1570 fn dynamic_map_to_typeobject_complete() {
1571 let desc = TypeDescriptor::map(
1572 "::Map",
1573 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1574 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
1575 7,
1576 );
1577 let t = DynamicTypeBuilderFactory::create_type(desc)
1578 .unwrap()
1579 .build()
1580 .unwrap();
1581 match t.to_type_object().expect("map bridge ok") {
1582 TypeObject::Complete(CompleteTypeObject::Map(m)) => {
1583 assert_eq!(m.bound, 7);
1584 assert!(matches!(
1585 m.key.common.type_id,
1586 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1587 ));
1588 assert!(matches!(
1589 m.element.common.type_id,
1590 TypeIdentifier::Primitive(PrimitiveKind::Boolean)
1591 ));
1592 }
1593 other => panic!("expected Map, got {other:?}"),
1594 }
1595 }
1596
1597 #[test]
1598 fn dynamic_union_to_typeobject_complete() {
1599 let disc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
1600 let t = {
1601 let mut b = DynamicTypeBuilderFactory::create_union("::Shape", disc).unwrap();
1602 let mut m1 = MemberDescriptor::new(
1603 "circle",
1604 1,
1605 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1606 );
1607 m1.label = alloc::vec![1];
1608 let mut m2 = MemberDescriptor::new(
1609 "square",
1610 2,
1611 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1612 );
1613 m2.label = alloc::vec![2, 3];
1614 b.add_member(m1).unwrap();
1615 b.add_member(m2).unwrap();
1616 b.build().unwrap()
1617 };
1618 let to = t.to_type_object().expect("union bridge ok");
1619 match to {
1620 TypeObject::Complete(CompleteTypeObject::Union(u)) => {
1621 assert_eq!(u.member_seq.len(), 2);
1622 assert_eq!(u.member_seq[0].detail.name, "circle");
1623 assert_eq!(u.member_seq[1].common.label_seq, alloc::vec![2, 3]);
1624 assert!(matches!(
1625 u.discriminator.common.type_id,
1626 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1627 ));
1628 }
1629 other => panic!("expected Union, got {other:?}"),
1630 }
1631 }
1632
1633 #[test]
1634 fn create_type_w_minimal_typeobject_bare_needs_registry() {
1635 use crate::type_object::minimal::{MinimalStructHeader, MinimalStructType};
1638 let m = MinimalStructType {
1639 struct_flags: StructTypeFlag::default(),
1640 header: MinimalStructHeader {
1641 base_type: TypeIdentifier::None,
1642 },
1643 member_seq: alloc::vec![],
1644 };
1645 let to = TypeObject::Minimal(MinimalTypeObject::Struct(m));
1646 let err = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap_err();
1647 assert!(matches!(err, DynamicError::Unsupported(_)));
1648 }
1649
1650 #[test]
1654 fn minimal_resolves_wire_identical_to_complete() {
1655 use crate::builder::TypeObjectBuilder;
1656 use crate::dynamic::DynamicData;
1657 use crate::dynamic::codec::{decode_dynamic, encode_dynamic};
1658
1659 let reg = crate::resolve::TypeRegistry::new();
1660 let sb = TypeObjectBuilder::struct_type("::Point")
1661 .member("x", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1662 .member("y", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m);
1663 let complete = TypeObject::Complete(CompleteTypeObject::Struct(sb.build_complete()));
1664 let minimal = TypeObject::Minimal(MinimalTypeObject::Struct(sb.build_minimal()));
1665
1666 let ct = DynamicTypeBuilderFactory::create_type_w_type_object_in(&complete, ®).unwrap();
1667 let mt = DynamicTypeBuilderFactory::create_type_w_type_object_in(&minimal, ®).unwrap();
1668
1669 assert_eq!(mt.kind(), TypeKind::Structure);
1670 assert_eq!(mt.member_count(), 2, "minimal carries the full structure");
1671 assert!(
1672 mt.member_by_name("x").is_none(),
1673 "minimal has hash names, not the readable 'x'"
1674 );
1675
1676 let cx = ct.member_by_name("x").unwrap().id();
1678 let cy = ct.member_by_name("y").unwrap().id();
1679 let mut dc = DynamicData::new(ct.clone());
1680 dc.set_int32_value(cx, 11).unwrap();
1681 dc.set_int32_value(cy, 22).unwrap();
1682 let mut dm = DynamicData::new(mt.clone());
1683 dm.set_int32_value(cx, 11).unwrap();
1684 dm.set_int32_value(cy, 22).unwrap();
1685
1686 for xcdr2 in [true, false] {
1687 let bc = encode_dynamic(&dc, xcdr2, false).unwrap();
1688 let bm = encode_dynamic(&dm, xcdr2, false).unwrap();
1689 assert_eq!(
1690 bc, bm,
1691 "minimal-resolved encodes byte-identically to complete xcdr2={xcdr2}"
1692 );
1693 let back = decode_dynamic(&mt, &bm, xcdr2, false).unwrap();
1694 assert_eq!(back.get_int32_value(cx).unwrap(), 11);
1695 }
1696 }
1697
1698 #[test]
1701 fn minimal_nested_member_resolves_via_registry() {
1702 use crate::builder::TypeObjectBuilder;
1703 use crate::resolve::TypeRegistry;
1704 use crate::type_identifier::EquivalenceHash;
1705
1706 let inner = TypeObjectBuilder::struct_type("::Point")
1707 .member("x", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1708 .build_minimal();
1709 let h = EquivalenceHash([0x7; 14]);
1710 let mut reg = TypeRegistry::new();
1711 reg.insert_minimal(h, MinimalTypeObject::Struct(inner));
1712
1713 let outer = TypeObjectBuilder::struct_type("::Line")
1714 .member("p", TypeIdentifier::EquivalenceHashMinimal(h), |m| m)
1715 .build_minimal();
1716 let to = TypeObject::Minimal(MinimalTypeObject::Struct(outer));
1717 let dt = DynamicTypeBuilderFactory::create_type_w_type_object_in(&to, ®).unwrap();
1718
1719 assert_eq!(dt.member_count(), 1);
1720 let p = dt.member_by_index(0).unwrap();
1721 assert_eq!(
1722 p.dynamic_type().kind(),
1723 TypeKind::Structure,
1724 "nested minimal struct resolved fully"
1725 );
1726 assert_eq!(p.dynamic_type().member_count(), 1);
1727 }
1728
1729 #[test]
1730 fn resolve_nested_struct_member_fully_via_registry() {
1731 use crate::builder::TypeObjectBuilder;
1732 use crate::resolve::TypeRegistry;
1733 use crate::type_identifier::EquivalenceHash;
1734
1735 let inner = TypeObjectBuilder::struct_type("::Point")
1737 .member("x", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1738 .member("y", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1739 .build_complete();
1740 let h = EquivalenceHash([0x42; 14]);
1741 let mut reg = TypeRegistry::new();
1742 reg.insert_complete(h, CompleteTypeObject::Struct(inner));
1743
1744 let outer = TypeObjectBuilder::struct_type("::Line")
1746 .member("start", TypeIdentifier::EquivalenceHashComplete(h), |m| m)
1747 .member(
1748 "len",
1749 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1750 |m| m,
1751 )
1752 .build_complete();
1753 let to = TypeObject::Complete(CompleteTypeObject::Struct(outer));
1754
1755 let dt = DynamicTypeBuilderFactory::create_type_w_type_object_in(&to, ®).unwrap();
1756 assert_eq!(dt.member_count(), 2);
1757 let start = dt.member_by_name("start").expect("start member");
1758 assert_eq!(start.dynamic_type().kind(), TypeKind::Structure);
1760 assert_eq!(start.dynamic_type().member_count(), 2);
1761 assert!(start.dynamic_type().member_by_name("x").is_some());
1762 assert!(start.dynamic_type().member_by_name("y").is_some());
1763 let dangling = TypeObjectBuilder::struct_type("::Bad")
1765 .member(
1766 "ref",
1767 TypeIdentifier::EquivalenceHashComplete(EquivalenceHash([0xFF; 14])),
1768 |m| m,
1769 )
1770 .build_complete();
1771 let bad = TypeObject::Complete(CompleteTypeObject::Struct(dangling));
1772 assert!(matches!(
1773 DynamicTypeBuilderFactory::create_type_w_type_object_in(&bad, ®),
1774 Err(DynamicError::Unsupported(_))
1775 ));
1776 }
1777
1778 fn point_registry() -> (
1786 crate::resolve::TypeRegistry,
1787 crate::type_identifier::EquivalenceHash,
1788 ) {
1789 use crate::builder::TypeObjectBuilder;
1790 use crate::resolve::TypeRegistry;
1791 use crate::type_identifier::EquivalenceHash;
1792 let point = TypeObjectBuilder::struct_type("::Point")
1793 .member("x", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1794 .member("y", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1795 .build_complete();
1796 let h = EquivalenceHash([0x11; 14]);
1797 let mut reg = TypeRegistry::new();
1798 reg.insert_complete(h, CompleteTypeObject::Struct(point));
1799 (reg, h)
1800 }
1801
1802 fn resolve_member(
1804 ti: TypeIdentifier,
1805 reg: &crate::resolve::TypeRegistry,
1806 ) -> Result<DynamicType, DynamicError> {
1807 use crate::builder::TypeObjectBuilder;
1808 let s = TypeObjectBuilder::struct_type("::Holder")
1809 .member("field", ti, |m| m)
1810 .build_complete();
1811 let to = TypeObject::Complete(CompleteTypeObject::Struct(s));
1812 let dt = DynamicTypeBuilderFactory::create_type_w_type_object_in(&to, reg)?;
1813 Ok(dt
1814 .member_by_name("field")
1815 .expect("field member")
1816 .dynamic_type()
1817 .clone())
1818 }
1819
1820 fn seq_of(elem: TypeIdentifier) -> TypeIdentifier {
1821 TypeIdentifier::PlainSequenceSmall {
1822 header: crate::type_identifier::PlainCollectionHeader::default(),
1823 bound: 0,
1824 element: alloc::boxed::Box::new(elem),
1825 }
1826 }
1827
1828 #[test]
1829 fn resolve_seq_of_struct_fully_via_registry() {
1830 let (reg, h) = point_registry();
1831 let seq = resolve_member(seq_of(TypeIdentifier::EquivalenceHashComplete(h)), ®).unwrap();
1832 assert_eq!(seq.kind(), TypeKind::Sequence);
1833 let elem = collection::resolved_element(&seq).expect("resolved composite element");
1834 assert_eq!(
1835 elem.kind(),
1836 TypeKind::Structure,
1837 "seq element is a full struct"
1838 );
1839 assert_eq!(elem.member_count(), 2, "Point's x + y survived");
1840 assert!(elem.member_by_name("x").is_some());
1841 assert!(elem.member_by_name("y").is_some());
1842 }
1843
1844 #[test]
1845 fn resolve_array_of_struct_fully_via_registry() {
1846 let (reg, h) = point_registry();
1847 let arr_ti = TypeIdentifier::PlainArraySmall {
1848 header: crate::type_identifier::PlainCollectionHeader::default(),
1849 array_bounds: alloc::vec![3],
1850 element: alloc::boxed::Box::new(TypeIdentifier::EquivalenceHashComplete(h)),
1851 };
1852 let arr = resolve_member(arr_ti, ®).unwrap();
1853 assert_eq!(arr.kind(), TypeKind::Array);
1854 let elem = collection::resolved_element(&arr).expect("resolved composite element");
1855 assert_eq!(elem.kind(), TypeKind::Structure);
1856 assert_eq!(elem.member_count(), 2);
1857 }
1858
1859 #[test]
1860 fn resolve_seq_of_seq_of_struct_nested() {
1861 let (reg, h) = point_registry();
1862 let nested = seq_of(seq_of(TypeIdentifier::EquivalenceHashComplete(h)));
1863 let outer = resolve_member(nested, ®).unwrap();
1864 assert_eq!(outer.kind(), TypeKind::Sequence);
1865 let inner = collection::resolved_element(&outer).expect("inner sequence");
1866 assert_eq!(
1867 inner.kind(),
1868 TypeKind::Sequence,
1869 "element is itself a sequence"
1870 );
1871 let leaf = collection::resolved_element(inner).expect("leaf struct");
1872 assert_eq!(leaf.kind(), TypeKind::Structure);
1873 assert_eq!(
1874 leaf.member_count(),
1875 2,
1876 "innermost Point still carries its members"
1877 );
1878 }
1879
1880 #[test]
1881 fn resolve_seq_of_scalar_still_works() {
1882 let reg = crate::resolve::TypeRegistry::new();
1884 let seq = resolve_member(
1885 seq_of(TypeIdentifier::Primitive(PrimitiveKind::Int32)),
1886 ®,
1887 )
1888 .unwrap();
1889 assert_eq!(seq.kind(), TypeKind::Sequence);
1890 let elem = collection::resolved_element(&seq).expect("scalar element retained");
1891 assert_eq!(elem.kind(), TypeKind::Int32);
1892 }
1893
1894 #[test]
1895 fn resolve_map_of_struct_fully_via_registry() {
1896 let (reg, h) = point_registry();
1898 let map_ti = TypeIdentifier::PlainMapSmall {
1899 header: crate::type_identifier::PlainCollectionHeader::default(),
1900 bound: 0,
1901 key_flags: crate::type_identifier::CollectionElementFlag(0),
1902 key: alloc::boxed::Box::new(TypeIdentifier::Primitive(PrimitiveKind::Int32)),
1903 element: alloc::boxed::Box::new(TypeIdentifier::EquivalenceHashComplete(h)),
1904 };
1905 let map = resolve_member(map_ti, ®).unwrap();
1906 assert_eq!(map.kind(), TypeKind::Map);
1907 let key = collection::resolved_map_key(&map).expect("resolved key");
1908 let val = collection::resolved_map_value(&map).expect("resolved value");
1909 assert_eq!(key.kind(), TypeKind::Int32);
1910 assert_eq!(
1911 val.kind(),
1912 TypeKind::Structure,
1913 "map value is a full struct"
1914 );
1915 assert_eq!(val.member_count(), 2, "Point's x + y survived");
1916 }
1917
1918 #[test]
1923 fn bridge_built_seq_of_struct_roundtrips_on_the_wire() {
1924 use crate::builder::TypeObjectBuilder;
1925 use crate::dynamic::codec::{decode_dynamic, encode_dynamic};
1926 use crate::dynamic::{DynamicData, DynamicValue};
1927
1928 let (reg, h) = point_registry();
1929 let path = TypeObjectBuilder::struct_type("::Path")
1930 .member(
1931 "pts",
1932 seq_of(TypeIdentifier::EquivalenceHashComplete(h)),
1933 |m| m,
1934 )
1935 .build_complete();
1936 let to = TypeObject::Complete(CompleteTypeObject::Struct(path));
1937 let ty = DynamicTypeBuilderFactory::create_type_w_type_object_in(&to, ®).unwrap();
1938
1939 let pts_member = ty.member_by_name("pts").expect("pts");
1940 let pts_id = pts_member.id();
1941 let elem = collection::resolved_element(pts_member.dynamic_type()).expect("elem");
1942 let xid = elem.member_by_name("x").unwrap().id();
1943 let yid = elem.member_by_name("y").unwrap().id();
1944
1945 let mut p0 = DynamicData::new(elem.clone());
1946 p0.set_int32_value(xid, 3).unwrap();
1947 p0.set_int32_value(yid, 4).unwrap();
1948 let mut p1 = DynamicData::new(elem.clone());
1949 p1.set_int32_value(xid, 5).unwrap();
1950 p1.set_int32_value(yid, 6).unwrap();
1951
1952 let mut d = DynamicData::new(ty.clone());
1953 d.set_sequence_value(pts_id, alloc::vec![p0, p1]).unwrap();
1954
1955 for xcdr2 in [true, false] {
1956 let bytes = encode_dynamic(&d, xcdr2, false).expect("encode");
1957 let back = decode_dynamic(&ty, &bytes, xcdr2, false).expect("decode");
1958 let DynamicValue::Sequence(v) = back.get_value(pts_id).unwrap() else {
1959 panic!("pts is a sequence")
1960 };
1961 assert_eq!(v.len(), 2);
1962 assert_eq!(v[0].dynamic_type().kind(), TypeKind::Structure);
1963 assert_eq!(v[0].get_int32_value(xid).unwrap(), 3);
1964 assert_eq!(v[1].get_int32_value(yid).unwrap(), 6);
1965 assert_eq!(
1966 encode_dynamic(&back, xcdr2, false).unwrap(),
1967 bytes,
1968 "byte-exact bridge-built seq<struct> xcdr2={xcdr2}"
1969 );
1970 }
1971 }
1972
1973 #[test]
1976 fn bridge_built_map_roundtrips_on_the_wire() {
1977 use crate::builder::TypeObjectBuilder;
1978 use crate::dynamic::codec::{decode_dynamic, encode_dynamic};
1979 use crate::dynamic::{DynamicData, DynamicValue};
1980
1981 let (reg, h) = point_registry();
1982 let map_ti = TypeIdentifier::PlainMapSmall {
1983 header: crate::type_identifier::PlainCollectionHeader::default(),
1984 bound: 0,
1985 key_flags: crate::type_identifier::CollectionElementFlag(0),
1986 key: alloc::boxed::Box::new(TypeIdentifier::Primitive(PrimitiveKind::Int32)),
1987 element: alloc::boxed::Box::new(TypeIdentifier::EquivalenceHashComplete(h)),
1988 };
1989 let holder = TypeObjectBuilder::struct_type("::Holder")
1990 .member("m", map_ti, |m| m)
1991 .build_complete();
1992 let to = TypeObject::Complete(CompleteTypeObject::Struct(holder));
1993 let ty = DynamicTypeBuilderFactory::create_type_w_type_object_in(&to, ®).unwrap();
1994
1995 let m_id = ty.member_by_name("m").unwrap().id();
1996 let map_ty = ty.member_by_name("m").unwrap().dynamic_type().clone();
1997 let kt = collection::resolved_map_key(&map_ty).unwrap().clone();
1998 let vt = collection::resolved_map_value(&map_ty).unwrap().clone();
1999 let xid = vt.member_by_name("x").unwrap().id();
2000 let yid = vt.member_by_name("y").unwrap().id();
2001
2002 let mut kd = DynamicData::new(kt.clone());
2003 kd.set_value_raw(0, DynamicValue::Int32(9));
2004 let mut vd = DynamicData::new(vt.clone());
2005 vd.set_int32_value(xid, 3).unwrap();
2006 vd.set_int32_value(yid, 4).unwrap();
2007
2008 let mut d = DynamicData::new(ty.clone());
2009 d.set_map_value(m_id, alloc::vec![(kd, vd)]).unwrap();
2010
2011 for xcdr2 in [true, false] {
2012 let bytes = encode_dynamic(&d, xcdr2, false).unwrap();
2013 let back = decode_dynamic(&ty, &bytes, xcdr2, false).unwrap();
2014 let DynamicValue::Map(got) = back.get_value(m_id).unwrap() else {
2015 panic!("m is a map")
2016 };
2017 assert_eq!(got.len(), 1);
2018 assert_eq!(got[0].0.get_int32_value(0).unwrap(), 9);
2019 assert_eq!(got[0].1.dynamic_type().kind(), TypeKind::Structure);
2020 assert_eq!(got[0].1.get_int32_value(xid).unwrap(), 3);
2021 assert_eq!(
2022 encode_dynamic(&back, xcdr2, false).unwrap(),
2023 bytes,
2024 "byte-exact bridge-built map<i32,struct> xcdr2={xcdr2}"
2025 );
2026 }
2027 }
2028
2029 #[test]
2030 fn alias_to_composite_resolves_transparently() {
2031 use crate::builder::TypeObjectBuilder;
2034 let (reg, h) = point_registry();
2035 let alias =
2036 TypeObjectBuilder::alias("::PointAlias", TypeIdentifier::EquivalenceHashComplete(h))
2037 .build_complete();
2038 let to = TypeObject::Complete(CompleteTypeObject::Alias(alias));
2039 let dt = DynamicTypeBuilderFactory::create_type_w_type_object_in(&to, ®).unwrap();
2040 assert_eq!(
2041 dt.kind(),
2042 TypeKind::Structure,
2043 "alias resolved transparently to its target"
2044 );
2045 assert_eq!(dt.member_count(), 2);
2046 assert!(dt.member_by_name("x").is_some());
2047
2048 let scalar_alias =
2050 TypeObjectBuilder::alias("::Id", TypeIdentifier::Primitive(PrimitiveKind::Int32))
2051 .build_complete();
2052 let sto = TypeObject::Complete(CompleteTypeObject::Alias(scalar_alias));
2053 let sdt = DynamicTypeBuilderFactory::create_type_w_type_object_in(&sto, ®).unwrap();
2054 assert_eq!(
2055 sdt.kind(),
2056 TypeKind::Alias,
2057 "scalar typedef stays an alias node"
2058 );
2059 }
2060}