1use alloc::string::String;
31use alloc::vec::Vec;
32
33use crate::type_identifier::TypeIdentifier;
34use crate::type_object::common::{
35 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CommonStructMember,
36 CompleteMemberDetail, CompleteTypeDetail, NameHash, OptionalAppliedAnnotationSeq,
37};
38use crate::type_object::complete::{
39 CompleteAliasBody, CompleteAliasHeader, CompleteAliasType, CompleteEnumeratedHeader,
40 CompleteEnumeratedLiteral, CompleteEnumeratedType, CompleteStructHeader, CompleteStructMember,
41 CompleteStructType,
42};
43use crate::type_object::flags::{
44 AliasMemberFlag, AliasTypeFlag, EnumLiteralFlag, EnumTypeFlag, StructMemberFlag, StructTypeFlag,
45};
46use crate::type_object::minimal::CommonAliasBody;
47use crate::type_object::minimal::{
48 CommonEnumeratedHeader, CommonEnumeratedLiteral, MinimalAliasBody, MinimalAliasType,
49 MinimalEnumeratedHeader, MinimalEnumeratedLiteral, MinimalEnumeratedType, MinimalStructHeader,
50 MinimalStructMember, MinimalStructType,
51};
52
53fn strip_leading_scope(name: &str) -> String {
58 name.strip_prefix("::").unwrap_or(name).into()
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
64pub enum Extensibility {
65 Final,
67 Appendable,
69 Mutable,
71}
72
73impl Default for Extensibility {
74 fn default() -> Self {
75 Self::Appendable
76 }
77}
78
79impl Extensibility {
80 const fn to_flag_bits(self) -> u16 {
81 match self {
82 Self::Final => StructTypeFlag::IS_FINAL,
83 Self::Appendable => StructTypeFlag::IS_APPENDABLE,
84 Self::Mutable => StructTypeFlag::IS_MUTABLE,
85 }
86 }
87}
88
89pub struct TypeObjectBuilder;
91
92impl TypeObjectBuilder {
93 #[must_use]
96 pub fn struct_type(name: impl Into<String>) -> StructBuilder {
97 StructBuilder {
98 name: name.into(),
99 extensibility: Extensibility::default(),
100 nested: false,
101 autoid_hash: false,
102 base_type: TypeIdentifier::None,
103 members: Vec::new(),
104 }
105 }
106
107 #[must_use]
109 pub fn enum_type(name: impl Into<String>) -> EnumBuilder {
110 EnumBuilder {
111 name: name.into(),
112 bit_bound: 32,
113 literals: Vec::new(),
114 }
115 }
116
117 #[must_use]
119 pub fn alias(name: impl Into<String>, target: TypeIdentifier) -> AliasBuilder {
120 AliasBuilder {
121 name: name.into(),
122 related_type: target,
123 }
124 }
125}
126
127pub struct StructBuilder {
133 name: String,
134 extensibility: Extensibility,
135 nested: bool,
136 autoid_hash: bool,
137 base_type: TypeIdentifier,
138 members: Vec<StructMemberSpec>,
139}
140
141pub struct StructMemberSpec {
143 name: String,
144 type_id: TypeIdentifier,
145 explicit_id: Option<u32>,
146 flags: u16,
147 unit: Option<String>,
148 min: Option<Vec<u8>>,
149 max: Option<Vec<u8>>,
150 hash_id: Option<String>,
151 default_value: Option<String>,
152}
153
154pub struct StructMemberBuilder<'a> {
156 spec: &'a mut StructMemberSpec,
157}
158
159impl StructMemberBuilder<'_> {
160 #[must_use]
162 pub fn key(self) -> Self {
163 self.spec.flags |= StructMemberFlag::IS_KEY;
164 self
165 }
166
167 #[must_use]
169 pub fn optional(self) -> Self {
170 self.spec.flags |= StructMemberFlag::IS_OPTIONAL;
171 self
172 }
173
174 #[must_use]
176 pub fn must_understand(self) -> Self {
177 self.spec.flags |= StructMemberFlag::IS_MUST_UNDERSTAND;
178 self
179 }
180
181 #[must_use]
183 pub fn external(self) -> Self {
184 self.spec.flags |= StructMemberFlag::IS_EXTERNAL;
185 self
186 }
187
188 #[must_use]
190 pub fn id(self, id: u32) -> Self {
191 self.spec.explicit_id = Some(id);
192 self
193 }
194
195 #[must_use]
197 pub fn unit(self, unit: impl Into<String>) -> Self {
198 self.spec.unit = Some(unit.into());
199 self
200 }
201
202 #[must_use]
204 pub fn min_bytes(self, min: Vec<u8>) -> Self {
205 self.spec.min = Some(min);
206 self
207 }
208
209 #[must_use]
211 pub fn max_bytes(self, max: Vec<u8>) -> Self {
212 self.spec.max = Some(max);
213 self
214 }
215
216 #[must_use]
218 pub fn hash_id(self, name: impl Into<String>) -> Self {
219 self.spec.hash_id = Some(name.into());
220 self
221 }
222
223 #[must_use]
227 pub fn set_member_default(self, value: impl Into<String>) -> Self {
228 self.spec.default_value = Some(value.into());
229 self
230 }
231}
232
233impl StructBuilder {
234 #[must_use]
236 pub fn extensibility(mut self, ext: Extensibility) -> Self {
237 self.extensibility = ext;
238 self
239 }
240
241 #[must_use]
243 pub fn nested(mut self) -> Self {
244 self.nested = true;
245 self
246 }
247
248 #[must_use]
250 pub fn autoid_hash(mut self) -> Self {
251 self.autoid_hash = true;
252 self
253 }
254
255 #[must_use]
257 pub fn base(mut self, base: TypeIdentifier) -> Self {
258 self.base_type = base;
259 self
260 }
261
262 #[must_use]
267 pub fn member<F>(mut self, name: impl Into<String>, ty: TypeIdentifier, f: F) -> Self
268 where
269 F: FnOnce(StructMemberBuilder<'_>) -> StructMemberBuilder<'_>,
270 {
271 let mut spec = StructMemberSpec {
272 name: name.into(),
273 type_id: ty,
274 explicit_id: None,
275 flags: StructMemberFlag::TRY_CONSTRUCT1,
280 unit: None,
281 min: None,
282 max: None,
283 hash_id: None,
284 default_value: None,
285 };
286 let _ = f(StructMemberBuilder { spec: &mut spec });
287 self.members.push(spec);
288 self
289 }
290
291 fn struct_flags(&self) -> StructTypeFlag {
292 let mut bits = self.extensibility.to_flag_bits();
293 if self.nested {
294 bits |= StructTypeFlag::IS_NESTED;
295 }
296 if self.autoid_hash {
297 bits |= StructTypeFlag::IS_AUTOID_HASH;
298 }
299 StructTypeFlag(bits)
300 }
301
302 fn resolve_member_ids(&self) -> Vec<u32> {
307 let mut ids = Vec::with_capacity(self.members.len());
308 let mut next_seq: u32 = 0;
314 for spec in &self.members {
315 let id = if let Some(explicit) = spec.explicit_id {
316 explicit
317 } else if self.autoid_hash {
318 let nh = NameHash::from_name(&spec.name);
323 (u32::from_le_bytes(nh.0) >> 4) & 0x00FF_FFFF
324 } else {
325 let v = next_seq;
326 next_seq += 1;
327 v
328 };
329 ids.push(id);
330 }
331 ids
332 }
333
334 fn member_common(spec: &StructMemberSpec, id: u32) -> CommonStructMember {
335 CommonStructMember {
336 member_id: id,
337 member_flags: StructMemberFlag(spec.flags),
338 member_type_id: spec.type_id.clone(),
339 }
340 }
341
342 fn member_detail(spec: &StructMemberSpec) -> CompleteMemberDetail {
343 CompleteMemberDetail {
344 name: spec.name.clone(),
345 ann_builtin: AppliedBuiltinMemberAnnotations {
346 unit: spec.unit.clone(),
347 min: spec.min.clone(),
348 max: spec.max.clone(),
349 hash_id: spec.hash_id.clone(),
350 default_value: spec.default_value.clone(),
351 },
352 ann_custom: OptionalAppliedAnnotationSeq::default(),
353 }
354 }
355
356 #[must_use]
358 pub fn build_minimal(&self) -> MinimalStructType {
359 let ids = self.resolve_member_ids();
360 let member_seq = self
361 .members
362 .iter()
363 .zip(ids.iter())
364 .map(|(spec, id)| MinimalStructMember {
365 common: Self::member_common(spec, *id),
366 detail: NameHash::from_name(&spec.name),
367 })
368 .collect();
369 MinimalStructType {
370 struct_flags: self.struct_flags(),
371 header: MinimalStructHeader {
372 base_type: self.base_type.clone(),
373 },
374 member_seq,
375 }
376 }
377
378 #[must_use]
380 pub fn build_complete(&self) -> CompleteStructType {
381 let ids = self.resolve_member_ids();
382 let member_seq = self
383 .members
384 .iter()
385 .zip(ids.iter())
386 .map(|(spec, id)| CompleteStructMember {
387 common: Self::member_common(spec, *id),
388 detail: Self::member_detail(spec),
389 })
390 .collect();
391 CompleteStructType {
392 struct_flags: self.struct_flags(),
393 header: CompleteStructHeader {
394 base_type: self.base_type.clone(),
395 detail: CompleteTypeDetail {
396 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
397 ann_custom: OptionalAppliedAnnotationSeq::default(),
398 type_name: strip_leading_scope(&self.name),
399 },
400 },
401 member_seq,
402 }
403 }
404}
405
406pub struct EnumBuilder {
412 name: String,
413 bit_bound: u16,
414 literals: Vec<EnumLiteralSpec>,
415}
416
417struct EnumLiteralSpec {
418 name: String,
419 value: i32,
420 is_default: bool,
421}
422
423impl EnumBuilder {
424 #[must_use]
426 pub fn bit_bound(mut self, bits: u16) -> Self {
427 self.bit_bound = bits;
428 self
429 }
430
431 #[must_use]
433 pub fn literal(mut self, name: impl Into<String>, value: i32) -> Self {
434 self.literals.push(EnumLiteralSpec {
435 name: name.into(),
436 value,
437 is_default: false,
438 });
439 self
440 }
441
442 #[must_use]
444 pub fn default_literal(mut self, name: impl Into<String>, value: i32) -> Self {
445 self.literals.push(EnumLiteralSpec {
446 name: name.into(),
447 value,
448 is_default: true,
449 });
450 self
451 }
452
453 #[must_use]
455 pub fn build_minimal(&self) -> MinimalEnumeratedType {
456 MinimalEnumeratedType {
457 enum_flags: EnumTypeFlag::default(),
458 header: MinimalEnumeratedHeader {
459 common: CommonEnumeratedHeader {
460 bit_bound: self.bit_bound,
461 },
462 },
463 literal_seq: self
464 .literals
465 .iter()
466 .map(|l| MinimalEnumeratedLiteral {
467 common: CommonEnumeratedLiteral {
468 value: l.value,
469 flags: EnumLiteralFlag(if l.is_default {
470 EnumLiteralFlag::IS_DEFAULT_LITERAL
471 } else {
472 0
473 }),
474 },
475 detail: NameHash::from_name(&l.name),
476 })
477 .collect(),
478 }
479 }
480
481 #[must_use]
483 pub fn build_complete(&self) -> CompleteEnumeratedType {
484 CompleteEnumeratedType {
485 enum_flags: EnumTypeFlag::default(),
486 header: CompleteEnumeratedHeader {
487 common: CommonEnumeratedHeader {
488 bit_bound: self.bit_bound,
489 },
490 detail: CompleteTypeDetail {
491 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
492 ann_custom: OptionalAppliedAnnotationSeq::default(),
493 type_name: strip_leading_scope(&self.name),
494 },
495 },
496 literal_seq: self
497 .literals
498 .iter()
499 .map(|l| CompleteEnumeratedLiteral {
500 common: CommonEnumeratedLiteral {
501 value: l.value,
502 flags: EnumLiteralFlag(if l.is_default {
503 EnumLiteralFlag::IS_DEFAULT_LITERAL
504 } else {
505 0
506 }),
507 },
508 detail: CompleteMemberDetail {
509 name: l.name.clone(),
510 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
511 ann_custom: OptionalAppliedAnnotationSeq::default(),
512 },
513 })
514 .collect(),
515 }
516 }
517}
518
519pub struct AliasBuilder {
525 name: String,
526 related_type: TypeIdentifier,
527}
528
529impl AliasBuilder {
530 #[must_use]
532 pub fn build_minimal(&self) -> MinimalAliasType {
533 MinimalAliasType {
534 alias_flags: AliasTypeFlag::default(),
535 body: MinimalAliasBody {
536 common: CommonAliasBody {
537 related_flags: AliasMemberFlag::default(),
538 related_type: self.related_type.clone(),
539 },
540 },
541 }
542 }
543
544 #[must_use]
546 pub fn build_complete(&self) -> CompleteAliasType {
547 CompleteAliasType {
548 alias_flags: AliasTypeFlag::default(),
549 header: CompleteAliasHeader {
550 detail: CompleteTypeDetail {
551 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
552 ann_custom: OptionalAppliedAnnotationSeq::default(),
553 type_name: strip_leading_scope(&self.name),
554 },
555 },
556 body: CompleteAliasBody {
557 related_flags: AliasMemberFlag::default(),
558 related_type: self.related_type.clone(),
559 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
560 ann_custom: OptionalAppliedAnnotationSeq::default(),
561 },
562 }
563 }
564}
565
566pub struct UnionBuilder {
572 name: String,
573 extensibility: Extensibility,
574 discriminator_type: TypeIdentifier,
575 cases: Vec<UnionCaseSpec>,
576}
577
578struct UnionCaseSpec {
579 name: String,
580 member_id: Option<u32>,
581 type_id: TypeIdentifier,
582 labels: Vec<i32>,
583 is_default: bool,
584}
585
586impl UnionBuilder {
587 #[must_use]
589 pub fn extensibility(mut self, ext: Extensibility) -> Self {
590 self.extensibility = ext;
591 self
592 }
593
594 #[must_use]
596 pub fn case(mut self, name: impl Into<String>, ty: TypeIdentifier, labels: Vec<i32>) -> Self {
597 self.cases.push(UnionCaseSpec {
598 name: name.into(),
599 member_id: None,
600 type_id: ty,
601 labels,
602 is_default: false,
603 });
604 self
605 }
606
607 #[must_use]
609 pub fn default_case(mut self, name: impl Into<String>, ty: TypeIdentifier) -> Self {
610 self.cases.push(UnionCaseSpec {
611 name: name.into(),
612 member_id: None,
613 type_id: ty,
614 labels: Vec::new(),
615 is_default: true,
616 });
617 self
618 }
619
620 fn union_flags(&self) -> crate::type_object::flags::UnionTypeFlag {
621 use crate::type_object::flags::UnionTypeFlag;
622 UnionTypeFlag(match self.extensibility {
625 Extensibility::Final => StructTypeFlag::IS_FINAL,
626 Extensibility::Appendable => StructTypeFlag::IS_APPENDABLE,
627 Extensibility::Mutable => StructTypeFlag::IS_MUTABLE,
628 })
629 }
630
631 fn resolve_case_ids(&self) -> Vec<u32> {
632 let mut ids = Vec::with_capacity(self.cases.len());
633 let mut next: u32 = 0;
636 for c in &self.cases {
637 ids.push(c.member_id.unwrap_or_else(|| {
638 let v = next;
639 next += 1;
640 v
641 }));
642 }
643 ids
644 }
645
646 #[must_use]
648 pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalUnionType {
649 use crate::type_object::common::CommonUnionMember;
650 use crate::type_object::flags::{UnionDiscriminatorFlag, UnionMemberFlag};
651 use crate::type_object::minimal::{
652 CommonDiscriminatorMember, MinimalDiscriminatorMember, MinimalUnionMember,
653 MinimalUnionType,
654 };
655 let ids = self.resolve_case_ids();
656 let member_seq = self
657 .cases
658 .iter()
659 .zip(ids.iter())
660 .map(|(c, id)| MinimalUnionMember {
661 common: CommonUnionMember {
662 member_id: *id,
663 member_flags: UnionMemberFlag(
664 UnionMemberFlag::TRY_CONSTRUCT1
665 | if c.is_default {
666 UnionMemberFlag::IS_DEFAULT
667 } else {
668 0
669 },
670 ),
671 type_id: c.type_id.clone(),
672 label_seq: c.labels.clone(),
673 },
674 detail: NameHash::from_name(&c.name),
675 })
676 .collect();
677 MinimalUnionType {
678 union_flags: self.union_flags(),
679 discriminator: MinimalDiscriminatorMember {
680 common: CommonDiscriminatorMember {
681 member_flags: UnionDiscriminatorFlag::discriminator_default(),
682 type_id: self.discriminator_type.clone(),
683 },
684 },
685 member_seq,
686 }
687 }
688
689 #[must_use]
691 pub fn build_complete(&self) -> crate::type_object::complete::CompleteUnionType {
692 use crate::type_object::common::CommonUnionMember;
693 use crate::type_object::complete::{
694 CompleteDiscriminatorMember, CompleteUnionHeader, CompleteUnionMember,
695 CompleteUnionType,
696 };
697 use crate::type_object::flags::{UnionDiscriminatorFlag, UnionMemberFlag};
698 use crate::type_object::minimal::CommonDiscriminatorMember;
699 let ids = self.resolve_case_ids();
700 let member_seq = self
701 .cases
702 .iter()
703 .zip(ids.iter())
704 .map(|(c, id)| CompleteUnionMember {
705 common: CommonUnionMember {
706 member_id: *id,
707 member_flags: UnionMemberFlag(
708 UnionMemberFlag::TRY_CONSTRUCT1
709 | if c.is_default {
710 UnionMemberFlag::IS_DEFAULT
711 } else {
712 0
713 },
714 ),
715 type_id: c.type_id.clone(),
716 label_seq: c.labels.clone(),
717 },
718 detail: CompleteMemberDetail {
719 name: c.name.clone(),
720 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
721 ann_custom: OptionalAppliedAnnotationSeq::default(),
722 },
723 })
724 .collect();
725 CompleteUnionType {
726 union_flags: self.union_flags(),
727 header: CompleteUnionHeader {
728 detail: CompleteTypeDetail {
729 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
730 ann_custom: OptionalAppliedAnnotationSeq::default(),
731 type_name: strip_leading_scope(&self.name),
732 },
733 },
734 discriminator: CompleteDiscriminatorMember {
735 common: CommonDiscriminatorMember {
736 member_flags: UnionDiscriminatorFlag::discriminator_default(),
737 type_id: self.discriminator_type.clone(),
738 },
739 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
740 ann_custom: OptionalAppliedAnnotationSeq::default(),
741 },
742 member_seq,
743 }
744 }
745}
746
747pub struct SequenceBuilder {
753 element: TypeIdentifier,
754 bound: u32,
755}
756
757impl SequenceBuilder {
758 #[must_use]
760 pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalSequenceType {
761 use crate::type_object::flags::{CollectionElementFlag, CollectionTypeFlag};
762 use crate::type_object::minimal::{
763 CommonCollectionElement, MinimalCollectionElement, MinimalSequenceType,
764 };
765 MinimalSequenceType {
766 collection_flag: CollectionTypeFlag::default(),
767 bound: self.bound,
768 element: MinimalCollectionElement {
769 common: CommonCollectionElement {
770 element_flags: CollectionElementFlag::default(),
771 type_id: self.element.clone(),
772 },
773 },
774 }
775 }
776}
777
778pub struct ArrayBuilder {
780 element: TypeIdentifier,
781 dimensions: Vec<u32>,
782}
783
784impl ArrayBuilder {
785 #[must_use]
787 pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalArrayType {
788 use crate::type_object::flags::{CollectionElementFlag, CollectionTypeFlag};
789 use crate::type_object::minimal::{
790 CommonCollectionElement, MinimalArrayType, MinimalCollectionElement,
791 };
792 MinimalArrayType {
793 collection_flag: CollectionTypeFlag::default(),
794 bound_seq: self.dimensions.clone(),
795 element: MinimalCollectionElement {
796 common: CommonCollectionElement {
797 element_flags: CollectionElementFlag::default(),
798 type_id: self.element.clone(),
799 },
800 },
801 }
802 }
803}
804
805#[derive(Debug, Clone, PartialEq, Eq)]
807pub enum BuilderError {
808 MutableMapExtensibilityNotAllowed,
813}
814
815pub struct MapBuilder {
817 key: TypeIdentifier,
818 value: TypeIdentifier,
819 bound: u32,
820}
821
822impl MapBuilder {
823 pub fn add_map_member(
830 self,
831 ext: Extensibility,
832 ) -> Result<crate::type_object::minimal::MinimalMapType, BuilderError> {
833 if matches!(ext, Extensibility::Mutable) {
834 return Err(BuilderError::MutableMapExtensibilityNotAllowed);
835 }
836 Ok(self.build_minimal())
837 }
838
839 #[must_use]
841 pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalMapType {
842 use crate::type_object::flags::{CollectionElementFlag, CollectionTypeFlag};
843 use crate::type_object::minimal::{
844 CommonCollectionElement, MinimalCollectionElement, MinimalMapType,
845 };
846 let element = MinimalCollectionElement {
847 common: CommonCollectionElement {
848 element_flags: CollectionElementFlag::default(),
849 type_id: self.value.clone(),
850 },
851 };
852 let key = MinimalCollectionElement {
853 common: CommonCollectionElement {
854 element_flags: CollectionElementFlag::default(),
855 type_id: self.key.clone(),
856 },
857 };
858 MinimalMapType {
859 collection_flag: CollectionTypeFlag::default(),
860 bound: self.bound,
861 key,
862 element,
863 }
864 }
865}
866
867pub struct BitmaskBuilder {
873 name: String,
874 bit_bound: u16,
875 flags: Vec<(String, u16)>,
876}
877
878impl BitmaskBuilder {
879 #[must_use]
881 pub fn bit_bound(mut self, bits: u16) -> Self {
882 self.bit_bound = bits;
883 self
884 }
885
886 #[must_use]
888 pub fn flag(mut self, name: impl Into<String>, position: u16) -> Self {
889 self.flags.push((name.into(), position));
890 self
891 }
892
893 #[must_use]
895 pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalBitmaskType {
896 use crate::type_object::flags::{BitflagFlag, BitmaskTypeFlag};
897 use crate::type_object::minimal::{CommonBitflag, MinimalBitflag, MinimalBitmaskType};
898 MinimalBitmaskType {
899 bitmask_flags: BitmaskTypeFlag::default(),
900 bit_bound: self.bit_bound,
901 flag_seq: self
902 .flags
903 .iter()
904 .map(|(n, p)| MinimalBitflag {
905 common: CommonBitflag {
906 position: *p,
907 flags: BitflagFlag::default(),
908 },
909 detail: NameHash::from_name(n),
910 })
911 .collect(),
912 }
913 }
914
915 #[must_use]
917 pub fn build_complete(&self) -> crate::type_object::complete::CompleteBitmaskType {
918 use crate::type_object::common::{
919 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
920 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
921 };
922 use crate::type_object::complete::{CompleteBitflag, CompleteBitmaskType};
923 use crate::type_object::flags::{BitflagFlag, BitmaskTypeFlag};
924 CompleteBitmaskType {
925 bitmask_flags: BitmaskTypeFlag::default(),
926 bit_bound: self.bit_bound,
927 detail: CompleteTypeDetail {
928 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
929 ann_custom: OptionalAppliedAnnotationSeq::default(),
930 type_name: strip_leading_scope(&self.name),
931 },
932 flag_seq: self
933 .flags
934 .iter()
935 .map(|(n, p)| CompleteBitflag {
936 common: crate::type_object::minimal::CommonBitflag {
937 position: *p,
938 flags: BitflagFlag::default(),
939 },
940 detail: CompleteMemberDetail {
941 name: n.clone(),
942 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
943 ann_custom: OptionalAppliedAnnotationSeq::default(),
944 },
945 })
946 .collect(),
947 }
948 }
949
950 #[must_use]
952 pub fn name(&self) -> &str {
953 &self.name
954 }
955}
956
957pub struct BitsetBuilder {
959 name: String,
960 fields: Vec<BitfieldSpec>,
961}
962
963struct BitfieldSpec {
964 name: String,
965 position: u16,
966 bitcount: u8,
967 holder_type: u8,
968}
969
970impl BitsetBuilder {
971 #[must_use]
973 pub fn field(
974 mut self,
975 name: impl Into<String>,
976 position: u16,
977 bitcount: u8,
978 holder_type: u8,
979 ) -> Self {
980 self.fields.push(BitfieldSpec {
981 name: name.into(),
982 position,
983 bitcount,
984 holder_type,
985 });
986 self
987 }
988
989 #[must_use]
991 pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalBitsetType {
992 use crate::type_object::flags::{BitfieldFlag, BitsetTypeFlag};
993 use crate::type_object::minimal::{CommonBitfield, MinimalBitfield, MinimalBitsetType};
994 MinimalBitsetType {
995 bitset_flags: BitsetTypeFlag::default(),
996 field_seq: self
997 .fields
998 .iter()
999 .map(|f| MinimalBitfield {
1000 common: CommonBitfield {
1001 position: f.position,
1002 flags: BitfieldFlag::default(),
1003 bitcount: f.bitcount,
1004 holder_type: f.holder_type,
1005 },
1006 name_hash: NameHash::from_name(&f.name),
1007 })
1008 .collect(),
1009 }
1010 }
1011
1012 #[must_use]
1014 pub fn build_complete(&self) -> crate::type_object::complete::CompleteBitsetType {
1015 use crate::type_object::common::{
1016 AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
1017 CompleteTypeDetail, OptionalAppliedAnnotationSeq,
1018 };
1019 use crate::type_object::complete::{CompleteBitfield, CompleteBitsetType};
1020 use crate::type_object::flags::{BitfieldFlag, BitsetTypeFlag};
1021 CompleteBitsetType {
1022 bitset_flags: BitsetTypeFlag::default(),
1023 detail: CompleteTypeDetail {
1024 ann_builtin: AppliedBuiltinTypeAnnotations::default(),
1025 ann_custom: OptionalAppliedAnnotationSeq::default(),
1026 type_name: strip_leading_scope(&self.name),
1027 },
1028 field_seq: self
1029 .fields
1030 .iter()
1031 .map(|f| CompleteBitfield {
1032 common: crate::type_object::minimal::CommonBitfield {
1033 position: f.position,
1034 flags: BitfieldFlag::default(),
1035 bitcount: f.bitcount,
1036 holder_type: f.holder_type,
1037 },
1038 detail: CompleteMemberDetail {
1039 name: f.name.clone(),
1040 ann_builtin: AppliedBuiltinMemberAnnotations::default(),
1041 ann_custom: OptionalAppliedAnnotationSeq::default(),
1042 },
1043 })
1044 .collect(),
1045 }
1046 }
1047
1048 #[must_use]
1050 pub fn name(&self) -> &str {
1051 &self.name
1052 }
1053}
1054
1055impl TypeObjectBuilder {
1060 #[must_use]
1063 pub fn union_type(name: impl Into<String>, discriminator_type: TypeIdentifier) -> UnionBuilder {
1064 UnionBuilder {
1065 name: name.into(),
1066 extensibility: Extensibility::default(),
1067 discriminator_type,
1068 cases: Vec::new(),
1069 }
1070 }
1071
1072 #[must_use]
1074 pub fn sequence(element: TypeIdentifier, bound: u32) -> SequenceBuilder {
1075 SequenceBuilder { element, bound }
1076 }
1077
1078 #[must_use]
1080 pub fn array(element: TypeIdentifier, dimensions: Vec<u32>) -> ArrayBuilder {
1081 ArrayBuilder {
1082 element,
1083 dimensions,
1084 }
1085 }
1086
1087 #[must_use]
1089 pub fn map(key: TypeIdentifier, value: TypeIdentifier, bound: u32) -> MapBuilder {
1090 MapBuilder { key, value, bound }
1091 }
1092
1093 #[must_use]
1095 pub fn bitmask(name: impl Into<String>) -> BitmaskBuilder {
1096 BitmaskBuilder {
1097 name: name.into(),
1098 bit_bound: 32,
1099 flags: Vec::new(),
1100 }
1101 }
1102
1103 #[must_use]
1105 pub fn bitset(name: impl Into<String>) -> BitsetBuilder {
1106 BitsetBuilder {
1107 name: name.into(),
1108 fields: Vec::new(),
1109 }
1110 }
1111}
1112
1113#[cfg(test)]
1118#[allow(clippy::unwrap_used)]
1119mod tests {
1120 use super::*;
1121 use crate::type_identifier::PrimitiveKind;
1122 use crate::type_object::flags::StructTypeFlag;
1123
1124 #[test]
1125 fn struct_builder_basic_with_two_members() {
1126 let st = TypeObjectBuilder::struct_type("::chat::Chatter")
1127 .member(
1128 "sensor_id",
1129 TypeIdentifier::Primitive(PrimitiveKind::Int64),
1130 |m| m.key(),
1131 )
1132 .member("text", TypeIdentifier::String8Small { bound: 255 }, |m| m)
1133 .build_minimal();
1134
1135 assert_eq!(st.member_seq.len(), 2);
1136 assert_eq!(st.member_seq[0].common.member_id, 0);
1138 assert!(
1139 st.member_seq[0]
1140 .common
1141 .member_flags
1142 .has(StructMemberFlag::IS_KEY)
1143 );
1144 assert_eq!(st.member_seq[1].common.member_id, 1);
1145 assert_eq!(st.member_seq[0].detail, NameHash::from_name("sensor_id"));
1147 assert_eq!(st.member_seq[1].detail, NameHash::from_name("text"));
1148 }
1149
1150 #[test]
1151 fn struct_builder_explicit_ids_respected() {
1152 let st = TypeObjectBuilder::struct_type("::X")
1153 .member("a", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1154 m.id(100)
1155 })
1156 .member("b", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1157 m.id(200)
1158 })
1159 .build_minimal();
1160 assert_eq!(st.member_seq[0].common.member_id, 100);
1161 assert_eq!(st.member_seq[1].common.member_id, 200);
1162 }
1163
1164 #[test]
1165 fn mutable_map_extensibility_is_error() {
1166 let res = TypeObjectBuilder::map(
1168 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1169 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1170 10,
1171 )
1172 .add_map_member(Extensibility::Mutable);
1173 assert!(matches!(
1174 res,
1175 Err(BuilderError::MutableMapExtensibilityNotAllowed)
1176 ));
1177 }
1178
1179 #[test]
1180 fn appendable_map_extensibility_is_ok() {
1181 let res = TypeObjectBuilder::map(
1182 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1183 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1184 10,
1185 )
1186 .add_map_member(Extensibility::Appendable);
1187 assert!(res.is_ok());
1188 }
1189
1190 #[test]
1191 fn final_map_extensibility_is_ok() {
1192 let res = TypeObjectBuilder::map(
1193 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1194 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1195 10,
1196 )
1197 .add_map_member(Extensibility::Final);
1198 assert!(res.is_ok());
1199 }
1200
1201 #[test]
1202 fn member_with_explicit_default_used_when_field_missing() {
1203 let st = TypeObjectBuilder::struct_type("::S")
1207 .member("a", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1208 m.set_member_default("42")
1209 })
1210 .build_complete();
1211 assert_eq!(
1212 st.member_seq[0].detail.ann_builtin.default_value.as_deref(),
1213 Some("42")
1214 );
1215 }
1216
1217 #[test]
1218 fn default_overrides_implicit_zero() {
1219 let st = TypeObjectBuilder::struct_type("::S")
1224 .member("a", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1225 m.set_member_default("99")
1226 })
1227 .member("b", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1228 .build_complete();
1229 assert_eq!(
1230 st.member_seq[0].detail.ann_builtin.default_value.as_deref(),
1231 Some("99")
1232 );
1233 assert_eq!(st.member_seq[1].detail.ann_builtin.default_value, None);
1234 }
1235
1236 #[test]
1237 fn default_value_roundtrips_via_encode_decode() {
1238 use crate::type_object::common::AppliedBuiltinMemberAnnotations;
1239 use alloc::vec;
1240 use zerodds_cdr::{BufferReader, BufferWriter, Endianness};
1241 let ann = AppliedBuiltinMemberAnnotations {
1242 unit: Some("meters".into()),
1243 min: Some(vec![0]),
1244 max: Some(vec![100]),
1245 hash_id: None,
1246 default_value: Some("17".into()),
1247 };
1248 let mut w = BufferWriter::new(Endianness::Little);
1249 ann.encode_into(&mut w).unwrap();
1250 let bytes = w.into_bytes();
1251 let mut r = BufferReader::new(&bytes, Endianness::Little);
1252 let decoded = AppliedBuiltinMemberAnnotations::decode_from(&mut r).unwrap();
1253 assert_eq!(decoded, ann);
1254 }
1255
1256 #[test]
1257 fn struct_builder_extensibility_mutable() {
1258 let st = TypeObjectBuilder::struct_type("::Y")
1259 .extensibility(Extensibility::Mutable)
1260 .build_minimal();
1261 assert!(st.struct_flags.has(StructTypeFlag::IS_MUTABLE));
1262 assert!(!st.struct_flags.has(StructTypeFlag::IS_APPENDABLE));
1263 }
1264
1265 #[test]
1266 fn complete_builder_preserves_names() {
1267 let st = TypeObjectBuilder::struct_type("::sensors::Chatter")
1268 .extensibility(Extensibility::Appendable)
1269 .member(
1270 "sensor_id",
1271 TypeIdentifier::Primitive(PrimitiveKind::Int64),
1272 |m| m.key().unit("celsius"),
1273 )
1274 .build_complete();
1275 assert_eq!(st.header.detail.type_name, "sensors::Chatter"); assert_eq!(st.member_seq[0].detail.name, "sensor_id");
1277 assert_eq!(
1278 st.member_seq[0].detail.ann_builtin.unit.as_deref(),
1279 Some("celsius")
1280 );
1281 }
1282
1283 #[test]
1284 fn struct_builder_autoid_hash_collision_free_for_distinct_names() {
1285 let st = TypeObjectBuilder::struct_type("::H")
1286 .autoid_hash()
1287 .member(
1288 "alpha",
1289 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1290 |m| m,
1291 )
1292 .member(
1293 "beta",
1294 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1295 |m| m,
1296 )
1297 .build_minimal();
1298 assert!(st.struct_flags.has(StructTypeFlag::IS_AUTOID_HASH));
1299 assert_ne!(
1300 st.member_seq[0].common.member_id,
1301 st.member_seq[1].common.member_id
1302 );
1303 }
1304
1305 #[test]
1306 fn enum_builder_roundtrip_ready() {
1307 let e = TypeObjectBuilder::enum_type("::Color")
1308 .bit_bound(16)
1309 .default_literal("RED", 0)
1310 .literal("GREEN", 1)
1311 .literal("BLUE", 2)
1312 .build_minimal();
1313 assert_eq!(e.header.common.bit_bound, 16);
1314 assert_eq!(e.literal_seq.len(), 3);
1315 assert!(e.literal_seq[0].common.flags.0 & EnumLiteralFlag::IS_DEFAULT_LITERAL != 0);
1316 }
1317
1318 #[test]
1319 fn alias_builder_minimal_and_complete() {
1320 let a_min =
1321 TypeObjectBuilder::alias("::Count", TypeIdentifier::Primitive(PrimitiveKind::UInt64))
1322 .build_minimal();
1323 assert!(matches!(
1324 a_min.body.common.related_type,
1325 TypeIdentifier::Primitive(PrimitiveKind::UInt64)
1326 ));
1327
1328 let a_cmp =
1329 TypeObjectBuilder::alias("::Count", TypeIdentifier::Primitive(PrimitiveKind::UInt64))
1330 .build_complete();
1331 assert_eq!(a_cmp.header.detail.type_name, "Count");
1332 }
1333
1334 #[test]
1339 fn union_builder_minimal_with_two_cases_and_default() {
1340 let u = TypeObjectBuilder::union_type(
1341 "::Shape",
1342 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1343 )
1344 .case(
1345 "circle",
1346 TypeIdentifier::Primitive(PrimitiveKind::Float64),
1347 alloc::vec![1, 2],
1348 )
1349 .default_case("other", TypeIdentifier::String8Small { bound: 64 })
1350 .build_minimal();
1351 assert_eq!(u.member_seq.len(), 2);
1352 assert_eq!(u.member_seq[0].common.label_seq, alloc::vec![1, 2]);
1353 assert!(
1355 u.member_seq[1].common.member_flags.0
1356 & crate::type_object::flags::UnionMemberFlag::IS_DEFAULT
1357 != 0
1358 );
1359 }
1360
1361 #[test]
1362 fn union_builder_complete_preserves_names_and_extensibility() {
1363 let u = TypeObjectBuilder::union_type(
1364 "::Shape",
1365 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1366 )
1367 .extensibility(Extensibility::Mutable)
1368 .case(
1369 "a",
1370 TypeIdentifier::Primitive(PrimitiveKind::Int32),
1371 alloc::vec![1],
1372 )
1373 .build_complete();
1374 assert_eq!(u.header.detail.type_name, "Shape");
1375 assert_eq!(u.member_seq[0].detail.name, "a");
1376 assert_eq!(
1377 u.union_flags.0 & StructTypeFlag::IS_MUTABLE,
1378 StructTypeFlag::IS_MUTABLE
1379 );
1380 }
1381
1382 #[test]
1383 fn sequence_builder_minimal() {
1384 let s = TypeObjectBuilder::sequence(TypeIdentifier::Primitive(PrimitiveKind::Int16), 100)
1385 .build_minimal();
1386 assert_eq!(s.bound, 100);
1387 assert!(matches!(
1388 s.element.common.type_id,
1389 TypeIdentifier::Primitive(PrimitiveKind::Int16)
1390 ));
1391 }
1392
1393 #[test]
1394 fn array_builder_3d() {
1395 let a = TypeObjectBuilder::array(
1396 TypeIdentifier::Primitive(PrimitiveKind::Float32),
1397 alloc::vec![4, 4, 4],
1398 )
1399 .build_minimal();
1400 assert_eq!(a.bound_seq, alloc::vec![4, 4, 4]);
1401 }
1402
1403 #[test]
1404 fn map_builder_string_to_int() {
1405 let m = TypeObjectBuilder::map(
1406 TypeIdentifier::String8Small { bound: 64 },
1407 TypeIdentifier::Primitive(PrimitiveKind::Int64),
1408 1_000,
1409 )
1410 .build_minimal();
1411 assert_eq!(m.bound, 1_000);
1412 assert!(matches!(
1413 m.key.common.type_id,
1414 TypeIdentifier::String8Small { bound: 64 }
1415 ));
1416 }
1417
1418 #[test]
1419 fn bitmask_builder_three_flags() {
1420 let b = TypeObjectBuilder::bitmask("::Permissions")
1421 .bit_bound(32)
1422 .flag("READ", 0)
1423 .flag("WRITE", 1)
1424 .flag("EXEC", 2)
1425 .build_minimal();
1426 assert_eq!(b.bit_bound, 32);
1427 assert_eq!(b.flag_seq.len(), 3);
1428 assert_eq!(b.flag_seq[0].common.position, 0);
1429 assert_eq!(b.flag_seq[2].common.position, 2);
1430 }
1431
1432 #[test]
1433 fn bitset_builder_two_fields() {
1434 let b = TypeObjectBuilder::bitset("::Packed")
1435 .field("header", 0, 4, 0x07) .field("body", 4, 28, 0x07)
1437 .build_minimal();
1438 assert_eq!(b.field_seq.len(), 2);
1439 assert_eq!(b.field_seq[0].common.bitcount, 4);
1440 assert_eq!(b.field_seq[1].common.position, 4);
1441 }
1442
1443 #[test]
1444 fn bitmask_builder_complete_preserves_names() {
1445 let b = TypeObjectBuilder::bitmask("::Perm")
1446 .bit_bound(16)
1447 .flag("READ", 0)
1448 .flag("WRITE", 1)
1449 .build_complete();
1450 assert_eq!(b.detail.type_name, "Perm");
1451 assert_eq!(b.bit_bound, 16);
1452 assert_eq!(b.flag_seq.len(), 2);
1453 assert_eq!(b.flag_seq[0].detail.name, "READ");
1454 assert_eq!(b.flag_seq[1].detail.name, "WRITE");
1455 }
1456
1457 #[test]
1458 fn bitset_builder_complete_preserves_names() {
1459 let b = TypeObjectBuilder::bitset("::Packed")
1460 .field("header", 0, 4, 0x07)
1461 .field("body", 4, 28, 0x07)
1462 .build_complete();
1463 assert_eq!(b.detail.type_name, "Packed");
1464 assert_eq!(b.field_seq.len(), 2);
1465 assert_eq!(b.field_seq[0].detail.name, "header");
1466 assert_eq!(b.field_seq[1].detail.name, "body");
1467 }
1468}