1use alloc::format;
16use alloc::string::{String, ToString};
17use alloc::vec::Vec;
18
19use crate::type_identifier::{PrimitiveKind, TypeIdentifier};
20use crate::type_object::common::{CommonStructMember, CommonUnionMember};
21use crate::type_object::complete::{
22 CompleteAliasBody, CompleteAliasHeader, CompleteAliasType, CompleteBitflag,
23 CompleteBitmaskType, CompleteDiscriminatorMember, CompleteEnumeratedHeader,
24 CompleteEnumeratedLiteral, CompleteEnumeratedType, CompleteStructHeader, CompleteStructMember,
25 CompleteStructType, CompleteUnionHeader, CompleteUnionMember, CompleteUnionType,
26};
27use crate::type_object::flags::{
28 AliasMemberFlag, AliasTypeFlag, BitflagFlag, BitmaskTypeFlag, EnumLiteralFlag, EnumTypeFlag,
29 StructMemberFlag, StructTypeFlag, UnionDiscriminatorFlag, UnionMemberFlag, UnionTypeFlag,
30};
31use crate::type_object::minimal::CommonDiscriminatorMember;
32use crate::type_object::minimal::{CommonBitflag, CommonEnumeratedHeader, CommonEnumeratedLiteral};
33use crate::type_object::{CompleteTypeObject, TypeObject};
34
35use super::builder::{DynamicTypeBuilder, DynamicTypeBuilderFactory};
36use super::descriptor::{ExtensibilityKind, MemberDescriptor, TypeDescriptor, TypeKind};
37use super::error::DynamicError;
38use super::type_::DynamicType;
39
40impl DynamicType {
45 pub fn to_type_object(&self) -> Result<TypeObject, DynamicError> {
57 match self.kind() {
58 TypeKind::Structure => Ok(TypeObject::Complete(CompleteTypeObject::Struct(
59 self.to_complete_struct()?,
60 ))),
61 TypeKind::Union => Ok(TypeObject::Complete(CompleteTypeObject::Union(
62 self.to_complete_union()?,
63 ))),
64 TypeKind::Enumeration => Ok(TypeObject::Complete(CompleteTypeObject::Enumerated(
65 self.to_complete_enum()?,
66 ))),
67 TypeKind::Bitmask => Ok(TypeObject::Complete(CompleteTypeObject::Bitmask(
68 self.to_complete_bitmask()?,
69 ))),
70 TypeKind::Alias => Ok(TypeObject::Complete(CompleteTypeObject::Alias(
71 self.to_complete_alias()?,
72 ))),
73 TypeKind::Array | TypeKind::Sequence | TypeKind::Map => {
74 Err(DynamicError::unsupported(format!(
79 "to_type_object for {:?} — Collection-Types use TypeIdentifier exclusively (XTypes §7.3.4)",
80 self.kind(),
81 )))
82 }
83 TypeKind::Bitset | TypeKind::Annotation => {
84 Err(DynamicError::unsupported(format!(
89 "to_type_object for {:?} — needs MemberDescriptor extension (MemberDescriptor extension)",
90 self.kind(),
91 )))
92 }
93 other => Err(DynamicError::unsupported(format!(
94 "to_type_object: {other:?} is a primitive/no-type kind without TypeObject",
95 ))),
96 }
97 }
98
99 fn to_complete_alias(&self) -> Result<CompleteAliasType, DynamicError> {
100 use crate::type_object::common::{
101 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteTypeDetail,
102 OptionalAppliedAnnotationSeq,
103 };
104 let header = CompleteAliasHeader {
105 detail: CompleteTypeDetail {
106 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
107 ann_custom: OptionalAppliedAnnotationSeq::default(),
108 type_name: self.descriptor().name.clone(),
109 },
110 };
111 let element = self.descriptor().element_type.as_ref().ok_or_else(|| {
112 DynamicError::inconsistent("alias type missing element_type (target)")
113 })?;
114 let related_type = descriptor_to_type_identifier(element)?;
115 let body = CompleteAliasBody {
116 related_flags: AliasMemberFlag(0),
117 related_type,
118 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
119 ann_custom: OptionalAppliedAnnotationSeq::default(),
120 };
121 Ok(CompleteAliasType {
122 alias_flags: AliasTypeFlag(0),
123 header,
124 body,
125 })
126 }
127
128 fn to_complete_enum(&self) -> Result<CompleteEnumeratedType, DynamicError> {
129 use crate::type_object::common::{
130 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
131 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
132 };
133 let bit_bound = self.descriptor().bound.first().copied().unwrap_or(32);
134 let bit_bound_u16 = u16::try_from(bit_bound).unwrap_or(32);
135 let header = CompleteEnumeratedHeader {
136 common: CommonEnumeratedHeader {
137 bit_bound: bit_bound_u16,
138 },
139 detail: CompleteTypeDetail {
140 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
141 ann_custom: OptionalAppliedAnnotationSeq::default(),
142 type_name: self.descriptor().name.clone(),
143 },
144 };
145 let mut literal_seq: Vec<CompleteEnumeratedLiteral> =
146 Vec::with_capacity(self.member_count() as usize);
147 for m in self.members() {
148 let mut flags_bits: u16 = 0;
149 if m.descriptor().is_default_label {
150 flags_bits |= EnumLiteralFlag::IS_DEFAULT_LITERAL;
151 }
152 let value = i32::try_from(m.id()).map_err(|_| {
154 DynamicError::inconsistent(format!("enum literal id {} exceeds i32 range", m.id()))
155 })?;
156 literal_seq.push(CompleteEnumeratedLiteral {
157 common: CommonEnumeratedLiteral {
158 value,
159 flags: EnumLiteralFlag(flags_bits),
160 },
161 detail: CompleteMemberDetail {
162 name: m.name().to_string(),
163 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
164 ann_custom: OptionalAppliedAnnotationSeq::default(),
165 },
166 });
167 }
168 Ok(CompleteEnumeratedType {
169 enum_flags: EnumTypeFlag(0),
170 header,
171 literal_seq,
172 })
173 }
174
175 fn to_complete_bitmask(&self) -> Result<CompleteBitmaskType, DynamicError> {
176 use crate::type_object::common::{
177 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
178 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
179 };
180 let bit_bound = self.descriptor().bound.first().copied().unwrap_or(32);
181 let bit_bound_u16 = u16::try_from(bit_bound).unwrap_or(32);
182 let detail = CompleteTypeDetail {
183 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
184 ann_custom: OptionalAppliedAnnotationSeq::default(),
185 type_name: self.descriptor().name.clone(),
186 };
187 let mut flag_seq: Vec<CompleteBitflag> = Vec::with_capacity(self.member_count() as usize);
188 for m in self.members() {
189 let position = u16::try_from(m.id()).map_err(|_| {
190 DynamicError::inconsistent(format!(
191 "bitmask flag position {} exceeds u16 range",
192 m.id()
193 ))
194 })?;
195 flag_seq.push(CompleteBitflag {
196 common: CommonBitflag {
197 position,
198 flags: BitflagFlag(0),
199 },
200 detail: CompleteMemberDetail {
201 name: m.name().to_string(),
202 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
203 ann_custom: OptionalAppliedAnnotationSeq::default(),
204 },
205 });
206 }
207 Ok(CompleteBitmaskType {
208 bitmask_flags: BitmaskTypeFlag(0),
209 bit_bound: bit_bound_u16,
210 detail,
211 flag_seq,
212 })
213 }
214
215 fn to_complete_union(&self) -> Result<CompleteUnionType, DynamicError> {
216 use crate::type_object::common::{
217 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
218 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
219 };
220 let union_flags = UnionTypeFlag(extensibility_to_flag_bits(
221 self.descriptor().extensibility_kind,
222 ));
223 let header = CompleteUnionHeader {
224 detail: CompleteTypeDetail {
225 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
226 ann_custom: OptionalAppliedAnnotationSeq::default(),
227 type_name: self.descriptor().name.clone(),
228 },
229 };
230 let disc_descriptor = self
231 .descriptor()
232 .discriminator_type
233 .as_ref()
234 .ok_or_else(|| DynamicError::inconsistent("union type missing discriminator_type"))?;
235 let disc_type = descriptor_to_type_identifier(disc_descriptor)?;
236 let discriminator = CompleteDiscriminatorMember {
237 common: CommonDiscriminatorMember {
238 member_flags: UnionDiscriminatorFlag(0),
239 type_id: disc_type,
240 },
241 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
242 ann_custom: OptionalAppliedAnnotationSeq::default(),
243 };
244 let mut member_seq: Vec<CompleteUnionMember> =
245 Vec::with_capacity(self.member_count() as usize);
246 for m in self.members() {
247 let mut flags_bits: u16 = 0;
248 if m.descriptor().is_default_label {
249 flags_bits |= UnionMemberFlag::IS_DEFAULT;
250 }
251 let label_seq: Vec<i32> = m
253 .descriptor()
254 .label
255 .iter()
256 .map(|&v| i32::try_from(v).unwrap_or_default())
257 .collect();
258 let common = CommonUnionMember {
259 member_id: m.id(),
260 member_flags: UnionMemberFlag(flags_bits),
261 type_id: descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?,
262 label_seq,
263 };
264 let detail = CompleteMemberDetail {
265 name: m.name().to_string(),
266 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
267 ann_custom: OptionalAppliedAnnotationSeq::default(),
268 };
269 member_seq.push(CompleteUnionMember { common, detail });
270 }
271 Ok(CompleteUnionType {
272 union_flags,
273 header,
274 discriminator,
275 member_seq,
276 })
277 }
278
279 fn to_complete_struct(&self) -> Result<CompleteStructType, DynamicError> {
280 use crate::type_object::common::{
281 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
282 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
283 };
284 let struct_flags = StructTypeFlag(extensibility_to_flag_bits(
285 self.descriptor().extensibility_kind,
286 ));
287 let header = CompleteStructHeader {
288 base_type: TypeIdentifier::None,
289 detail: CompleteTypeDetail {
290 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
291 ann_custom: OptionalAppliedAnnotationSeq::default(),
292 type_name: self.descriptor().name.clone(),
293 },
294 };
295 let mut member_seq: Vec<CompleteStructMember> =
296 Vec::with_capacity(self.member_count() as usize);
297 for m in self.members() {
298 let mut flags_bits: u16 = 0;
299 if m.descriptor().is_key {
300 flags_bits |= StructMemberFlag::IS_KEY;
301 }
302 if m.descriptor().is_optional {
303 flags_bits |= StructMemberFlag::IS_OPTIONAL;
304 }
305 if m.descriptor().is_must_understand {
306 flags_bits |= StructMemberFlag::IS_MUST_UNDERSTAND;
307 }
308 if m.descriptor().is_shared {
309 flags_bits |= StructMemberFlag::IS_EXTERNAL;
310 }
311 let common = CommonStructMember {
312 member_id: m.id(),
313 member_flags: StructMemberFlag(flags_bits),
314 member_type_id: descriptor_to_type_identifier(m.descriptor().member_type.as_ref())?,
315 };
316 let detail = CompleteMemberDetail {
317 name: m.name().to_string(),
318 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
319 ann_custom: OptionalAppliedAnnotationSeq::default(),
320 };
321 member_seq.push(CompleteStructMember { common, detail });
322 }
323 Ok(CompleteStructType {
324 struct_flags,
325 header,
326 member_seq,
327 })
328 }
329}
330
331const fn extensibility_to_flag_bits(ext: ExtensibilityKind) -> u16 {
332 match ext {
333 ExtensibilityKind::Final => StructTypeFlag::IS_FINAL,
334 ExtensibilityKind::Appendable => StructTypeFlag::IS_APPENDABLE,
335 ExtensibilityKind::Mutable => StructTypeFlag::IS_MUTABLE,
336 }
337}
338
339const fn flag_bits_to_extensibility(flags: u16) -> ExtensibilityKind {
340 if flags & StructTypeFlag::IS_FINAL != 0 {
341 ExtensibilityKind::Final
342 } else if flags & StructTypeFlag::IS_MUTABLE != 0 {
343 ExtensibilityKind::Mutable
344 } else {
345 ExtensibilityKind::Appendable
346 }
347}
348
349fn descriptor_to_type_identifier(desc: &TypeDescriptor) -> Result<TypeIdentifier, DynamicError> {
354 match desc.kind {
355 TypeKind::Boolean => Ok(TypeIdentifier::Primitive(PrimitiveKind::Boolean)),
356 TypeKind::Byte => Ok(TypeIdentifier::Primitive(PrimitiveKind::Byte)),
357 TypeKind::Int8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int8)),
358 TypeKind::UInt8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt8)),
359 TypeKind::Int16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int16)),
360 TypeKind::UInt16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt16)),
361 TypeKind::Int32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int32)),
362 TypeKind::UInt32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt32)),
363 TypeKind::Int64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Int64)),
364 TypeKind::UInt64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::UInt64)),
365 TypeKind::Float32 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float32)),
366 TypeKind::Float64 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float64)),
367 TypeKind::Float128 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Float128)),
368 TypeKind::Char8 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Char8)),
369 TypeKind::Char16 => Ok(TypeIdentifier::Primitive(PrimitiveKind::Char16)),
370 TypeKind::String8 => {
371 let bound = desc.bound.first().copied().unwrap_or(0);
372 if bound <= u32::from(u8::MAX) {
373 Ok(TypeIdentifier::String8Small { bound: bound as u8 })
374 } else {
375 Ok(TypeIdentifier::String8Large { bound })
376 }
377 }
378 TypeKind::String16 => {
379 let bound = desc.bound.first().copied().unwrap_or(0);
380 if bound <= u32::from(u8::MAX) {
381 Ok(TypeIdentifier::String16Small { bound: bound as u8 })
382 } else {
383 Ok(TypeIdentifier::String16Large { bound })
384 }
385 }
386 TypeKind::Structure | TypeKind::Union | TypeKind::Enumeration | TypeKind::Alias => {
387 Ok(TypeIdentifier::None)
392 }
393 kind => Err(DynamicError::unsupported(format!(
394 "descriptor_to_type_identifier: {kind:?} not yet covered"
395 ))),
396 }
397}
398
399impl DynamicTypeBuilderFactory {
404 pub fn create_type_w_type_object(
414 type_obj: &TypeObject,
415 ) -> Result<DynamicTypeBuilder, DynamicError> {
416 match type_obj {
417 TypeObject::Complete(c) => match c {
418 CompleteTypeObject::Struct(s) => complete_struct_to_builder(s),
419 other => Err(DynamicError::unsupported(format!(
420 "complete-typeobject kind {} not yet supported",
421 other_kind_name(other)
422 ))),
423 },
424 TypeObject::Minimal(_) => Err(DynamicError::unsupported(
425 "minimal-typeobject → dynamic-type pending C4.2 TypeRegistry",
426 )),
427 }
428 }
429}
430
431fn complete_struct_to_builder(s: &CompleteStructType) -> Result<DynamicTypeBuilder, DynamicError> {
432 let mut desc = TypeDescriptor::structure(s.header.detail.type_name.clone());
433 desc.extensibility_kind = flag_bits_to_extensibility(s.struct_flags.0);
434 if (s.struct_flags.0 & StructTypeFlag::IS_NESTED) != 0 {
435 desc.is_nested = true;
436 }
437 let mut b = DynamicTypeBuilderFactory::create_type(desc)?;
438 for (idx, m) in s.member_seq.iter().enumerate() {
439 let kind = type_id_to_kind(&m.common.member_type_id)?;
440 let member_type = type_id_to_descriptor(&m.common.member_type_id, kind)?;
441 let mut md = MemberDescriptor::new(m.detail.name.clone(), m.common.member_id, member_type);
442 md.index = u32::try_from(idx).unwrap_or(u32::MAX);
443 md.is_key = (m.common.member_flags.0 & StructMemberFlag::IS_KEY) != 0;
444 md.is_optional = (m.common.member_flags.0 & StructMemberFlag::IS_OPTIONAL) != 0;
445 md.is_must_understand =
446 (m.common.member_flags.0 & StructMemberFlag::IS_MUST_UNDERSTAND) != 0;
447 md.is_shared = (m.common.member_flags.0 & StructMemberFlag::IS_EXTERNAL) != 0;
448 b.add_member(md)?;
449 }
450 Ok(b)
451}
452
453const fn other_kind_name(c: &CompleteTypeObject) -> &'static str {
454 match c {
455 CompleteTypeObject::Alias(_) => "alias",
456 CompleteTypeObject::Annotation(_) => "annotation",
457 CompleteTypeObject::Struct(_) => "struct",
458 CompleteTypeObject::Union(_) => "union",
459 CompleteTypeObject::Bitset(_) => "bitset",
460 CompleteTypeObject::Sequence(_) => "sequence",
461 CompleteTypeObject::Array(_) => "array",
462 CompleteTypeObject::Map(_) => "map",
463 CompleteTypeObject::Enumerated(_) => "enum",
464 CompleteTypeObject::Bitmask(_) => "bitmask",
465 }
466}
467
468fn type_id_to_kind(ti: &TypeIdentifier) -> Result<TypeKind, DynamicError> {
469 Ok(match ti {
470 TypeIdentifier::None => TypeKind::NoType,
471 TypeIdentifier::Primitive(p) => primitive_kind_to_type_kind(*p),
472 TypeIdentifier::String8Small { .. } | TypeIdentifier::String8Large { .. } => {
473 TypeKind::String8
474 }
475 TypeIdentifier::String16Small { .. } | TypeIdentifier::String16Large { .. } => {
476 TypeKind::String16
477 }
478 TypeIdentifier::PlainSequenceSmall { .. } | TypeIdentifier::PlainSequenceLarge { .. } => {
479 TypeKind::Sequence
480 }
481 TypeIdentifier::PlainArraySmall { .. } | TypeIdentifier::PlainArrayLarge { .. } => {
482 TypeKind::Array
483 }
484 TypeIdentifier::PlainMapSmall { .. } | TypeIdentifier::PlainMapLarge { .. } => {
485 TypeKind::Map
486 }
487 TypeIdentifier::EquivalenceHashMinimal(_) | TypeIdentifier::EquivalenceHashComplete(_) => {
488 TypeKind::Structure
491 }
492 other => {
493 return Err(DynamicError::unsupported(format!(
494 "type_id_to_kind: {other:?} not yet supported"
495 )));
496 }
497 })
498}
499
500const fn primitive_kind_to_type_kind(p: PrimitiveKind) -> TypeKind {
501 match p {
502 PrimitiveKind::Boolean => TypeKind::Boolean,
503 PrimitiveKind::Byte => TypeKind::Byte,
504 PrimitiveKind::Int8 => TypeKind::Int8,
505 PrimitiveKind::UInt8 => TypeKind::UInt8,
506 PrimitiveKind::Int16 => TypeKind::Int16,
507 PrimitiveKind::UInt16 => TypeKind::UInt16,
508 PrimitiveKind::Int32 => TypeKind::Int32,
509 PrimitiveKind::UInt32 => TypeKind::UInt32,
510 PrimitiveKind::Int64 => TypeKind::Int64,
511 PrimitiveKind::UInt64 => TypeKind::UInt64,
512 PrimitiveKind::Float32 => TypeKind::Float32,
513 PrimitiveKind::Float64 => TypeKind::Float64,
514 PrimitiveKind::Float128 => TypeKind::Float128,
515 PrimitiveKind::Char8 => TypeKind::Char8,
516 PrimitiveKind::Char16 => TypeKind::Char16,
517 }
518}
519
520fn type_id_to_descriptor(
527 ti: &TypeIdentifier,
528 kind: TypeKind,
529) -> Result<TypeDescriptor, DynamicError> {
530 if kind.is_primitive() {
531 return Ok(TypeDescriptor::primitive(
532 kind,
533 super::type_::primitive_name(kind).to_string(),
534 ));
535 }
536 Ok(match ti {
537 TypeIdentifier::String8Small { bound } => TypeDescriptor::string8(u32::from(*bound)),
538 TypeIdentifier::String8Large { bound } => TypeDescriptor::string8(*bound),
539 TypeIdentifier::String16Small { bound } => TypeDescriptor::string16(u32::from(*bound)),
540 TypeIdentifier::String16Large { bound } => TypeDescriptor::string16(*bound),
541 TypeIdentifier::None => TypeDescriptor {
542 kind: TypeKind::Structure,
543 name: String::from("<unresolved>"),
544 base_type: None,
545 discriminator_type: None,
546 bound: Vec::new(),
547 element_type: None,
548 key_element_type: None,
549 extensibility_kind: ExtensibilityKind::default(),
550 is_nested: false,
551 },
552 TypeIdentifier::EquivalenceHashMinimal(_) | TypeIdentifier::EquivalenceHashComplete(_) => {
553 TypeDescriptor {
556 kind: TypeKind::Structure,
557 name: String::from("<typeref>"),
558 base_type: None,
559 discriminator_type: None,
560 bound: Vec::new(),
561 element_type: None,
562 key_element_type: None,
563 extensibility_kind: ExtensibilityKind::default(),
564 is_nested: false,
565 }
566 }
567 TypeIdentifier::PlainSequenceSmall { bound, element, .. } => {
568 let elem_kind = type_id_to_kind(element)?;
569 TypeDescriptor::sequence(
570 "<seq>".to_string(),
571 type_id_to_descriptor(element, elem_kind)?,
572 u32::from(*bound),
573 )
574 }
575 TypeIdentifier::PlainSequenceLarge { bound, element, .. } => {
576 let elem_kind = type_id_to_kind(element)?;
577 TypeDescriptor::sequence(
578 "<seq>".to_string(),
579 type_id_to_descriptor(element, elem_kind)?,
580 *bound,
581 )
582 }
583 TypeIdentifier::PlainArraySmall {
584 array_bounds,
585 element,
586 ..
587 } => {
588 let elem_kind = type_id_to_kind(element)?;
589 TypeDescriptor::array(
590 "<arr>".to_string(),
591 type_id_to_descriptor(element, elem_kind)?,
592 array_bounds.iter().map(|b| u32::from(*b)).collect(),
593 )
594 }
595 TypeIdentifier::PlainArrayLarge {
596 array_bounds,
597 element,
598 ..
599 } => {
600 let elem_kind = type_id_to_kind(element)?;
601 TypeDescriptor::array(
602 "<arr>".to_string(),
603 type_id_to_descriptor(element, elem_kind)?,
604 array_bounds.clone(),
605 )
606 }
607 other => {
608 return Err(DynamicError::unsupported(format!(
609 "type_id_to_descriptor: {other:?} not yet supported"
610 )));
611 }
612 })
613}
614
615#[cfg(test)]
616#[allow(
617 clippy::unwrap_used,
618 clippy::expect_used,
619 clippy::panic,
620 clippy::unreachable
621)]
622mod tests {
623 use super::*;
624 use crate::dynamic::DynamicTypeBuilderFactory;
625
626 fn build_int_struct() -> DynamicType {
627 let mut b = DynamicTypeBuilderFactory::create_struct("::Sensor");
628 b.add_struct_member("id", 1, TypeDescriptor::primitive(TypeKind::Int64, "int64"))
629 .unwrap();
630 b.add_struct_member(
631 "temp",
632 2,
633 TypeDescriptor::primitive(TypeKind::Float64, "double"),
634 )
635 .unwrap();
636 b.add_struct_member("name", 3, TypeDescriptor::string8(64))
637 .unwrap();
638 b.build().unwrap()
639 }
640
641 #[test]
642 fn dynamic_struct_to_typeobject_complete() {
643 let t = build_int_struct();
644 let to = t.to_type_object().unwrap();
645 match to {
646 TypeObject::Complete(CompleteTypeObject::Struct(s)) => {
647 assert_eq!(s.header.detail.type_name, "::Sensor");
648 assert_eq!(s.member_seq.len(), 3);
649 assert_eq!(s.member_seq[0].detail.name, "id");
650 }
651 _ => panic!("to_type_object on Structure must return Complete::Struct"),
652 }
653 }
654
655 #[test]
656 fn typeobject_complete_struct_back_to_dynamic_type() {
657 let t = build_int_struct();
658 let to = t.to_type_object().unwrap();
659 let b = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap();
660 let t2 = b.build().unwrap();
661 assert_eq!(t2.name(), "::Sensor");
662 assert_eq!(t2.member_count(), 3);
663 assert_eq!(t2.member_by_id(1).unwrap().name(), "id");
664 assert_eq!(t2.member_by_id(2).unwrap().name(), "temp");
665 assert_eq!(t2.member_by_id(3).unwrap().name(), "name");
666 }
667
668 #[test]
669 fn roundtrip_dynamic_to_typeobject_to_dynamic_equals_logically() {
670 let t = build_int_struct();
671 let to = t.to_type_object().unwrap();
672 let b = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap();
673 let t2 = b.build().unwrap();
674 assert!(t.equals(&t2), "roundtrip failed: {t:?} vs {t2:?}");
676 }
677
678 #[test]
679 fn unsupported_kind_to_typeobject_yields_unsupported_error() {
680 let prim = DynamicTypeBuilderFactory::get_primitive_type(TypeKind::Int32).unwrap();
681 let err = prim.to_type_object().unwrap_err();
682 assert!(matches!(err, DynamicError::Unsupported(_)));
683 }
684
685 #[test]
686 fn dynamic_alias_to_typeobject_complete() {
687 let mut desc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
689 desc.kind = TypeKind::Alias;
690 desc.name = "::SensorId".to_string();
691 desc.element_type = Some(alloc::boxed::Box::new(TypeDescriptor::primitive(
692 TypeKind::Int32,
693 "int32",
694 )));
695 let t = DynamicTypeBuilderFactory::create_type(desc)
696 .unwrap()
697 .build()
698 .unwrap();
699 let to = t.to_type_object().expect("alias bridge ok");
700 match to {
701 TypeObject::Complete(CompleteTypeObject::Alias(a)) => {
702 assert_eq!(a.header.detail.type_name, "::SensorId");
703 assert!(matches!(a.body.related_type, TypeIdentifier::Primitive(_)));
704 }
705 other => panic!("expected Alias, got {other:?}"),
706 }
707 }
708
709 #[test]
710 fn dynamic_enum_to_typeobject_complete() {
711 let mut desc = TypeDescriptor::primitive(TypeKind::Enumeration, "::Color");
712 desc.kind = TypeKind::Enumeration;
713 desc.bound = alloc::vec![32];
714 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
715 for (id, name) in [(0u32, "RED"), (1u32, "GREEN"), (2u32, "BLUE")] {
716 let m = MemberDescriptor::new(
717 name,
718 id,
719 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
720 );
721 b.add_member(m).unwrap();
722 }
723 let t = b.build().unwrap();
724 let to = t.to_type_object().expect("enum bridge ok");
725 match to {
726 TypeObject::Complete(CompleteTypeObject::Enumerated(e)) => {
727 assert_eq!(e.literal_seq.len(), 3);
728 assert_eq!(e.literal_seq[0].detail.name, "RED");
729 assert_eq!(e.literal_seq[2].common.value, 2);
730 }
731 other => panic!("expected Enumerated, got {other:?}"),
732 }
733 }
734
735 #[test]
736 fn dynamic_bitmask_to_typeobject_complete() {
737 let mut desc = TypeDescriptor::primitive(TypeKind::Bitmask, "::Flags");
738 desc.kind = TypeKind::Bitmask;
739 desc.bound = alloc::vec![8];
740 let mut b = DynamicTypeBuilderFactory::create_type(desc).unwrap();
741 for (pos, name) in [(0u32, "A"), (3u32, "D"), (7u32, "H")] {
742 let m = MemberDescriptor::new(
743 name,
744 pos,
745 TypeDescriptor::primitive(TypeKind::Boolean, "boolean"),
746 );
747 b.add_member(m).unwrap();
748 }
749 let t = b.build().unwrap();
750 let to = t.to_type_object().expect("bitmask bridge ok");
751 match to {
752 TypeObject::Complete(CompleteTypeObject::Bitmask(bm)) => {
753 assert_eq!(bm.bit_bound, 8);
754 assert_eq!(bm.flag_seq.len(), 3);
755 assert_eq!(bm.flag_seq[1].common.position, 3);
756 }
757 other => panic!("expected Bitmask, got {other:?}"),
758 }
759 }
760
761 #[test]
762 fn dynamic_union_to_typeobject_complete() {
763 let disc = TypeDescriptor::primitive(TypeKind::Int32, "int32");
764 let t = {
765 let mut b = DynamicTypeBuilderFactory::create_union("::Shape", disc).unwrap();
766 let mut m1 = MemberDescriptor::new(
767 "circle",
768 1,
769 TypeDescriptor::primitive(TypeKind::Float64, "double"),
770 );
771 m1.label = alloc::vec![1];
772 let mut m2 = MemberDescriptor::new(
773 "square",
774 2,
775 TypeDescriptor::primitive(TypeKind::Float64, "double"),
776 );
777 m2.label = alloc::vec![2, 3];
778 b.add_member(m1).unwrap();
779 b.add_member(m2).unwrap();
780 b.build().unwrap()
781 };
782 let to = t.to_type_object().expect("union bridge ok");
783 match to {
784 TypeObject::Complete(CompleteTypeObject::Union(u)) => {
785 assert_eq!(u.member_seq.len(), 2);
786 assert_eq!(u.member_seq[0].detail.name, "circle");
787 assert_eq!(u.member_seq[1].common.label_seq, alloc::vec![2, 3]);
788 assert!(matches!(
789 u.discriminator.common.type_id,
790 TypeIdentifier::Primitive(PrimitiveKind::Int32)
791 ));
792 }
793 other => panic!("expected Union, got {other:?}"),
794 }
795 }
796
797 #[test]
798 fn collection_kinds_to_typeobject_yield_explicit_error() {
799 let mut seq_desc = TypeDescriptor::primitive(TypeKind::Sequence, "sequence");
802 seq_desc.kind = TypeKind::Sequence;
803 seq_desc.element_type = Some(alloc::boxed::Box::new(TypeDescriptor::primitive(
804 TypeKind::Int32,
805 "int32",
806 )));
807 seq_desc.bound = alloc::vec![16];
808 let seq = DynamicTypeBuilderFactory::create_type(seq_desc)
809 .unwrap()
810 .build()
811 .unwrap();
812 let err = seq.to_type_object().unwrap_err();
813 match err {
814 DynamicError::Unsupported(msg) => {
815 assert!(msg.contains("Collection-Types"), "msg: {msg}");
816 }
817 other => panic!("expected Unsupported, got {other:?}"),
818 }
819 }
820
821 #[test]
822 fn create_type_w_minimal_typeobject_is_unsupported() {
823 use crate::type_object::MinimalTypeObject;
824 use crate::type_object::minimal::{MinimalStructHeader, MinimalStructType};
825 let m = MinimalStructType {
826 struct_flags: StructTypeFlag::default(),
827 header: MinimalStructHeader {
828 base_type: TypeIdentifier::None,
829 },
830 member_seq: alloc::vec![],
831 };
832 let to = TypeObject::Minimal(MinimalTypeObject::Struct(m));
833 let err = DynamicTypeBuilderFactory::create_type_w_type_object(&to).unwrap_err();
834 assert!(matches!(err, DynamicError::Unsupported(_)));
835 }
836}