1use alloc::format;
27use alloc::string::{String, ToString};
28use alloc::vec::Vec;
29
30use crate::type_identifier::{PrimitiveKind, TypeIdentifier};
31use crate::type_object::common::{CommonStructMember, CommonUnionMember};
32use crate::type_object::complete::{
33 CompleteAliasBody, CompleteAliasHeader, CompleteAliasType, CompleteAnnotationParameter,
34 CompleteAnnotationType, CompleteArrayType, CompleteBitfield, CompleteBitflag,
35 CompleteBitmaskType, CompleteBitsetType, CompleteCollectionElement,
36 CompleteDiscriminatorMember, CompleteEnumeratedHeader, CompleteEnumeratedLiteral,
37 CompleteEnumeratedType, CompleteMapType, CompleteSequenceType, CompleteStructHeader,
38 CompleteStructMember, CompleteStructType, CompleteUnionHeader, CompleteUnionMember,
39 CompleteUnionType,
40};
41use crate::type_object::flags::{
42 AliasMemberFlag, AliasTypeFlag, AnnotationParameterFlag, AnnotationTypeFlag, BitfieldFlag,
43 BitflagFlag, BitmaskTypeFlag, BitsetTypeFlag, CollectionElementFlag, CollectionTypeFlag,
44 EnumLiteralFlag, EnumTypeFlag, StructMemberFlag, StructTypeFlag, UnionDiscriminatorFlag,
45 UnionMemberFlag, UnionTypeFlag,
46};
47use crate::type_object::minimal::CommonDiscriminatorMember;
48use crate::type_object::minimal::{
49 CommonBitfield, CommonBitflag, CommonCollectionElement, CommonEnumeratedHeader,
50 CommonEnumeratedLiteral,
51};
52use crate::type_object::{CompleteTypeObject, TypeObject};
53
54use super::builder::{DynamicTypeBuilder, DynamicTypeBuilderFactory};
55use super::descriptor::{ExtensibilityKind, MemberDescriptor, TypeDescriptor, TypeKind};
56use super::error::DynamicError;
57use super::type_::DynamicType;
58
59impl DynamicType {
64 pub fn to_type_object(&self) -> Result<TypeObject, DynamicError> {
76 match self.kind() {
77 TypeKind::Structure => Ok(TypeObject::Complete(CompleteTypeObject::Struct(
78 self.to_complete_struct()?,
79 ))),
80 TypeKind::Union => Ok(TypeObject::Complete(CompleteTypeObject::Union(
81 self.to_complete_union()?,
82 ))),
83 TypeKind::Enumeration => Ok(TypeObject::Complete(CompleteTypeObject::Enumerated(
84 self.to_complete_enum()?,
85 ))),
86 TypeKind::Bitmask => Ok(TypeObject::Complete(CompleteTypeObject::Bitmask(
87 self.to_complete_bitmask()?,
88 ))),
89 TypeKind::Alias => Ok(TypeObject::Complete(CompleteTypeObject::Alias(
90 self.to_complete_alias()?,
91 ))),
92 TypeKind::Sequence => Ok(TypeObject::Complete(CompleteTypeObject::Sequence(
93 self.to_complete_sequence()?,
94 ))),
95 TypeKind::Array => Ok(TypeObject::Complete(CompleteTypeObject::Array(
96 self.to_complete_array()?,
97 ))),
98 TypeKind::Map => Ok(TypeObject::Complete(CompleteTypeObject::Map(
99 self.to_complete_map()?,
100 ))),
101 TypeKind::Bitset => Ok(TypeObject::Complete(CompleteTypeObject::Bitset(
102 self.to_complete_bitset()?,
103 ))),
104 TypeKind::Annotation => Ok(TypeObject::Complete(CompleteTypeObject::Annotation(
105 self.to_complete_annotation()?,
106 ))),
107 other => Err(DynamicError::unsupported(format!(
108 "to_type_object: {other:?} is a primitive/no-type kind without TypeObject",
109 ))),
110 }
111 }
112
113 fn to_complete_sequence(&self) -> Result<CompleteSequenceType, DynamicError> {
116 use crate::type_object::common::{
117 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
118 };
119 let element = self
120 .descriptor()
121 .element_type
122 .as_ref()
123 .ok_or_else(|| DynamicError::inconsistent("sequence type missing element_type"))?;
124 let bound = self.descriptor().bound.first().copied().unwrap_or(0);
125 Ok(CompleteSequenceType {
126 collection_flag: CollectionTypeFlag(0),
127 bound,
128 detail: CompleteTypeDetail {
129 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
130 ann_custom: OptionalAppliedAnnotationSeq::default(),
131 type_name: self.descriptor().name.clone(),
132 },
133 element: complete_collection_element(element)?,
134 })
135 }
136
137 fn to_complete_array(&self) -> Result<CompleteArrayType, DynamicError> {
140 use crate::type_object::common::{
141 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
142 };
143 let element = self
144 .descriptor()
145 .element_type
146 .as_ref()
147 .ok_or_else(|| DynamicError::inconsistent("array type missing element_type"))?;
148 let bound_seq = self.descriptor().bound.clone();
149 if bound_seq.is_empty() {
150 return Err(DynamicError::inconsistent(
151 "array type missing dimensions (bound)",
152 ));
153 }
154 Ok(CompleteArrayType {
155 collection_flag: CollectionTypeFlag(0),
156 bound_seq,
157 detail: CompleteTypeDetail {
158 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
159 ann_custom: OptionalAppliedAnnotationSeq::default(),
160 type_name: self.descriptor().name.clone(),
161 },
162 element: complete_collection_element(element)?,
163 })
164 }
165
166 fn to_complete_map(&self) -> Result<CompleteMapType, DynamicError> {
169 use crate::type_object::common::{
170 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
171 };
172 let value =
173 self.descriptor().element_type.as_ref().ok_or_else(|| {
174 DynamicError::inconsistent("map type missing element_type (value)")
175 })?;
176 let key = self
177 .descriptor()
178 .key_element_type
179 .as_ref()
180 .ok_or_else(|| DynamicError::inconsistent("map type missing key_element_type"))?;
181 let bound = self.descriptor().bound.first().copied().unwrap_or(0);
182 Ok(CompleteMapType {
183 collection_flag: CollectionTypeFlag(0),
184 bound,
185 detail: CompleteTypeDetail {
186 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
187 ann_custom: OptionalAppliedAnnotationSeq::default(),
188 type_name: self.descriptor().name.clone(),
189 },
190 key: complete_collection_element(key)?,
191 element: complete_collection_element(value)?,
192 })
193 }
194
195 fn to_complete_alias(&self) -> Result<CompleteAliasType, DynamicError> {
196 use crate::type_object::common::{
197 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteTypeDetail,
198 OptionalAppliedAnnotationSeq,
199 };
200 let header = CompleteAliasHeader {
201 detail: CompleteTypeDetail {
202 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
203 ann_custom: OptionalAppliedAnnotationSeq::default(),
204 type_name: self.descriptor().name.clone(),
205 },
206 };
207 let element = self.descriptor().element_type.as_ref().ok_or_else(|| {
208 DynamicError::inconsistent("alias type missing element_type (target)")
209 })?;
210 let related_type = descriptor_to_type_identifier(element)?;
211 let body = CompleteAliasBody {
212 related_flags: AliasMemberFlag(0),
213 related_type,
214 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
215 ann_custom: OptionalAppliedAnnotationSeq::default(),
216 };
217 Ok(CompleteAliasType {
218 alias_flags: AliasTypeFlag(0),
219 header,
220 body,
221 })
222 }
223
224 fn to_complete_enum(&self) -> Result<CompleteEnumeratedType, DynamicError> {
225 use crate::type_object::common::{
226 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
227 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
228 };
229 let bit_bound = self.descriptor().bound.first().copied().unwrap_or(32);
230 let bit_bound_u16 = u16::try_from(bit_bound).unwrap_or(32);
231 let header = CompleteEnumeratedHeader {
232 common: CommonEnumeratedHeader {
233 bit_bound: bit_bound_u16,
234 },
235 detail: CompleteTypeDetail {
236 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
237 ann_custom: OptionalAppliedAnnotationSeq::default(),
238 type_name: self.descriptor().name.clone(),
239 },
240 };
241 let mut literal_seq: Vec<CompleteEnumeratedLiteral> =
242 Vec::with_capacity(self.member_count() as usize);
243 for m in self.members() {
244 let mut flags_bits: u16 = 0;
245 if m.descriptor().is_default_label {
246 flags_bits |= EnumLiteralFlag::IS_DEFAULT_LITERAL;
247 }
248 let value = i32::try_from(m.id()).map_err(|_| {
250 DynamicError::inconsistent(format!("enum literal id {} exceeds i32 range", m.id()))
251 })?;
252 literal_seq.push(CompleteEnumeratedLiteral {
253 common: CommonEnumeratedLiteral {
254 value,
255 flags: EnumLiteralFlag(flags_bits),
256 },
257 detail: CompleteMemberDetail {
258 name: m.name().to_string(),
259 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
260 ann_custom: OptionalAppliedAnnotationSeq::default(),
261 },
262 });
263 }
264 Ok(CompleteEnumeratedType {
265 enum_flags: EnumTypeFlag(0),
266 header,
267 literal_seq,
268 })
269 }
270
271 fn to_complete_bitmask(&self) -> Result<CompleteBitmaskType, DynamicError> {
272 use crate::type_object::common::{
273 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
274 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
275 };
276 let bit_bound = self.descriptor().bound.first().copied().unwrap_or(32);
277 let bit_bound_u16 = u16::try_from(bit_bound).unwrap_or(32);
278 let detail = CompleteTypeDetail {
279 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
280 ann_custom: OptionalAppliedAnnotationSeq::default(),
281 type_name: self.descriptor().name.clone(),
282 };
283 let mut flag_seq: Vec<CompleteBitflag> = Vec::with_capacity(self.member_count() as usize);
284 for m in self.members() {
285 let position = u16::try_from(m.id()).map_err(|_| {
286 DynamicError::inconsistent(format!(
287 "bitmask flag position {} exceeds u16 range",
288 m.id()
289 ))
290 })?;
291 flag_seq.push(CompleteBitflag {
292 common: CommonBitflag {
293 position,
294 flags: BitflagFlag(0),
295 },
296 detail: CompleteMemberDetail {
297 name: m.name().to_string(),
298 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
299 ann_custom: OptionalAppliedAnnotationSeq::default(),
300 },
301 });
302 }
303 Ok(CompleteBitmaskType {
304 bitmask_flags: BitmaskTypeFlag(0),
305 bit_bound: bit_bound_u16,
306 detail,
307 flag_seq,
308 })
309 }
310
311 fn to_complete_bitset(&self) -> Result<CompleteBitsetType, DynamicError> {
316 use crate::type_object::common::{
317 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
318 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
319 };
320 let detail = CompleteTypeDetail {
321 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
322 ann_custom: OptionalAppliedAnnotationSeq::default(),
323 type_name: self.descriptor().name.clone(),
324 };
325 let mut field_seq: Vec<CompleteBitfield> = Vec::with_capacity(self.member_count() as usize);
326 for m in self.members() {
327 let position = u16::try_from(m.id()).map_err(|_| {
328 DynamicError::inconsistent(format!(
329 "bitset field position {} exceeds u16 range",
330 m.id()
331 ))
332 })?;
333 let holder_type = match descriptor_to_type_identifier(
334 m.descriptor().member_type.as_ref(),
335 )? {
336 TypeIdentifier::Primitive(pk) => pk.to_u8(),
337 other => {
338 return Err(DynamicError::inconsistent(format!(
339 "bitset field {:?} holder must be a primitive integer type, got {other:?}",
340 m.name()
341 )));
342 }
343 };
344 let bitcount = m.descriptor().bit_bound.ok_or_else(|| {
345 DynamicError::inconsistent(format!(
346 "bitset field {:?} missing bit_bound (bitfield width)",
347 m.name()
348 ))
349 })?;
350 field_seq.push(CompleteBitfield {
351 common: CommonBitfield {
352 position,
353 flags: BitfieldFlag(0),
354 bitcount,
355 holder_type,
356 },
357 detail: CompleteMemberDetail {
358 name: m.name().to_string(),
359 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
360 ann_custom: OptionalAppliedAnnotationSeq::default(),
361 },
362 });
363 }
364 Ok(CompleteBitsetType {
365 bitset_flags: BitsetTypeFlag(0),
366 detail,
367 field_seq,
368 })
369 }
370
371 fn to_complete_annotation(&self) -> Result<CompleteAnnotationType, DynamicError> {
376 use crate::type_object::common::{
377 AppliedBuiltinTypeAnnotations, CompleteTypeDetail, OptionalAppliedAnnotationSeq,
378 };
379 let detail = CompleteTypeDetail {
380 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
381 ann_custom: OptionalAppliedAnnotationSeq::default(),
382 type_name: self.descriptor().name.clone(),
383 };
384 let mut member_seq: Vec<CompleteAnnotationParameter> =
385 Vec::with_capacity(self.member_count() as usize);
386 for m in self.members() {
387 let member_type_id =
388 descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?;
389 let default_value = m
390 .descriptor()
391 .default_value
392 .as_deref()
393 .map(|s| s.as_bytes().to_vec())
394 .unwrap_or_default();
395 member_seq.push(CompleteAnnotationParameter {
396 member_id: m.id(),
397 member_flags: AnnotationParameterFlag(0),
398 member_type_id,
399 name: m.name().to_string(),
400 default_value,
401 });
402 }
403 Ok(CompleteAnnotationType {
404 annotation_flag: AnnotationTypeFlag(0),
405 detail,
406 member_seq,
407 })
408 }
409
410 fn to_complete_union(&self) -> Result<CompleteUnionType, DynamicError> {
411 use crate::type_object::common::{
412 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
413 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
414 };
415 let union_flags = UnionTypeFlag(extensibility_to_flag_bits(
416 self.descriptor().extensibility_kind,
417 ));
418 let header = CompleteUnionHeader {
419 detail: CompleteTypeDetail {
420 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
421 ann_custom: OptionalAppliedAnnotationSeq::default(),
422 type_name: self.descriptor().name.clone(),
423 },
424 };
425 let disc_descriptor = self
426 .descriptor()
427 .discriminator_type
428 .as_ref()
429 .ok_or_else(|| DynamicError::inconsistent("union type missing discriminator_type"))?;
430 let disc_type = descriptor_to_type_identifier(disc_descriptor)?;
431 let discriminator = CompleteDiscriminatorMember {
432 common: CommonDiscriminatorMember {
433 member_flags: UnionDiscriminatorFlag(0),
434 type_id: disc_type,
435 },
436 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
437 ann_custom: OptionalAppliedAnnotationSeq::default(),
438 };
439 let mut member_seq: Vec<CompleteUnionMember> =
440 Vec::with_capacity(self.member_count() as usize);
441 for m in self.members() {
442 let mut flags_bits: u16 = 0;
443 if m.descriptor().is_default_label {
444 flags_bits |= UnionMemberFlag::IS_DEFAULT;
445 }
446 let label_seq: Vec<i32> = m
448 .descriptor()
449 .label
450 .iter()
451 .map(|&v| i32::try_from(v).unwrap_or_default())
452 .collect();
453 let common = CommonUnionMember {
454 member_id: m.id(),
455 member_flags: UnionMemberFlag(flags_bits),
456 type_id: descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?,
457 label_seq,
458 };
459 let detail = CompleteMemberDetail {
460 name: m.name().to_string(),
461 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
462 ann_custom: OptionalAppliedAnnotationSeq::default(),
463 };
464 member_seq.push(CompleteUnionMember { common, detail });
465 }
466 Ok(CompleteUnionType {
467 union_flags,
468 header,
469 discriminator,
470 member_seq,
471 })
472 }
473
474 fn to_complete_struct(&self) -> Result<CompleteStructType, DynamicError> {
475 use crate::type_object::common::{
476 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
477 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
478 };
479 let struct_flags = StructTypeFlag(extensibility_to_flag_bits(
480 self.descriptor().extensibility_kind,
481 ));
482 let header = CompleteStructHeader {
483 base_type: TypeIdentifier::None,
484 detail: CompleteTypeDetail {
485 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
486 ann_custom: OptionalAppliedAnnotationSeq::default(),
487 type_name: self.descriptor().name.clone(),
488 },
489 };
490 let mut member_seq: Vec<CompleteStructMember> =
491 Vec::with_capacity(self.member_count() as usize);
492 for m in self.members() {
493 let mut flags_bits: u16 = 0;
494 if m.descriptor().is_key {
495 flags_bits |= StructMemberFlag::IS_KEY;
496 }
497 if m.descriptor().is_optional {
498 flags_bits |= StructMemberFlag::IS_OPTIONAL;
499 }
500 if m.descriptor().is_must_understand {
501 flags_bits |= StructMemberFlag::IS_MUST_UNDERSTAND;
502 }
503 if m.descriptor().is_shared {
504 flags_bits |= StructMemberFlag::IS_EXTERNAL;
505 }
506 let common = CommonStructMember {
507 member_id: m.id(),
508 member_flags: StructMemberFlag(flags_bits),
509 member_type_id: descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?,
510 };
511 let detail = CompleteMemberDetail {
512 name: m.name().to_string(),
513 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
514 ann_custom: OptionalAppliedAnnotationSeq::default(),
515 };
516 member_seq.push(CompleteStructMember { common, detail });
517 }
518 Ok(CompleteStructType {
519 struct_flags,
520 header,
521 member_seq,
522 })
523 }
524}
525
526const fn extensibility_to_flag_bits(ext: ExtensibilityKind) -> u16 {
527 match ext {
528 ExtensibilityKind::Final => StructTypeFlag::IS_FINAL,
529 ExtensibilityKind::Appendable => StructTypeFlag::IS_APPENDABLE,
530 ExtensibilityKind::Mutable => StructTypeFlag::IS_MUTABLE,
531 }
532}
533
534const fn flag_bits_to_extensibility(flags: u16) -> ExtensibilityKind {
535 if flags & StructTypeFlag::IS_FINAL != 0 {
536 ExtensibilityKind::Final
537 } else if flags & StructTypeFlag::IS_MUTABLE != 0 {
538 ExtensibilityKind::Mutable
539 } else {
540 ExtensibilityKind::Appendable
541 }
542}
543
544fn complete_collection_element(
547 desc: &TypeDescriptor,
548) -> Result<CompleteCollectionElement, DynamicError> {
549 use crate::type_object::common::{
550 AppliedBuiltinMemberAnnotations, OptionalAppliedAnnotationSeq,
551 };
552 Ok(CompleteCollectionElement {
553 common: CommonCollectionElement {
554 element_flags: CollectionElementFlag(0),
555 type_id: descriptor_to_type_identifier(desc)?,
556 },
557 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
558 ann_custom: OptionalAppliedAnnotationSeq::default(),
559 })
560}
561
562fn descriptor_to_type_identifier(desc: &TypeDescriptor) -> Result<TypeIdentifier, DynamicError> {
567 match desc.kind {
568 TypeKind::Boolean => Ok(TypeIdentifier::Primitive(PrimitiveKind::Boolean)),
569 TypeKind::Byte => Ok(TypeIdentifier::Primitive(PrimitiveKind::Byte)),
570 TypeKind::Int8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int8)),
571 TypeKind::UInt8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt8)),
572 TypeKind::Int16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int16)),
573 TypeKind::UInt16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt16)),
574 TypeKind::Int32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int32)),
575 TypeKind::UInt32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt32)),
576 TypeKind::Int64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int64)),
577 TypeKind::UInt64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt64)),
578 TypeKind::Float32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float32)),
579 TypeKind::Float64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float64)),
580 TypeKind::Float128 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float128)),
581 TypeKind::Char8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Char8)),
582 TypeKind::Char16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Char16)),
583 TypeKind::String8 => {
584 let bound = desc.bound.first().copied().unwrap_or(0);
585 if bound <= u32::from(u8::MAX) {
586 Ok(TypeIdentifier::String8Small { bound: bound as u8 })
587 } else {
588 Ok(TypeIdentifier::String8Large { bound })
589 }
590 }
591 TypeKind::String16 => {
592 let bound = desc.bound.first().copied().unwrap_or(0);
593 if bound <= u32::from(u8::MAX) {
594 Ok(TypeIdentifier::String16Small { bound: bound as u8 })
595 } else {
596 Ok(TypeIdentifier::String16Large { bound })
597 }
598 }
599 TypeKind::Structure | TypeKind::Union | TypeKind::Enumeration | TypeKind::Alias => {
600 Ok(TypeIdentifier::None)
605 }
606 kind => Err(DynamicError::unsupported(format!(
607 "descriptor_to_type_identifier: {kind:?} not yet covered"
608 ))),
609 }
610}
611
612impl DynamicTypeBuilderFactory {
617 pub fn create_type_w_type_object(
627 type_obj: &TypeObject,
628 ) -> Result<DynamicTypeBuilder, DynamicError> {
629 match type_obj {
630 TypeObject::Complete(c) => match c {
631 CompleteTypeObject::Struct(s) => complete_struct_to_builder(s),
632 other => Err(DynamicError::unsupported(format!(
633 "complete-typeobject kind {} not yet supported",
634 other_kind_name(other)
635 ))),
636 },
637 TypeObject::Minimal(_) => Err(DynamicError::unsupported(
638 "minimal-typeobject → dynamic-type pending C4.2 TypeRegistry",
639 )),
640 }
641 }
642
643 pub fn create_type_w_type_object_in(
660 type_obj: &TypeObject,
661 registry: &crate::resolve::TypeRegistry,
662 ) -> Result<DynamicType, DynamicError> {
663 match type_obj {
664 TypeObject::Complete(c) => resolve_complete(c, registry),
665 TypeObject::Minimal(_) => Err(DynamicError::unsupported(
666 "minimal-typeobject → dynamic-type pending C4.2 TypeRegistry",
667 )),
668 }
669 }
670}
671
672fn resolve_type_id(
678 ti: &TypeIdentifier,
679 registry: &crate::resolve::TypeRegistry,
680) -> Result<DynamicType, DynamicError> {
681 use super::builder::DynamicTypeBuilderFactory as F;
682 match ti {
683 TypeIdentifier::Primitive(p) => {
684 let kind = primitive_kind_to_type_kind(*p);
685 F::get_primitive_type(kind)
686 }
687 TypeIdentifier::String8Small { bound } => Ok(F::create_string_type(u32::from(*bound))),
688 TypeIdentifier::String8Large { bound } => Ok(F::create_string_type(*bound)),
689 TypeIdentifier::String16Small { bound } => Ok(F::create_wstring_type(u32::from(*bound))),
690 TypeIdentifier::String16Large { bound } => Ok(F::create_wstring_type(*bound)),
691 TypeIdentifier::PlainSequenceSmall { .. }
694 | TypeIdentifier::PlainSequenceLarge { .. }
695 | TypeIdentifier::PlainArraySmall { .. }
696 | TypeIdentifier::PlainArrayLarge { .. }
697 | TypeIdentifier::PlainMapSmall { .. }
698 | TypeIdentifier::PlainMapLarge { .. } => {
699 let kind = type_id_to_kind(ti)?;
700 let desc = type_id_to_descriptor(ti, kind)?;
701 F::create_type(desc)?.build()
702 }
703 TypeIdentifier::EquivalenceHashComplete(h) => {
704 let c = registry.get_complete(h).ok_or_else(|| {
705 DynamicError::unsupported("composite member: EquivalenceHash not in TypeRegistry")
706 })?;
707 resolve_complete(c, registry)
708 }
709 TypeIdentifier::EquivalenceHashMinimal(_) => Err(DynamicError::unsupported(
710 "minimal composite member → dynamic-type pending C4.2",
711 )),
712 other => Err(DynamicError::unsupported(format!(
713 "resolve_type_id: {other:?} not yet supported"
714 ))),
715 }
716}
717
718fn resolve_complete(
722 c: &CompleteTypeObject,
723 registry: &crate::resolve::TypeRegistry,
724) -> Result<DynamicType, DynamicError> {
725 use super::builder::DynamicTypeBuilderFactory as F;
726 match c {
727 CompleteTypeObject::Struct(s) => complete_struct_to_builder_in(s, registry)?.build(),
728 CompleteTypeObject::Union(u) => {
729 let disc_kind = type_id_to_kind(&u.discriminator.common.type_id)?;
730 let disc_desc = type_id_to_descriptor(&u.discriminator.common.type_id, disc_kind)?;
731 let mut b = F::create_type(TypeDescriptor::union(
732 u.header.detail.type_name.clone(),
733 disc_desc,
734 ))?;
735 for m in &u.member_seq {
736 let mt = resolve_type_id(&m.common.type_id, registry)?;
737 let mut md = MemberDescriptor::new(
738 m.detail.name.clone(),
739 m.common.member_id,
740 mt.descriptor().clone(),
741 );
742 md.label = m.common.label_seq.iter().map(|&v| i64::from(v)).collect();
743 md.is_default_label = (m.common.member_flags.0 & UnionMemberFlag::IS_DEFAULT) != 0;
744 b.add_member_resolved(md, mt)?;
745 }
746 b.build()
747 }
748 CompleteTypeObject::Enumerated(e) => {
749 let mut desc = TypeDescriptor::enumeration(e.header.detail.type_name.clone());
750 desc.bound = alloc::vec![u32::from(e.header.common.bit_bound)];
751 let mut b = F::create_type(desc)?;
752 for lit in &e.literal_seq {
753 let id = u32::try_from(lit.common.value).unwrap_or(0);
754 let mut md = MemberDescriptor::new(
755 lit.detail.name.clone(),
756 id,
757 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
758 );
759 md.is_default_label =
760 (lit.common.flags.0 & EnumLiteralFlag::IS_DEFAULT_LITERAL) != 0;
761 b.add_member(md)?;
762 }
763 b.build()
764 }
765 CompleteTypeObject::Bitmask(bm) => {
766 let mut desc = bare_descriptor(TypeKind::Bitmask, bm.detail.type_name.clone());
767 desc.bound = alloc::vec![u32::from(bm.bit_bound)];
768 let mut b = F::create_type(desc)?;
769 for f in &bm.flag_seq {
770 let md = MemberDescriptor::new(
771 f.detail.name.clone(),
772 u32::from(f.common.position),
773 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
774 );
775 b.add_member(md)?;
776 }
777 b.build()
778 }
779 CompleteTypeObject::Bitset(bs) => {
780 let desc = bare_descriptor(TypeKind::Bitset, bs.detail.type_name.clone());
781 let mut b = F::create_type(desc)?;
782 for f in &bs.field_seq {
783 let holder = PrimitiveKind::from_u8(f.common.holder_type).ok_or_else(|| {
784 DynamicError::inconsistent(format!(
785 "bitset field holder_type {} is not a primitive",
786 f.common.holder_type
787 ))
788 })?;
789 let mut md = MemberDescriptor::new(
790 f.detail.name.clone(),
791 u32::from(f.common.position),
792 TypeDescriptor::primitive(primitive_kind_to_type_kind(holder), "holder"),
793 );
794 md.bit_bound = Some(f.common.bitcount);
795 b.add_member(md)?;
796 }
797 b.build()
798 }
799 CompleteTypeObject::Alias(a) => {
800 let target_kind = type_id_to_kind(&a.body.related_type)?;
803 let target = type_id_to_descriptor(&a.body.related_type, target_kind)?;
804 let mut desc = bare_descriptor(TypeKind::Alias, a.header.detail.type_name.clone());
805 desc.element_type = Some(alloc::boxed::Box::new(target));
806 F::create_type(desc)?.build()
807 }
808 CompleteTypeObject::Sequence(_)
809 | CompleteTypeObject::Array(_)
810 | CompleteTypeObject::Map(_) => {
811 resolve_named_collection(c)
814 }
815 CompleteTypeObject::Annotation(an) => {
816 let desc = bare_descriptor(TypeKind::Annotation, an.detail.type_name.clone());
817 let mut b = F::create_type(desc)?;
818 for m in &an.member_seq {
819 let mk = type_id_to_kind(&m.member_type_id)?;
820 let mt = type_id_to_descriptor(&m.member_type_id, mk)?;
821 let mut md = MemberDescriptor::new(m.name.clone(), m.member_id, mt);
822 if !m.default_value.is_empty() {
823 md.default_value = Some(String::from_utf8_lossy(&m.default_value).into_owned());
824 }
825 b.add_member(md)?;
826 }
827 b.build()
828 }
829 }
830}
831
832fn complete_struct_to_builder_in(
836 s: &CompleteStructType,
837 registry: &crate::resolve::TypeRegistry,
838) -> Result<DynamicTypeBuilder, DynamicError> {
839 let mut desc = TypeDescriptor::structure(s.header.detail.type_name.clone());
840 desc.extensibility_kind = flag_bits_to_extensibility(s.struct_flags.0);
841 if (s.struct_flags.0 & StructTypeFlag::IS_NESTED) != 0 {
842 desc.is_nested = true;
843 }
844 let mut b = DynamicTypeBuilderFactory::create_type(desc)?;
845 for (idx, m) in s.member_seq.iter().enumerate() {
846 let mt = resolve_type_id(&m.common.member_type_id, registry)?;
847 let mut md = MemberDescriptor::new(
848 m.detail.name.clone(),
849 m.common.member_id,
850 mt.descriptor().clone(),
851 );
852 md.index = u32::try_from(idx).unwrap_or(u32::MAX);
853 md.is_key = (m.common.member_flags.0 & StructMemberFlag::IS_KEY) != 0;
854 md.is_optional = (m.common.member_flags.0 & StructMemberFlag::IS_OPTIONAL) != 0;
855 md.is_must_understand =
856 (m.common.member_flags.0 & StructMemberFlag::IS_MUST_UNDERSTAND) != 0;
857 md.is_shared = (m.common.member_flags.0 & StructMemberFlag::IS_EXTERNAL) != 0;
858 b.add_member_resolved(md, mt)?;
859 }
860 Ok(b)
861}
862
863fn resolve_named_collection(c: &CompleteTypeObject) -> Result<DynamicType, DynamicError> {
866 use super::builder::DynamicTypeBuilderFactory as F;
867 let desc = match c {
868 CompleteTypeObject::Sequence(s) => {
869 let ek = type_id_to_kind(&s.element.common.type_id)?;
870 let ed = type_id_to_descriptor(&s.element.common.type_id, ek)?;
871 TypeDescriptor::sequence(s.detail.type_name.clone(), ed, s.bound)
872 }
873 CompleteTypeObject::Array(a) => {
874 let ek = type_id_to_kind(&a.element.common.type_id)?;
875 let ed = type_id_to_descriptor(&a.element.common.type_id, ek)?;
876 TypeDescriptor::array(a.detail.type_name.clone(), ed, a.bound_seq.clone())
877 }
878 CompleteTypeObject::Map(m) => {
879 let kk = type_id_to_kind(&m.key.common.type_id)?;
880 let kd = type_id_to_descriptor(&m.key.common.type_id, kk)?;
881 let vk = type_id_to_kind(&m.element.common.type_id)?;
882 let vd = type_id_to_descriptor(&m.element.common.type_id, vk)?;
883 TypeDescriptor::map(m.detail.type_name.clone(), kd, vd, m.bound)
884 }
885 other => {
886 return Err(DynamicError::unsupported(format!(
887 "resolve_named_collection called on non-collection: {other:?}"
888 )));
889 }
890 };
891 F::create_type(desc)?.build()
892}
893
894fn bare_descriptor(kind: TypeKind, name: impl Into<String>) -> TypeDescriptor {
899 TypeDescriptor {
900 kind,
901 name: name.into(),
902 base_type: None,
903 discriminator_type: None,
904 bound: Vec::new(),
905 element_type: None,
906 key_element_type: None,
907 extensibility_kind: ExtensibilityKind::default(),
908 is_nested: false,
909 }
910}
911
912fn complete_struct_to_builder(s: &CompleteStructType) -> Result<DynamicTypeBuilder, DynamicError> {
913 let mut desc = TypeDescriptor::structure(s.header.detail.type_name.clone());
914 desc.extensibility_kind = flag_bits_to_extensibility(s.struct_flags.0);
915 if (s.struct_flags.0 & StructTypeFlag::IS_NESTED) != 0 {
916 desc.is_nested = true;
917 }
918 let mut b = DynamicTypeBuilderFactory::create_type(desc)?;
919 for (idx, m) in s.member_seq.iter().enumerate() {
920 let kind = type_id_to_kind(&m.common.member_type_id)?;
921 let member_type = type_id_to_descriptor(&m.common.member_type_id, kind)?;
922 let mut md = MemberDescriptor::new(m.detail.name.clone(), m.common.member_id, member_type);
923 md.index = u32::try_from(idx).unwrap_or(u32::MAX);
924 md.is_key = (m.common.member_flags.0 & StructMemberFlag::IS_KEY) != 0;
925 md.is_optional = (m.common.member_flags.0 & StructMemberFlag::IS_OPTIONAL) != 0;
926 md.is_must_understand =
927 (m.common.member_flags.0 & StructMemberFlag::IS_MUST_UNDERSTAND) != 0;
928 md.is_shared = (m.common.member_flags.0 & StructMemberFlag::IS_EXTERNAL) != 0;
929 b.add_member(md)?;
930 }
931 Ok(b)
932}
933
934const fn other_kind_name(c: &CompleteTypeObject) -> &'static str {
935 match c {
936 CompleteTypeObject::Alias(_) => "alias",
937 CompleteTypeObject::Annotation(_) => "annotation",
938 CompleteTypeObject::Struct(_) => "struct",
939 CompleteTypeObject::Union(_) => "union",
940 CompleteTypeObject::Bitset(_) => "bitset",
941 CompleteTypeObject::Sequence(_) => "sequence",
942 CompleteTypeObject::Array(_) => "array",
943 CompleteTypeObject::Map(_) => "map",
944 CompleteTypeObject::Enumerated(_) => "enum",
945 CompleteTypeObject::Bitmask(_) => "bitmask",
946 }
947}
948
949fn type_id_to_kind(ti: &TypeIdentifier) -> Result<TypeKind, DynamicError> {
950 Ok(match ti {
951 TypeIdentifier::None => TypeKind::NoType,
952 TypeIdentifier::Primitive(p) => primitive_kind_to_type_kind(*p),
953 TypeIdentifier::String8Small { .. } | TypeIdentifier::String8Large { .. } => {
954 TypeKind::String8
955 }
956 TypeIdentifier::String16Small { .. } | TypeIdentifier::String16Large { .. } => {
957 TypeKind::String16
958 }
959 TypeIdentifier::PlainSequenceSmall { .. } | TypeIdentifier::PlainSequenceLarge { .. } => {
960 TypeKind::Sequence
961 }
962 TypeIdentifier::PlainArraySmall { .. } | TypeIdentifier::PlainArrayLarge { .. } => {
963 TypeKind::Array
964 }
965 TypeIdentifier::PlainMapSmall { .. } | TypeIdentifier::PlainMapLarge { .. } => {
966 TypeKind::Map
967 }
968 TypeIdentifier::EquivalenceHashMinimal(_) | TypeIdentifier::EquivalenceHashComplete(_) => {
969 TypeKind::Structure
972 }
973 other => {
974 return Err(DynamicError::unsupported(format!(
975 "type_id_to_kind: {other:?} not yet supported"
976 )));
977 }
978 })
979}
980
981const fn primitive_kind_to_type_kind(p: PrimitiveKind) -> TypeKind {
982 match p {
983 PrimitiveKind::Boolean => TypeKind::Boolean,
984 PrimitiveKind::Byte => TypeKind::Byte,
985 PrimitiveKind::Int8 => TypeKind::Int8,
986 PrimitiveKind::UInt8 => TypeKind::UInt8,
987 PrimitiveKind::Int16 => TypeKind::Int16,
988 PrimitiveKind::UInt16 => TypeKind::UInt16,
989 PrimitiveKind::Int32 => TypeKind::Int32,
990 PrimitiveKind::UInt32 => TypeKind::UInt32,
991 PrimitiveKind::Int64 => TypeKind::Int64,
992 PrimitiveKind::UInt64 => TypeKind::UInt64,
993 PrimitiveKind::Float32 => TypeKind::Float32,
994 PrimitiveKind::Float64 => TypeKind::Float64,
995 PrimitiveKind::Float128 => TypeKind::Float128,
996 PrimitiveKind::Char8 => TypeKind::Char8,
997 PrimitiveKind::Char16 => TypeKind::Char16,
998 }
999}
1000
1001fn type_id_to_descriptor(
1008 ti: &TypeIdentifier,
1009 kind: TypeKind,
1010) -> Result<TypeDescriptor, DynamicError> {
1011 if kind.is_primitive() {
1012 return Ok(TypeDescriptor::primitive(
1013 kind,
1014 super::type_::primitive_name(kind).to_string(),
1015 ));
1016 }
1017 Ok(match ti {
1018 TypeIdentifier::String8Small { bound } => TypeDescriptor::string8(u32::from(*bound)),
1019 TypeIdentifier::String8Large { bound } => TypeDescriptor::string8(*bound),
1020 TypeIdentifier::String16Small { bound } => TypeDescriptor::string16(u32::from(*bound)),
1021 TypeIdentifier::String16Large { bound } => TypeDescriptor::string16(*bound),
1022 TypeIdentifier::None => TypeDescriptor {
1023 kind: TypeKind::Structure,
1024 name: String::from("<unresolved>"),
1025 base_type: None,
1026 discriminator_type: None,
1027 bound: Vec::new(),
1028 element_type: None,
1029 key_element_type: None,
1030 extensibility_kind: ExtensibilityKind::default(),
1031 is_nested: false,
1032 },
1033 TypeIdentifier::EquivalenceHashMinimal(_) | TypeIdentifier::EquivalenceHashComplete(_) => {
1034 TypeDescriptor {
1037 kind: TypeKind::Structure,
1038 name: String::from("<typeref>"),
1039 base_type: None,
1040 discriminator_type: None,
1041 bound: Vec::new(),
1042 element_type: None,
1043 key_element_type: None,
1044 extensibility_kind: ExtensibilityKind::default(),
1045 is_nested: false,
1046 }
1047 }
1048 TypeIdentifier::PlainSequenceSmall { bound, element, .. } => {
1049 let elem_kind = type_id_to_kind(element)?;
1050 TypeDescriptor::sequence(
1051 "<seq>".to_string(),
1052 type_id_to_descriptor(element, elem_kind)?,
1053 u32::from(*bound),
1054 )
1055 }
1056 TypeIdentifier::PlainSequenceLarge { bound, element, .. } => {
1057 let elem_kind = type_id_to_kind(element)?;
1058 TypeDescriptor::sequence(
1059 "<seq>".to_string(),
1060 type_id_to_descriptor(element, elem_kind)?,
1061 *bound,
1062 )
1063 }
1064 TypeIdentifier::PlainArraySmall {
1065 array_bounds,
1066 element,
1067 ..
1068 } => {
1069 let elem_kind = type_id_to_kind(element)?;
1070 TypeDescriptor::array(
1071 "<arr>".to_string(),
1072 type_id_to_descriptor(element, elem_kind)?,
1073 array_bounds.iter().map(|b| u32::from(*b)).collect(),
1074 )
1075 }
1076 TypeIdentifier::PlainArrayLarge {
1077 array_bounds,
1078 element,
1079 ..
1080 } => {
1081 let elem_kind = type_id_to_kind(element)?;
1082 TypeDescriptor::array(
1083 "<arr>".to_string(),
1084 type_id_to_descriptor(element, elem_kind)?,
1085 array_bounds.clone(),
1086 )
1087 }
1088 other => {
1089 return Err(DynamicError::unsupported(format!(
1090 "type_id_to_descriptor: {other:?} not yet supported"
1091 )));
1092 }
1093 })
1094}
1095
1096#[cfg(test)]
1097#[allow(
1098 clippy::unwrap_used,
1099 clippy::expect_used,
1100 clippy::panic,
1101 clippy::unreachable
1102)]
1103mod tests {
1104 use super::*;
1105 use crate::dynamic::DynamicTypeBuilderFactory;
1106
1107 fn build_int_struct() -> DynamicType {
1108 let mut b = DynamicTypeBuilderFactory::create_struct("::Sensor");
1109 b.add_struct_member("id", 1, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
1110 .unwrap();
1111 b.add_struct_member(
1112 "temp",
1113 2,
1114 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1115 )
1116 .unwrap();
1117 b.add_struct_member("name", 3, TypeDescriptor::string8(64))
1118 .unwrap();
1119 b.build().unwrap()
1120 }
1121
1122 #[test]
1123 fn dynamic_struct_to_typeobject_complete() {
1124 let t = build_int_struct();
1125 let to = t.to_type_object().unwrap();
1126 match to {
1127 TypeObject::Complete(CompleteTypeObject::Struct(s)) => {
1128 assert_eq!(s.header.detail.type_name, "::Sensor");
1129 assert_eq!(s.member_seq.len(), 3);
1130 assert_eq!(s.member_seq[0].detail.name, "id");
1131 }
1132 _ => panic!("to_type_object on Structure must return Complete::Struct"),
1133 }
1134 }
1135
1136 #[test]
1137 fn typeobject_complete_struct_back_to_dynamic_type() {
1138 let t = build_int_struct();
1139 let to = t.to_type_object().unwrap();
1140 let b = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap();
1141 let t2 = b.build().unwrap();
1142 assert_eq!(t2.name(), "::Sensor");
1143 assert_eq!(t2.member_count(), 3);
1144 assert_eq!(t2.member_by_id(1).unwrap().name(), "id");
1145 assert_eq!(t2.member_by_id(2).unwrap().name(), "temp");
1146 assert_eq!(t2.member_by_id(3).unwrap().name(), "name");
1147 }
1148
1149 #[test]
1150 fn roundtrip_dynamic_to_typeobject_to_dynamic_equals_logically() {
1151 let t = build_int_struct();
1152 let to = t.to_type_object().unwrap();
1153 let b = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap();
1154 let t2 = b.build().unwrap();
1155 assert!(t.equals(&t2), "roundtrip failed: {t:?} vs {t2:?}");
1157 }
1158
1159 #[test]
1160 fn unsupported_kind_to_typeobject_yields_unsupported_error() {
1161 let prim = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
1162 let err = prim.to_type_object().unwrap_err();
1163 assert!(matches!(err, DynamicError::Unsupported(_)));
1164 }
1165
1166 #[test]
1167 fn dynamic_alias_to_typeobject_complete() {
1168 let mut desc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
1170 desc.kind = TypeKind::Alias;
1171 desc.name = "::SensorId".to_string();
1172 desc.element_type = Some(alloc::boxed::Box::new(TypeDescriptor::primitive(
1173 TypeKind::Int32,
1174 "int32",
1175 )));
1176 let t = DynamicTypeBuilderFactory::create_type(desc)
1177 .unwrap()
1178 .build()
1179 .unwrap();
1180 let to = t.to_type_object().expect("alias bridge ok");
1181 match to {
1182 TypeObject::Complete(CompleteTypeObject::Alias(a)) => {
1183 assert_eq!(a.header.detail.type_name, "::SensorId");
1184 assert!(matches!(a.body.related_type, TypeIdentifier::Primitive(_)));
1185 }
1186 other => panic!("expected Alias, got {other:?}"),
1187 }
1188 }
1189
1190 #[test]
1191 fn dynamic_enum_to_typeobject_complete() {
1192 let mut desc = TypeDescriptor::primitive(TypeKind::Enumeration, "::Color");
1193 desc.kind = TypeKind::Enumeration;
1194 desc.bound = alloc::vec![32];
1195 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1196 for (id, name) in [(0u32, "RED"), (1u32, "GREEN"), (2u32, "BLUE")] {
1197 let m = MemberDescriptor::new(
1198 name,
1199 id,
1200 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1201 );
1202 b.add_member(m).unwrap();
1203 }
1204 let t = b.build().unwrap();
1205 let to = t.to_type_object().expect("enum bridge ok");
1206 match to {
1207 TypeObject::Complete(CompleteTypeObject::Enumerated(e)) => {
1208 assert_eq!(e.literal_seq.len(), 3);
1209 assert_eq!(e.literal_seq[0].detail.name, "RED");
1210 assert_eq!(e.literal_seq[2].common.value, 2);
1211 }
1212 other => panic!("expected Enumerated, got {other:?}"),
1213 }
1214 }
1215
1216 #[test]
1217 fn dynamic_bitmask_to_typeobject_complete() {
1218 let mut desc = TypeDescriptor::primitive(TypeKind::Bitmask, "::Flags");
1219 desc.kind = TypeKind::Bitmask;
1220 desc.bound = alloc::vec![8];
1221 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1222 for (pos, name) in [(0u32, "A"), (3u32, "D"), (7u32, "H")] {
1223 let m = MemberDescriptor::new(
1224 name,
1225 pos,
1226 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
1227 );
1228 b.add_member(m).unwrap();
1229 }
1230 let t = b.build().unwrap();
1231 let to = t.to_type_object().expect("bitmask bridge ok");
1232 match to {
1233 TypeObject::Complete(CompleteTypeObject::Bitmask(bm)) => {
1234 assert_eq!(bm.bit_bound, 8);
1235 assert_eq!(bm.flag_seq.len(), 3);
1236 assert_eq!(bm.flag_seq[1].common.position, 3);
1237 }
1238 other => panic!("expected Bitmask, got {other:?}"),
1239 }
1240 }
1241
1242 #[test]
1243 fn dynamic_bitset_to_typeobject_complete() {
1244 let mut desc = TypeDescriptor::primitive(TypeKind::Bitset, "::Reg");
1245 desc.kind = TypeKind::Bitset;
1246 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1247 for (pos, name, width) in [(0u32, "lo", 3u8), (3u32, "hi", 5u8)] {
1248 let mut m = MemberDescriptor::new(
1249 name,
1250 pos,
1251 TypeDescriptor::primitive(TypeKind::UInt8, "uint8"),
1252 );
1253 m.bit_bound = Some(width);
1254 b.add_member(m).unwrap();
1255 }
1256 let t = b.build().unwrap();
1257 let to = t.to_type_object().expect("bitset bridge ok");
1258 match to {
1259 TypeObject::Complete(CompleteTypeObject::Bitset(bs)) => {
1260 assert_eq!(bs.field_seq.len(), 2);
1261 assert_eq!(bs.field_seq[0].common.position, 0);
1262 assert_eq!(bs.field_seq[0].common.bitcount, 3);
1263 assert_eq!(bs.field_seq[0].detail.name, "lo");
1264 assert_eq!(bs.field_seq[1].common.position, 3);
1265 assert_eq!(bs.field_seq[1].common.bitcount, 5);
1266 assert_eq!(
1267 bs.field_seq[1].common.holder_type,
1268 PrimitiveKind::UInt8.to_u8()
1269 );
1270 }
1271 other => panic!("expected Bitset, got {other:?}"),
1272 }
1273 }
1274
1275 #[test]
1276 fn dynamic_annotation_to_typeobject_complete() {
1277 let mut desc = TypeDescriptor::primitive(TypeKind::Annotation, "::Range");
1278 desc.kind = TypeKind::Annotation;
1279 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
1280 let mut m = MemberDescriptor::new(
1281 "max",
1282 1,
1283 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1284 );
1285 m.default_value = Some("100".into());
1286 b.add_member(m).unwrap();
1287 let t = b.build().unwrap();
1288 let to = t.to_type_object().expect("annotation bridge ok");
1289 match to {
1290 TypeObject::Complete(CompleteTypeObject::Annotation(a)) => {
1291 assert_eq!(a.member_seq.len(), 1);
1292 assert_eq!(a.member_seq[0].name, "max");
1293 assert_eq!(a.member_seq[0].member_id, 1);
1294 assert_eq!(a.member_seq[0].default_value, b"100".to_vec());
1295 assert!(matches!(
1296 a.member_seq[0].member_type_id,
1297 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1298 ));
1299 }
1300 other => panic!("expected Annotation, got {other:?}"),
1301 }
1302 }
1303
1304 #[test]
1305 fn dynamic_sequence_to_typeobject_complete() {
1306 let desc = TypeDescriptor::sequence(
1307 "::Seq",
1308 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1309 10,
1310 );
1311 let t = DynamicTypeBuilderFactory::create_type(desc)
1312 .unwrap()
1313 .build()
1314 .unwrap();
1315 match t.to_type_object().expect("sequence bridge ok") {
1316 TypeObject::Complete(CompleteTypeObject::Sequence(s)) => {
1317 assert_eq!(s.bound, 10);
1318 assert_eq!(s.detail.type_name, "::Seq");
1319 assert!(matches!(
1320 s.element.common.type_id,
1321 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1322 ));
1323 }
1324 other => panic!("expected Sequence, got {other:?}"),
1325 }
1326 }
1327
1328 #[test]
1329 fn dynamic_array_to_typeobject_complete() {
1330 let desc = TypeDescriptor::array(
1331 "::Arr",
1332 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1333 alloc::vec![3, 4],
1334 );
1335 let t = DynamicTypeBuilderFactory::create_type(desc)
1336 .unwrap()
1337 .build()
1338 .unwrap();
1339 match t.to_type_object().expect("array bridge ok") {
1340 TypeObject::Complete(CompleteTypeObject::Array(a)) => {
1341 assert_eq!(a.bound_seq, alloc::vec![3, 4]);
1342 assert!(matches!(
1343 a.element.common.type_id,
1344 TypeIdentifier::Primitive(PrimitiveKind::Float64)
1345 ));
1346 }
1347 other => panic!("expected Array, got {other:?}"),
1348 }
1349 }
1350
1351 #[test]
1352 fn dynamic_map_to_typeobject_complete() {
1353 let desc = TypeDescriptor::map(
1354 "::Map",
1355 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
1356 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
1357 7,
1358 );
1359 let t = DynamicTypeBuilderFactory::create_type(desc)
1360 .unwrap()
1361 .build()
1362 .unwrap();
1363 match t.to_type_object().expect("map bridge ok") {
1364 TypeObject::Complete(CompleteTypeObject::Map(m)) => {
1365 assert_eq!(m.bound, 7);
1366 assert!(matches!(
1367 m.key.common.type_id,
1368 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1369 ));
1370 assert!(matches!(
1371 m.element.common.type_id,
1372 TypeIdentifier::Primitive(PrimitiveKind::Boolean)
1373 ));
1374 }
1375 other => panic!("expected Map, got {other:?}"),
1376 }
1377 }
1378
1379 #[test]
1380 fn dynamic_union_to_typeobject_complete() {
1381 let disc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
1382 let t = {
1383 let mut b = DynamicTypeBuilderFactory::create_union("::Shape", disc).unwrap();
1384 let mut m1 = MemberDescriptor::new(
1385 "circle",
1386 1,
1387 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1388 );
1389 m1.label = alloc::vec![1];
1390 let mut m2 = MemberDescriptor::new(
1391 "square",
1392 2,
1393 TypeDescriptor::primitive(TypeKind::Float64, "double"),
1394 );
1395 m2.label = alloc::vec![2, 3];
1396 b.add_member(m1).unwrap();
1397 b.add_member(m2).unwrap();
1398 b.build().unwrap()
1399 };
1400 let to = t.to_type_object().expect("union bridge ok");
1401 match to {
1402 TypeObject::Complete(CompleteTypeObject::Union(u)) => {
1403 assert_eq!(u.member_seq.len(), 2);
1404 assert_eq!(u.member_seq[0].detail.name, "circle");
1405 assert_eq!(u.member_seq[1].common.label_seq, alloc::vec![2, 3]);
1406 assert!(matches!(
1407 u.discriminator.common.type_id,
1408 TypeIdentifier::Primitive(PrimitiveKind::Int32)
1409 ));
1410 }
1411 other => panic!("expected Union, got {other:?}"),
1412 }
1413 }
1414
1415 #[test]
1416 fn create_type_w_minimal_typeobject_is_unsupported() {
1417 use crate::type_object::MinimalTypeObject;
1418 use crate::type_object::minimal::{MinimalStructHeader, MinimalStructType};
1419 let m = MinimalStructType {
1420 struct_flags: StructTypeFlag::default(),
1421 header: MinimalStructHeader {
1422 base_type: TypeIdentifier::None,
1423 },
1424 member_seq: alloc::vec![],
1425 };
1426 let to = TypeObject::Minimal(MinimalTypeObject::Struct(m));
1427 let err = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap_err();
1428 assert!(matches!(err, DynamicError::Unsupported(_)));
1429 }
1430
1431 #[test]
1432 fn resolve_nested_struct_member_fully_via_registry() {
1433 use crate::builder::TypeObjectBuilder;
1434 use crate::resolve::TypeRegistry;
1435 use crate::type_identifier::EquivalenceHash;
1436
1437 let inner = TypeObjectBuilder::struct_type("::Point")
1439 .member("x", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1440 .member("y", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1441 .build_complete();
1442 let h = EquivalenceHash([0x42; 14]);
1443 let mut reg = TypeRegistry::new();
1444 reg.insert_complete(h, CompleteTypeObject::Struct(inner));
1445
1446 let outer = TypeObjectBuilder::struct_type("::Line")
1448 .member("start", TypeIdentifier::EquivalenceHashComplete(h), |m| m)
1449 .member(
1450 "len",
1451 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1452 |m| m,
1453 )
1454 .build_complete();
1455 let to = TypeObject::Complete(CompleteTypeObject::Struct(outer));
1456
1457 let dt = DynamicTypeBuilderFactory::create_type_w_type_object_in(&to, ®).unwrap();
1458 assert_eq!(dt.member_count(), 2);
1459 let start = dt.member_by_name("start").expect("start member");
1460 assert_eq!(start.dynamic_type().kind(), TypeKind::Structure);
1462 assert_eq!(start.dynamic_type().member_count(), 2);
1463 assert!(start.dynamic_type().member_by_name("x").is_some());
1464 assert!(start.dynamic_type().member_by_name("y").is_some());
1465 let dangling = TypeObjectBuilder::struct_type("::Bad")
1467 .member(
1468 "ref",
1469 TypeIdentifier::EquivalenceHashComplete(EquivalenceHash([0xFF; 14])),
1470 |m| m,
1471 )
1472 .build_complete();
1473 let bad = TypeObject::Complete(CompleteTypeObject::Struct(dangling));
1474 assert!(matches!(
1475 DynamicTypeBuilderFactory::create_type_w_type_object_in(&bad, ®),
1476 Err(DynamicError::Unsupported(_))
1477 ));
1478 }
1479}