Skip to main content

zerodds_types/
builder.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3//! Programmatischer Builder fuer TypeObjects.
4//!
5//! Ermoeglicht lesbaren Code wie:
6//!
7//! ```no_run
8//! use zerodds_types::builder::{Extensibility, TypeObjectBuilder};
9//! use zerodds_types::{PrimitiveKind, TypeIdentifier};
10//!
11//! let chatter = TypeObjectBuilder::struct_type("::chat::Chatter")
12//!     .extensibility(Extensibility::Appendable)
13//!     .member(
14//!         "msg_id",
15//!         TypeIdentifier::Primitive(PrimitiveKind::Int64),
16//!         |m| m.key(),
17//!     )
18//!     .member(
19//!         "text",
20//!         TypeIdentifier::String8Small { bound: 255 },
21//!         |m| m,
22//!     )
23//!     .build_complete();
24//! ```
25//!
26//! Scope in T5: StructBuilder, EnumBuilder, AliasBuilder — die drei
27//! am haeufigsten gebrauchten Top-Level-Typen. Union, Collections,
28//! Bitmask, Bitset, Annotation folgen on-demand.
29
30use 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
53/// Extensibility-Kind (§7.2.2.4). Einfachere Darstellung als die
54/// Flag-Bits: genau einer von drei Werten.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum Extensibility {
57    /// `@final` — Typ kann nicht erweitert werden.
58    Final,
59    /// `@appendable` — Neue Felder am Ende (default).
60    Appendable,
61    /// `@mutable` — Jedes Feld mit expliziter @id; beliebige Evolution.
62    Mutable,
63}
64
65impl Default for Extensibility {
66    fn default() -> Self {
67        Self::Appendable
68    }
69}
70
71impl Extensibility {
72    const fn to_flag_bits(self) -> u16 {
73        match self {
74            Self::Final => StructTypeFlag::IS_FINAL,
75            Self::Appendable => StructTypeFlag::IS_APPENDABLE,
76            Self::Mutable => StructTypeFlag::IS_MUTABLE,
77        }
78    }
79}
80
81/// Einstiegspunkt.
82pub struct TypeObjectBuilder;
83
84impl TypeObjectBuilder {
85    /// Startet einen Struct-Builder mit dem angegebenen qualifizierten
86    /// Namen (z.B. "::sensors::Chatter").
87    #[must_use]
88    pub fn struct_type(name: impl Into<String>) -> StructBuilder {
89        StructBuilder {
90            name: name.into(),
91            extensibility: Extensibility::default(),
92            nested: false,
93            autoid_hash: false,
94            base_type: TypeIdentifier::None,
95            members: Vec::new(),
96        }
97    }
98
99    /// Startet einen Enum-Builder.
100    #[must_use]
101    pub fn enum_type(name: impl Into<String>) -> EnumBuilder {
102        EnumBuilder {
103            name: name.into(),
104            bit_bound: 32,
105            literals: Vec::new(),
106        }
107    }
108
109    /// Startet einen Alias-Builder.
110    #[must_use]
111    pub fn alias(name: impl Into<String>, target: TypeIdentifier) -> AliasBuilder {
112        AliasBuilder {
113            name: name.into(),
114            related_type: target,
115        }
116    }
117}
118
119// ============================================================================
120// Struct
121// ============================================================================
122
123/// Builder fuer Struct-Typen.
124pub struct StructBuilder {
125    name: String,
126    extensibility: Extensibility,
127    nested: bool,
128    autoid_hash: bool,
129    base_type: TypeIdentifier,
130    members: Vec<StructMemberSpec>,
131}
132
133/// Innerer State eines Struct-Members — via [`StructMemberBuilder`]
134/// gesetzt.
135pub struct StructMemberSpec {
136    name: String,
137    type_id: TypeIdentifier,
138    explicit_id: Option<u32>,
139    flags: u16,
140    unit: Option<String>,
141    min: Option<Vec<u8>>,
142    max: Option<Vec<u8>>,
143    hash_id: Option<String>,
144    default_value: Option<String>,
145}
146
147/// Fluent-Builder fuer Member-Attribute.
148pub struct StructMemberBuilder<'a> {
149    spec: &'a mut StructMemberSpec,
150}
151
152impl StructMemberBuilder<'_> {
153    /// Markiert Member als `@key`.
154    #[must_use]
155    pub fn key(self) -> Self {
156        self.spec.flags |= StructMemberFlag::IS_KEY;
157        self
158    }
159
160    /// `@optional`.
161    #[must_use]
162    pub fn optional(self) -> Self {
163        self.spec.flags |= StructMemberFlag::IS_OPTIONAL;
164        self
165    }
166
167    /// `@must_understand`.
168    #[must_use]
169    pub fn must_understand(self) -> Self {
170        self.spec.flags |= StructMemberFlag::IS_MUST_UNDERSTAND;
171        self
172    }
173
174    /// `@external` — indirect storage.
175    #[must_use]
176    pub fn external(self) -> Self {
177        self.spec.flags |= StructMemberFlag::IS_EXTERNAL;
178        self
179    }
180
181    /// Explizite `@id(n)`.
182    #[must_use]
183    pub fn id(self, id: u32) -> Self {
184        self.spec.explicit_id = Some(id);
185        self
186    }
187
188    /// `@unit("...")` — nur in Complete sichtbar.
189    #[must_use]
190    pub fn unit(self, unit: impl Into<String>) -> Self {
191        self.spec.unit = Some(unit.into());
192        self
193    }
194
195    /// `@min(val)` — opaque bytes.
196    #[must_use]
197    pub fn min_bytes(self, min: Vec<u8>) -> Self {
198        self.spec.min = Some(min);
199        self
200    }
201
202    /// `@max(val)` — opaque bytes.
203    #[must_use]
204    pub fn max_bytes(self, max: Vec<u8>) -> Self {
205        self.spec.max = Some(max);
206        self
207    }
208
209    /// `@hashid("name")`.
210    #[must_use]
211    pub fn hash_id(self, name: impl Into<String>) -> Self {
212        self.spec.hash_id = Some(name.into());
213        self
214    }
215
216    /// `@default(val)` — XTypes 1.3 §7.2.4.4.4.4.9. Wert als String
217    /// (Encoder-konvertiert beim Wire-Encode). Wird im Complete-
218    /// TypeObject ueber `AppliedBuiltinMemberAnnotations.default_value`
219    /// transportiert.
220    #[must_use]
221    pub fn set_member_default(self, value: impl Into<String>) -> Self {
222        self.spec.default_value = Some(value.into());
223        self
224    }
225}
226
227impl StructBuilder {
228    /// Setzt die Extensibility (default: Appendable).
229    #[must_use]
230    pub fn extensibility(mut self, ext: Extensibility) -> Self {
231        self.extensibility = ext;
232        self
233    }
234
235    /// Markiert als `@nested`.
236    #[must_use]
237    pub fn nested(mut self) -> Self {
238        self.nested = true;
239        self
240    }
241
242    /// Aktiviert `@autoid(HASH)`.
243    #[must_use]
244    pub fn autoid_hash(mut self) -> Self {
245        self.autoid_hash = true;
246        self
247    }
248
249    /// Setzt einen Base-Type fuer Inheritance.
250    #[must_use]
251    pub fn base(mut self, base: TypeIdentifier) -> Self {
252        self.base_type = base;
253        self
254    }
255
256    /// Fuegt einen Member hinzu.
257    ///
258    /// Der Callback erhaelt einen `StructMemberBuilder` um Flags
259    /// und Annotationen zu setzen.
260    #[must_use]
261    pub fn member<F>(mut self, name: impl Into<String>, ty: TypeIdentifier, f: F) -> Self
262    where
263        F: FnOnce(StructMemberBuilder<'_>) -> StructMemberBuilder<'_>,
264    {
265        let mut spec = StructMemberSpec {
266            name: name.into(),
267            type_id: ty,
268            explicit_id: None,
269            flags: 0,
270            unit: None,
271            min: None,
272            max: None,
273            hash_id: None,
274            default_value: None,
275        };
276        let _ = f(StructMemberBuilder { spec: &mut spec });
277        self.members.push(spec);
278        self
279    }
280
281    fn struct_flags(&self) -> StructTypeFlag {
282        let mut bits = self.extensibility.to_flag_bits();
283        if self.nested {
284            bits |= StructTypeFlag::IS_NESTED;
285        }
286        if self.autoid_hash {
287            bits |= StructTypeFlag::IS_AUTOID_HASH;
288        }
289        StructTypeFlag(bits)
290    }
291
292    /// Member-ID-Vergabe:
293    /// - explicit_id, wenn gesetzt
294    /// - sonst autoid-hash (erste 4 bytes SHA-256 ueber Name — vereinfacht)
295    /// - sonst sequentiell ab 1
296    fn resolve_member_ids(&self) -> Vec<u32> {
297        let mut ids = Vec::with_capacity(self.members.len());
298        let mut next_seq: u32 = 1;
299        for spec in &self.members {
300            let id = if let Some(explicit) = spec.explicit_id {
301                explicit
302            } else if self.autoid_hash {
303                // XTypes §7.2.2.4.9 + §7.3.1.2.1.1: fuer `@autoid(HASH)`
304                // wird die Member-ID aus Bits [4..28) (=24 Bits) der ersten
305                // 4 MD5-Bytes des Member-Namens abgeleitet. Bits [0..4)
306                // sind reserviert (E-Flag etc.), werden nicht benutzt.
307                let nh = NameHash::from_name(&spec.name);
308                (u32::from_le_bytes(nh.0) >> 4) & 0x00FF_FFFF
309            } else {
310                let v = next_seq;
311                next_seq += 1;
312                v
313            };
314            ids.push(id);
315        }
316        ids
317    }
318
319    fn member_common(spec: &StructMemberSpec, id: u32) -> CommonStructMember {
320        CommonStructMember {
321            member_id: id,
322            member_flags: StructMemberFlag(spec.flags),
323            member_type_id: spec.type_id.clone(),
324        }
325    }
326
327    fn member_detail(spec: &StructMemberSpec) -> CompleteMemberDetail {
328        CompleteMemberDetail {
329            name: spec.name.clone(),
330            ann_builtin: AppliedBuiltinMemberAnnotations {
331                unit: spec.unit.clone(),
332                min: spec.min.clone(),
333                max: spec.max.clone(),
334                hash_id: spec.hash_id.clone(),
335                default_value: spec.default_value.clone(),
336            },
337            ann_custom: OptionalAppliedAnnotationSeq::default(),
338        }
339    }
340
341    /// Baut einen `MinimalStructType`.
342    #[must_use]
343    pub fn build_minimal(&self) -> MinimalStructType {
344        let ids = self.resolve_member_ids();
345        let member_seq = self
346            .members
347            .iter()
348            .zip(ids.iter())
349            .map(|(spec, id)| MinimalStructMember {
350                common: Self::member_common(spec, *id),
351                detail: NameHash::from_name(&spec.name),
352            })
353            .collect();
354        MinimalStructType {
355            struct_flags: self.struct_flags(),
356            header: MinimalStructHeader {
357                base_type: self.base_type.clone(),
358            },
359            member_seq,
360        }
361    }
362
363    /// Baut einen `CompleteStructType`.
364    #[must_use]
365    pub fn build_complete(&self) -> CompleteStructType {
366        let ids = self.resolve_member_ids();
367        let member_seq = self
368            .members
369            .iter()
370            .zip(ids.iter())
371            .map(|(spec, id)| CompleteStructMember {
372                common: Self::member_common(spec, *id),
373                detail: Self::member_detail(spec),
374            })
375            .collect();
376        CompleteStructType {
377            struct_flags: self.struct_flags(),
378            header: CompleteStructHeader {
379                base_type: self.base_type.clone(),
380                detail: CompleteTypeDetail {
381                    ann_builtin: AppliedBuiltinTypeAnnotations::default(),
382                    ann_custom: OptionalAppliedAnnotationSeq::default(),
383                    type_name: self.name.clone(),
384                },
385            },
386            member_seq,
387        }
388    }
389}
390
391// ============================================================================
392// Enum
393// ============================================================================
394
395/// Builder fuer Enumerated-Typen.
396pub struct EnumBuilder {
397    name: String,
398    bit_bound: u16,
399    literals: Vec<EnumLiteralSpec>,
400}
401
402struct EnumLiteralSpec {
403    name: String,
404    value: i32,
405    is_default: bool,
406}
407
408impl EnumBuilder {
409    /// Setzt die bit-Breite (8/16/32, default 32).
410    #[must_use]
411    pub fn bit_bound(mut self, bits: u16) -> Self {
412        self.bit_bound = bits;
413        self
414    }
415
416    /// Fuegt ein Literal hinzu.
417    #[must_use]
418    pub fn literal(mut self, name: impl Into<String>, value: i32) -> Self {
419        self.literals.push(EnumLiteralSpec {
420            name: name.into(),
421            value,
422            is_default: false,
423        });
424        self
425    }
426
427    /// Fuegt das Default-Literal hinzu (`@default_literal`).
428    #[must_use]
429    pub fn default_literal(mut self, name: impl Into<String>, value: i32) -> Self {
430        self.literals.push(EnumLiteralSpec {
431            name: name.into(),
432            value,
433            is_default: true,
434        });
435        self
436    }
437
438    /// Baut ein `MinimalEnumeratedType`.
439    #[must_use]
440    pub fn build_minimal(&self) -> MinimalEnumeratedType {
441        MinimalEnumeratedType {
442            enum_flags: EnumTypeFlag::default(),
443            header: MinimalEnumeratedHeader {
444                common: CommonEnumeratedHeader {
445                    bit_bound: self.bit_bound,
446                },
447            },
448            literal_seq: self
449                .literals
450                .iter()
451                .map(|l| MinimalEnumeratedLiteral {
452                    common: CommonEnumeratedLiteral {
453                        value: l.value,
454                        flags: EnumLiteralFlag(if l.is_default {
455                            EnumLiteralFlag::IS_DEFAULT_LITERAL
456                        } else {
457                            0
458                        }),
459                    },
460                    detail: NameHash::from_name(&l.name),
461                })
462                .collect(),
463        }
464    }
465
466    /// Baut ein `CompleteEnumeratedType`.
467    #[must_use]
468    pub fn build_complete(&self) -> CompleteEnumeratedType {
469        CompleteEnumeratedType {
470            enum_flags: EnumTypeFlag::default(),
471            header: CompleteEnumeratedHeader {
472                common: CommonEnumeratedHeader {
473                    bit_bound: self.bit_bound,
474                },
475                detail: CompleteTypeDetail {
476                    ann_builtin: AppliedBuiltinTypeAnnotations::default(),
477                    ann_custom: OptionalAppliedAnnotationSeq::default(),
478                    type_name: self.name.clone(),
479                },
480            },
481            literal_seq: self
482                .literals
483                .iter()
484                .map(|l| CompleteEnumeratedLiteral {
485                    common: CommonEnumeratedLiteral {
486                        value: l.value,
487                        flags: EnumLiteralFlag(if l.is_default {
488                            EnumLiteralFlag::IS_DEFAULT_LITERAL
489                        } else {
490                            0
491                        }),
492                    },
493                    detail: CompleteMemberDetail {
494                        name: l.name.clone(),
495                        ann_builtin: AppliedBuiltinMemberAnnotations::default(),
496                        ann_custom: OptionalAppliedAnnotationSeq::default(),
497                    },
498                })
499                .collect(),
500        }
501    }
502}
503
504// ============================================================================
505// Alias
506// ============================================================================
507
508/// Builder fuer Alias/Typedef.
509pub struct AliasBuilder {
510    name: String,
511    related_type: TypeIdentifier,
512}
513
514impl AliasBuilder {
515    /// Minimal-Alias.
516    #[must_use]
517    pub fn build_minimal(&self) -> MinimalAliasType {
518        MinimalAliasType {
519            alias_flags: AliasTypeFlag::default(),
520            body: MinimalAliasBody {
521                common: CommonAliasBody {
522                    related_flags: AliasMemberFlag::default(),
523                    related_type: self.related_type.clone(),
524                },
525            },
526        }
527    }
528
529    /// Complete-Alias.
530    #[must_use]
531    pub fn build_complete(&self) -> CompleteAliasType {
532        CompleteAliasType {
533            alias_flags: AliasTypeFlag::default(),
534            header: CompleteAliasHeader {
535                detail: CompleteTypeDetail {
536                    ann_builtin: AppliedBuiltinTypeAnnotations::default(),
537                    ann_custom: OptionalAppliedAnnotationSeq::default(),
538                    type_name: self.name.clone(),
539                },
540            },
541            body: CompleteAliasBody {
542                related_flags: AliasMemberFlag::default(),
543                related_type: self.related_type.clone(),
544                ann_builtin: AppliedBuiltinMemberAnnotations::default(),
545                ann_custom: OptionalAppliedAnnotationSeq::default(),
546            },
547        }
548    }
549}
550
551// ============================================================================
552// Union
553// ============================================================================
554
555/// Builder fuer Union-Typen.
556pub struct UnionBuilder {
557    name: String,
558    extensibility: Extensibility,
559    discriminator_type: TypeIdentifier,
560    cases: Vec<UnionCaseSpec>,
561}
562
563struct UnionCaseSpec {
564    name: String,
565    member_id: Option<u32>,
566    type_id: TypeIdentifier,
567    labels: Vec<i32>,
568    is_default: bool,
569}
570
571impl UnionBuilder {
572    /// Setzt die Extensibility (default Appendable).
573    #[must_use]
574    pub fn extensibility(mut self, ext: Extensibility) -> Self {
575        self.extensibility = ext;
576        self
577    }
578
579    /// Fuegt einen Case-Member hinzu.
580    #[must_use]
581    pub fn case(mut self, name: impl Into<String>, ty: TypeIdentifier, labels: Vec<i32>) -> Self {
582        self.cases.push(UnionCaseSpec {
583            name: name.into(),
584            member_id: None,
585            type_id: ty,
586            labels,
587            is_default: false,
588        });
589        self
590    }
591
592    /// Fuegt den Default-Case hinzu.
593    #[must_use]
594    pub fn default_case(mut self, name: impl Into<String>, ty: TypeIdentifier) -> Self {
595        self.cases.push(UnionCaseSpec {
596            name: name.into(),
597            member_id: None,
598            type_id: ty,
599            labels: Vec::new(),
600            is_default: true,
601        });
602        self
603    }
604
605    fn union_flags(&self) -> crate::type_object::flags::UnionTypeFlag {
606        use crate::type_object::flags::UnionTypeFlag;
607        // UnionTypeFlag verwendet analog die Struct-Bits fuer
608        // Extensibility (§7.3.4.5) — reuse die Bit-Positionen.
609        UnionTypeFlag(match self.extensibility {
610            Extensibility::Final => StructTypeFlag::IS_FINAL,
611            Extensibility::Appendable => StructTypeFlag::IS_APPENDABLE,
612            Extensibility::Mutable => StructTypeFlag::IS_MUTABLE,
613        })
614    }
615
616    fn resolve_case_ids(&self) -> Vec<u32> {
617        let mut ids = Vec::with_capacity(self.cases.len());
618        let mut next: u32 = 1;
619        for c in &self.cases {
620            ids.push(c.member_id.unwrap_or_else(|| {
621                let v = next;
622                next += 1;
623                v
624            }));
625        }
626        ids
627    }
628
629    /// Baut `MinimalUnionType`.
630    #[must_use]
631    pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalUnionType {
632        use crate::type_object::common::CommonUnionMember;
633        use crate::type_object::flags::{UnionDiscriminatorFlag, UnionMemberFlag};
634        use crate::type_object::minimal::{
635            CommonDiscriminatorMember, MinimalDiscriminatorMember, MinimalUnionMember,
636            MinimalUnionType,
637        };
638        let ids = self.resolve_case_ids();
639        let member_seq = self
640            .cases
641            .iter()
642            .zip(ids.iter())
643            .map(|(c, id)| MinimalUnionMember {
644                common: CommonUnionMember {
645                    member_id: *id,
646                    member_flags: UnionMemberFlag(if c.is_default {
647                        UnionMemberFlag::IS_DEFAULT
648                    } else {
649                        0
650                    }),
651                    type_id: c.type_id.clone(),
652                    label_seq: c.labels.clone(),
653                },
654                detail: NameHash::from_name(&c.name),
655            })
656            .collect();
657        MinimalUnionType {
658            union_flags: self.union_flags(),
659            discriminator: MinimalDiscriminatorMember {
660                common: CommonDiscriminatorMember {
661                    member_flags: UnionDiscriminatorFlag::default(),
662                    type_id: self.discriminator_type.clone(),
663                },
664            },
665            member_seq,
666        }
667    }
668
669    /// Baut `CompleteUnionType`.
670    #[must_use]
671    pub fn build_complete(&self) -> crate::type_object::complete::CompleteUnionType {
672        use crate::type_object::common::CommonUnionMember;
673        use crate::type_object::complete::{
674            CompleteDiscriminatorMember, CompleteUnionHeader, CompleteUnionMember,
675            CompleteUnionType,
676        };
677        use crate::type_object::flags::{UnionDiscriminatorFlag, UnionMemberFlag};
678        use crate::type_object::minimal::CommonDiscriminatorMember;
679        let ids = self.resolve_case_ids();
680        let member_seq = self
681            .cases
682            .iter()
683            .zip(ids.iter())
684            .map(|(c, id)| CompleteUnionMember {
685                common: CommonUnionMember {
686                    member_id: *id,
687                    member_flags: UnionMemberFlag(if c.is_default {
688                        UnionMemberFlag::IS_DEFAULT
689                    } else {
690                        0
691                    }),
692                    type_id: c.type_id.clone(),
693                    label_seq: c.labels.clone(),
694                },
695                detail: CompleteMemberDetail {
696                    name: c.name.clone(),
697                    ann_builtin: AppliedBuiltinMemberAnnotations::default(),
698                    ann_custom: OptionalAppliedAnnotationSeq::default(),
699                },
700            })
701            .collect();
702        CompleteUnionType {
703            union_flags: self.union_flags(),
704            header: CompleteUnionHeader {
705                detail: CompleteTypeDetail {
706                    ann_builtin: AppliedBuiltinTypeAnnotations::default(),
707                    ann_custom: OptionalAppliedAnnotationSeq::default(),
708                    type_name: self.name.clone(),
709                },
710            },
711            discriminator: CompleteDiscriminatorMember {
712                common: CommonDiscriminatorMember {
713                    member_flags: UnionDiscriminatorFlag::default(),
714                    type_id: self.discriminator_type.clone(),
715                },
716                ann_builtin: AppliedBuiltinTypeAnnotations::default(),
717                ann_custom: OptionalAppliedAnnotationSeq::default(),
718            },
719            member_seq,
720        }
721    }
722}
723
724// ============================================================================
725// Sequence / Array / Map
726// ============================================================================
727
728/// Builder fuer `sequence<T, N>`.
729pub struct SequenceBuilder {
730    element: TypeIdentifier,
731    bound: u32,
732}
733
734impl SequenceBuilder {
735    /// Baut MinimalSequenceType.
736    #[must_use]
737    pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalSequenceType {
738        use crate::type_object::flags::{CollectionElementFlag, CollectionTypeFlag};
739        use crate::type_object::minimal::{
740            CommonCollectionElement, MinimalCollectionElement, MinimalSequenceType,
741        };
742        MinimalSequenceType {
743            collection_flag: CollectionTypeFlag::default(),
744            bound: self.bound,
745            element: MinimalCollectionElement {
746                common: CommonCollectionElement {
747                    element_flags: CollectionElementFlag::default(),
748                    type_id: self.element.clone(),
749                },
750            },
751        }
752    }
753}
754
755/// Builder fuer `T[D1, D2, ...]`.
756pub struct ArrayBuilder {
757    element: TypeIdentifier,
758    dimensions: Vec<u32>,
759}
760
761impl ArrayBuilder {
762    /// Baut MinimalArrayType.
763    #[must_use]
764    pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalArrayType {
765        use crate::type_object::flags::{CollectionElementFlag, CollectionTypeFlag};
766        use crate::type_object::minimal::{
767            CommonCollectionElement, MinimalArrayType, MinimalCollectionElement,
768        };
769        MinimalArrayType {
770            collection_flag: CollectionTypeFlag::default(),
771            bound_seq: self.dimensions.clone(),
772            element: MinimalCollectionElement {
773                common: CommonCollectionElement {
774                    element_flags: CollectionElementFlag::default(),
775                    type_id: self.element.clone(),
776                },
777            },
778        }
779    }
780}
781
782/// Validierungs-Fehler beim Bauen von Collection-Typen.
783#[derive(Debug, Clone, PartialEq, Eq)]
784pub enum BuilderError {
785    /// MUTABLE-Extensibility ist auf Maps nicht erlaubt
786    /// (XTypes 1.3 §7.4.3.5.3 Rules 11-16). Spec erlaubt nur FINAL/
787    /// APPENDABLE; MUTABLE wird historisch silent als APPENDABLE
788    /// behandelt. Dieser Fehler verhindert die silent demotion.
789    MutableMapExtensibilityNotAllowed,
790}
791
792/// Builder fuer `map<K, V, N>`.
793pub struct MapBuilder {
794    key: TypeIdentifier,
795    value: TypeIdentifier,
796    bound: u32,
797}
798
799impl MapBuilder {
800    /// Validierender Builder: erlaubt nur FINAL/APPENDABLE-Extensibility.
801    /// MUTABLE wirft `BuilderError::MutableMapExtensibilityNotAllowed`
802    /// (XTypes 1.3 §7.4.3.5.3 Rules 11-16).
803    ///
804    /// # Errors
805    /// `MutableMapExtensibilityNotAllowed` wenn `ext == Mutable`.
806    pub fn add_map_member(
807        self,
808        ext: Extensibility,
809    ) -> Result<crate::type_object::minimal::MinimalMapType, BuilderError> {
810        if matches!(ext, Extensibility::Mutable) {
811            return Err(BuilderError::MutableMapExtensibilityNotAllowed);
812        }
813        Ok(self.build_minimal())
814    }
815
816    /// Baut MinimalMapType.
817    #[must_use]
818    pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalMapType {
819        use crate::type_object::flags::{CollectionElementFlag, CollectionTypeFlag};
820        use crate::type_object::minimal::{
821            CommonCollectionElement, MinimalCollectionElement, MinimalMapType,
822        };
823        let element = MinimalCollectionElement {
824            common: CommonCollectionElement {
825                element_flags: CollectionElementFlag::default(),
826                type_id: self.value.clone(),
827            },
828        };
829        let key = MinimalCollectionElement {
830            common: CommonCollectionElement {
831                element_flags: CollectionElementFlag::default(),
832                type_id: self.key.clone(),
833            },
834        };
835        MinimalMapType {
836            collection_flag: CollectionTypeFlag::default(),
837            bound: self.bound,
838            key,
839            element,
840        }
841    }
842}
843
844// ============================================================================
845// Bitmask / Bitset
846// ============================================================================
847
848/// Builder fuer `bitmask`-Typen.
849pub struct BitmaskBuilder {
850    name: String,
851    bit_bound: u16,
852    flags: Vec<(String, u16)>,
853}
854
855impl BitmaskBuilder {
856    /// Bit-Breite (default 32).
857    #[must_use]
858    pub fn bit_bound(mut self, bits: u16) -> Self {
859        self.bit_bound = bits;
860        self
861    }
862
863    /// Fuegt ein Bit-Flag hinzu.
864    #[must_use]
865    pub fn flag(mut self, name: impl Into<String>, position: u16) -> Self {
866        self.flags.push((name.into(), position));
867        self
868    }
869
870    /// Baut MinimalBitmaskType.
871    #[must_use]
872    pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalBitmaskType {
873        use crate::type_object::flags::{BitflagFlag, BitmaskTypeFlag};
874        use crate::type_object::minimal::{CommonBitflag, MinimalBitflag, MinimalBitmaskType};
875        MinimalBitmaskType {
876            bitmask_flags: BitmaskTypeFlag::default(),
877            bit_bound: self.bit_bound,
878            flag_seq: self
879                .flags
880                .iter()
881                .map(|(n, p)| MinimalBitflag {
882                    common: CommonBitflag {
883                        position: *p,
884                        flags: BitflagFlag::default(),
885                    },
886                    detail: NameHash::from_name(n),
887                })
888                .collect(),
889        }
890    }
891
892    /// Baut `CompleteBitmaskType` (mit Namen + Annotations-Placeholder).
893    #[must_use]
894    pub fn build_complete(&self) -> crate::type_object::complete::CompleteBitmaskType {
895        use crate::type_object::common::{
896            AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
897            CompleteTypeDetail, OptionalAppliedAnnotationSeq,
898        };
899        use crate::type_object::complete::{CompleteBitflag, CompleteBitmaskType};
900        use crate::type_object::flags::{BitflagFlag, BitmaskTypeFlag};
901        CompleteBitmaskType {
902            bitmask_flags: BitmaskTypeFlag::default(),
903            bit_bound: self.bit_bound,
904            detail: CompleteTypeDetail {
905                ann_builtin: AppliedBuiltinTypeAnnotations::default(),
906                ann_custom: OptionalAppliedAnnotationSeq::default(),
907                type_name: self.name.clone(),
908            },
909            flag_seq: self
910                .flags
911                .iter()
912                .map(|(n, p)| CompleteBitflag {
913                    common: crate::type_object::minimal::CommonBitflag {
914                        position: *p,
915                        flags: BitflagFlag::default(),
916                    },
917                    detail: CompleteMemberDetail {
918                        name: n.clone(),
919                        ann_builtin: AppliedBuiltinMemberAnnotations::default(),
920                        ann_custom: OptionalAppliedAnnotationSeq::default(),
921                    },
922                })
923                .collect(),
924        }
925    }
926
927    /// Getter — meist ueber [`build_complete`] genutzt.
928    #[must_use]
929    pub fn name(&self) -> &str {
930        &self.name
931    }
932}
933
934/// Builder fuer `bitset`-Typen.
935pub struct BitsetBuilder {
936    name: String,
937    fields: Vec<BitfieldSpec>,
938}
939
940struct BitfieldSpec {
941    name: String,
942    position: u16,
943    bitcount: u8,
944    holder_type: u8,
945}
946
947impl BitsetBuilder {
948    /// Fuegt ein Bitfield hinzu.
949    #[must_use]
950    pub fn field(
951        mut self,
952        name: impl Into<String>,
953        position: u16,
954        bitcount: u8,
955        holder_type: u8,
956    ) -> Self {
957        self.fields.push(BitfieldSpec {
958            name: name.into(),
959            position,
960            bitcount,
961            holder_type,
962        });
963        self
964    }
965
966    /// Baut MinimalBitsetType.
967    #[must_use]
968    pub fn build_minimal(&self) -> crate::type_object::minimal::MinimalBitsetType {
969        use crate::type_object::flags::{BitfieldFlag, BitsetTypeFlag};
970        use crate::type_object::minimal::{CommonBitfield, MinimalBitfield, MinimalBitsetType};
971        MinimalBitsetType {
972            bitset_flags: BitsetTypeFlag::default(),
973            field_seq: self
974                .fields
975                .iter()
976                .map(|f| MinimalBitfield {
977                    common: CommonBitfield {
978                        position: f.position,
979                        flags: BitfieldFlag::default(),
980                        bitcount: f.bitcount,
981                        holder_type: f.holder_type,
982                    },
983                    name_hash: NameHash::from_name(&f.name),
984                })
985                .collect(),
986        }
987    }
988
989    /// Baut `CompleteBitsetType` (mit Namen + Annotations-Placeholder).
990    #[must_use]
991    pub fn build_complete(&self) -> crate::type_object::complete::CompleteBitsetType {
992        use crate::type_object::common::{
993            AppliedBuiltinMemberAnnotations, AppliedBuiltinTypeAnnotations, CompleteMemberDetail,
994            CompleteTypeDetail, OptionalAppliedAnnotationSeq,
995        };
996        use crate::type_object::complete::{CompleteBitfield, CompleteBitsetType};
997        use crate::type_object::flags::{BitfieldFlag, BitsetTypeFlag};
998        CompleteBitsetType {
999            bitset_flags: BitsetTypeFlag::default(),
1000            detail: CompleteTypeDetail {
1001                ann_builtin: AppliedBuiltinTypeAnnotations::default(),
1002                ann_custom: OptionalAppliedAnnotationSeq::default(),
1003                type_name: self.name.clone(),
1004            },
1005            field_seq: self
1006                .fields
1007                .iter()
1008                .map(|f| CompleteBitfield {
1009                    common: crate::type_object::minimal::CommonBitfield {
1010                        position: f.position,
1011                        flags: BitfieldFlag::default(),
1012                        bitcount: f.bitcount,
1013                        holder_type: f.holder_type,
1014                    },
1015                    detail: CompleteMemberDetail {
1016                        name: f.name.clone(),
1017                        ann_builtin: AppliedBuiltinMemberAnnotations::default(),
1018                        ann_custom: OptionalAppliedAnnotationSeq::default(),
1019                    },
1020                })
1021                .collect(),
1022        }
1023    }
1024
1025    /// Getter — meist ueber [`build_complete`] genutzt.
1026    #[must_use]
1027    pub fn name(&self) -> &str {
1028        &self.name
1029    }
1030}
1031
1032// ============================================================================
1033// Einstiegspunkte fuer die neuen Builder
1034// ============================================================================
1035
1036impl TypeObjectBuilder {
1037    /// Startet einen Union-Builder. `discriminator_type` ist typisch
1038    /// ein Enum oder Integer-Primitiv.
1039    #[must_use]
1040    pub fn union_type(name: impl Into<String>, discriminator_type: TypeIdentifier) -> UnionBuilder {
1041        UnionBuilder {
1042            name: name.into(),
1043            extensibility: Extensibility::default(),
1044            discriminator_type,
1045            cases: Vec::new(),
1046        }
1047    }
1048
1049    /// Startet einen Sequence-Builder. `bound=0` = unbounded.
1050    #[must_use]
1051    pub fn sequence(element: TypeIdentifier, bound: u32) -> SequenceBuilder {
1052        SequenceBuilder { element, bound }
1053    }
1054
1055    /// Startet einen Array-Builder mit der angegebenen Dimensions-Liste.
1056    #[must_use]
1057    pub fn array(element: TypeIdentifier, dimensions: Vec<u32>) -> ArrayBuilder {
1058        ArrayBuilder {
1059            element,
1060            dimensions,
1061        }
1062    }
1063
1064    /// Startet einen Map-Builder.
1065    #[must_use]
1066    pub fn map(key: TypeIdentifier, value: TypeIdentifier, bound: u32) -> MapBuilder {
1067        MapBuilder { key, value, bound }
1068    }
1069
1070    /// Startet einen Bitmask-Builder.
1071    #[must_use]
1072    pub fn bitmask(name: impl Into<String>) -> BitmaskBuilder {
1073        BitmaskBuilder {
1074            name: name.into(),
1075            bit_bound: 32,
1076            flags: Vec::new(),
1077        }
1078    }
1079
1080    /// Startet einen Bitset-Builder.
1081    #[must_use]
1082    pub fn bitset(name: impl Into<String>) -> BitsetBuilder {
1083        BitsetBuilder {
1084            name: name.into(),
1085            fields: Vec::new(),
1086        }
1087    }
1088}
1089
1090// ============================================================================
1091// Tests
1092// ============================================================================
1093
1094#[cfg(test)]
1095#[allow(clippy::unwrap_used)]
1096mod tests {
1097    use super::*;
1098    use crate::type_identifier::PrimitiveKind;
1099    use crate::type_object::flags::StructTypeFlag;
1100
1101    #[test]
1102    fn struct_builder_basic_with_two_members() {
1103        let st = TypeObjectBuilder::struct_type("::chat::Chatter")
1104            .member(
1105                "sensor_id",
1106                TypeIdentifier::Primitive(PrimitiveKind::Int64),
1107                |m| m.key(),
1108            )
1109            .member("text", TypeIdentifier::String8Small { bound: 255 }, |m| m)
1110            .build_minimal();
1111
1112        assert_eq!(st.member_seq.len(), 2);
1113        assert_eq!(st.member_seq[0].common.member_id, 1);
1114        assert!(
1115            st.member_seq[0]
1116                .common
1117                .member_flags
1118                .has(StructMemberFlag::IS_KEY)
1119        );
1120        assert_eq!(st.member_seq[1].common.member_id, 2);
1121        // NameHash deterministisch: MD5("sensor_id")[0..4]
1122        assert_eq!(st.member_seq[0].detail, NameHash::from_name("sensor_id"));
1123        assert_eq!(st.member_seq[1].detail, NameHash::from_name("text"));
1124    }
1125
1126    #[test]
1127    fn struct_builder_explicit_ids_respected() {
1128        let st = TypeObjectBuilder::struct_type("::X")
1129            .member("a", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1130                m.id(100)
1131            })
1132            .member("b", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1133                m.id(200)
1134            })
1135            .build_minimal();
1136        assert_eq!(st.member_seq[0].common.member_id, 100);
1137        assert_eq!(st.member_seq[1].common.member_id, 200);
1138    }
1139
1140    #[test]
1141    fn mutable_map_extensibility_is_error() {
1142        // §7.4.3.5.3 Rules 11-16 — MUTABLE-Map ist verboten (silent demotion).
1143        let res = TypeObjectBuilder::map(
1144            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1145            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1146            10,
1147        )
1148        .add_map_member(Extensibility::Mutable);
1149        assert!(matches!(
1150            res,
1151            Err(BuilderError::MutableMapExtensibilityNotAllowed)
1152        ));
1153    }
1154
1155    #[test]
1156    fn appendable_map_extensibility_is_ok() {
1157        let res = TypeObjectBuilder::map(
1158            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1159            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1160            10,
1161        )
1162        .add_map_member(Extensibility::Appendable);
1163        assert!(res.is_ok());
1164    }
1165
1166    #[test]
1167    fn final_map_extensibility_is_ok() {
1168        let res = TypeObjectBuilder::map(
1169            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1170            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1171            10,
1172        )
1173        .add_map_member(Extensibility::Final);
1174        assert!(res.is_ok());
1175    }
1176
1177    #[test]
1178    fn member_with_explicit_default_used_when_field_missing() {
1179        // §7.2.4.4.4.4.9 — `set_member_default` setzt
1180        // `AppliedBuiltinMemberAnnotations.default_value`. Test stellt
1181        // sicher, dass der Wert ueber die Complete-Pipeline durchreicht.
1182        let st = TypeObjectBuilder::struct_type("::S")
1183            .member("a", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1184                m.set_member_default("42")
1185            })
1186            .build_complete();
1187        assert_eq!(
1188            st.member_seq[0].detail.ann_builtin.default_value.as_deref(),
1189            Some("42")
1190        );
1191    }
1192
1193    #[test]
1194    fn default_overrides_implicit_zero() {
1195        // Encoder-Side Hint: ein expliziter `@default("99")` muss im
1196        // Complete-TypeObject erscheinen — der Decoder verwendet ihn,
1197        // wenn das Feld bei Optional-Mutable-Members fehlt, statt der
1198        // typ-impliziten Null.
1199        let st = TypeObjectBuilder::struct_type("::S")
1200            .member("a", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| {
1201                m.set_member_default("99")
1202            })
1203            .member("b", TypeIdentifier::Primitive(PrimitiveKind::Int32), |m| m)
1204            .build_complete();
1205        assert_eq!(
1206            st.member_seq[0].detail.ann_builtin.default_value.as_deref(),
1207            Some("99")
1208        );
1209        assert_eq!(st.member_seq[1].detail.ann_builtin.default_value, None);
1210    }
1211
1212    #[test]
1213    fn default_value_roundtrips_via_encode_decode() {
1214        use crate::type_object::common::AppliedBuiltinMemberAnnotations;
1215        use alloc::vec;
1216        use zerodds_cdr::{BufferReader, BufferWriter, Endianness};
1217        let ann = AppliedBuiltinMemberAnnotations {
1218            unit: Some("meters".into()),
1219            min: Some(vec![0]),
1220            max: Some(vec![100]),
1221            hash_id: None,
1222            default_value: Some("17".into()),
1223        };
1224        let mut w = BufferWriter::new(Endianness::Little);
1225        ann.encode_into(&mut w).unwrap();
1226        let bytes = w.into_bytes();
1227        let mut r = BufferReader::new(&bytes, Endianness::Little);
1228        let decoded = AppliedBuiltinMemberAnnotations::decode_from(&mut r).unwrap();
1229        assert_eq!(decoded, ann);
1230    }
1231
1232    #[test]
1233    fn struct_builder_extensibility_mutable() {
1234        let st = TypeObjectBuilder::struct_type("::Y")
1235            .extensibility(Extensibility::Mutable)
1236            .build_minimal();
1237        assert!(st.struct_flags.has(StructTypeFlag::IS_MUTABLE));
1238        assert!(!st.struct_flags.has(StructTypeFlag::IS_APPENDABLE));
1239    }
1240
1241    #[test]
1242    fn complete_builder_preserves_names() {
1243        let st = TypeObjectBuilder::struct_type("::sensors::Chatter")
1244            .extensibility(Extensibility::Appendable)
1245            .member(
1246                "sensor_id",
1247                TypeIdentifier::Primitive(PrimitiveKind::Int64),
1248                |m| m.key().unit("celsius"),
1249            )
1250            .build_complete();
1251        assert_eq!(st.header.detail.type_name, "::sensors::Chatter");
1252        assert_eq!(st.member_seq[0].detail.name, "sensor_id");
1253        assert_eq!(
1254            st.member_seq[0].detail.ann_builtin.unit.as_deref(),
1255            Some("celsius")
1256        );
1257    }
1258
1259    #[test]
1260    fn struct_builder_autoid_hash_collision_free_for_distinct_names() {
1261        let st = TypeObjectBuilder::struct_type("::H")
1262            .autoid_hash()
1263            .member(
1264                "alpha",
1265                TypeIdentifier::Primitive(PrimitiveKind::Int32),
1266                |m| m,
1267            )
1268            .member(
1269                "beta",
1270                TypeIdentifier::Primitive(PrimitiveKind::Int32),
1271                |m| m,
1272            )
1273            .build_minimal();
1274        assert!(st.struct_flags.has(StructTypeFlag::IS_AUTOID_HASH));
1275        assert_ne!(
1276            st.member_seq[0].common.member_id,
1277            st.member_seq[1].common.member_id
1278        );
1279    }
1280
1281    #[test]
1282    fn enum_builder_roundtrip_ready() {
1283        let e = TypeObjectBuilder::enum_type("::Color")
1284            .bit_bound(16)
1285            .default_literal("RED", 0)
1286            .literal("GREEN", 1)
1287            .literal("BLUE", 2)
1288            .build_minimal();
1289        assert_eq!(e.header.common.bit_bound, 16);
1290        assert_eq!(e.literal_seq.len(), 3);
1291        assert!(e.literal_seq[0].common.flags.0 & EnumLiteralFlag::IS_DEFAULT_LITERAL != 0);
1292    }
1293
1294    #[test]
1295    fn alias_builder_minimal_and_complete() {
1296        let a_min =
1297            TypeObjectBuilder::alias("::Count", TypeIdentifier::Primitive(PrimitiveKind::UInt64))
1298                .build_minimal();
1299        assert!(matches!(
1300            a_min.body.common.related_type,
1301            TypeIdentifier::Primitive(PrimitiveKind::UInt64)
1302        ));
1303
1304        let a_cmp =
1305            TypeObjectBuilder::alias("::Count", TypeIdentifier::Primitive(PrimitiveKind::UInt64))
1306                .build_complete();
1307        assert_eq!(a_cmp.header.detail.type_name, "::Count");
1308    }
1309
1310    // ------------------------------------------------------------------
1311    // Neue Builder (T#2 — Union / Collections / Bitmask / Bitset)
1312    // ------------------------------------------------------------------
1313
1314    #[test]
1315    fn union_builder_minimal_with_two_cases_and_default() {
1316        let u = TypeObjectBuilder::union_type(
1317            "::Shape",
1318            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1319        )
1320        .case(
1321            "circle",
1322            TypeIdentifier::Primitive(PrimitiveKind::Float64),
1323            alloc::vec![1, 2],
1324        )
1325        .default_case("other", TypeIdentifier::String8Small { bound: 64 })
1326        .build_minimal();
1327        assert_eq!(u.member_seq.len(), 2);
1328        assert_eq!(u.member_seq[0].common.label_seq, alloc::vec![1, 2]);
1329        // Default-Case hat IS_DEFAULT-Bit.
1330        assert!(
1331            u.member_seq[1].common.member_flags.0
1332                & crate::type_object::flags::UnionMemberFlag::IS_DEFAULT
1333                != 0
1334        );
1335    }
1336
1337    #[test]
1338    fn union_builder_complete_preserves_names_and_extensibility() {
1339        let u = TypeObjectBuilder::union_type(
1340            "::Shape",
1341            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1342        )
1343        .extensibility(Extensibility::Mutable)
1344        .case(
1345            "a",
1346            TypeIdentifier::Primitive(PrimitiveKind::Int32),
1347            alloc::vec![1],
1348        )
1349        .build_complete();
1350        assert_eq!(u.header.detail.type_name, "::Shape");
1351        assert_eq!(u.member_seq[0].detail.name, "a");
1352        assert_eq!(
1353            u.union_flags.0 & StructTypeFlag::IS_MUTABLE,
1354            StructTypeFlag::IS_MUTABLE
1355        );
1356    }
1357
1358    #[test]
1359    fn sequence_builder_minimal() {
1360        let s = TypeObjectBuilder::sequence(TypeIdentifier::Primitive(PrimitiveKind::Int16), 100)
1361            .build_minimal();
1362        assert_eq!(s.bound, 100);
1363        assert!(matches!(
1364            s.element.common.type_id,
1365            TypeIdentifier::Primitive(PrimitiveKind::Int16)
1366        ));
1367    }
1368
1369    #[test]
1370    fn array_builder_3d() {
1371        let a = TypeObjectBuilder::array(
1372            TypeIdentifier::Primitive(PrimitiveKind::Float32),
1373            alloc::vec![4, 4, 4],
1374        )
1375        .build_minimal();
1376        assert_eq!(a.bound_seq, alloc::vec![4, 4, 4]);
1377    }
1378
1379    #[test]
1380    fn map_builder_string_to_int() {
1381        let m = TypeObjectBuilder::map(
1382            TypeIdentifier::String8Small { bound: 64 },
1383            TypeIdentifier::Primitive(PrimitiveKind::Int64),
1384            1_000,
1385        )
1386        .build_minimal();
1387        assert_eq!(m.bound, 1_000);
1388        assert!(matches!(
1389            m.key.common.type_id,
1390            TypeIdentifier::String8Small { bound: 64 }
1391        ));
1392    }
1393
1394    #[test]
1395    fn bitmask_builder_three_flags() {
1396        let b = TypeObjectBuilder::bitmask("::Permissions")
1397            .bit_bound(32)
1398            .flag("READ", 0)
1399            .flag("WRITE", 1)
1400            .flag("EXEC", 2)
1401            .build_minimal();
1402        assert_eq!(b.bit_bound, 32);
1403        assert_eq!(b.flag_seq.len(), 3);
1404        assert_eq!(b.flag_seq[0].common.position, 0);
1405        assert_eq!(b.flag_seq[2].common.position, 2);
1406    }
1407
1408    #[test]
1409    fn bitset_builder_two_fields() {
1410        let b = TypeObjectBuilder::bitset("::Packed")
1411            .field("header", 0, 4, 0x07) // TK_UINT32
1412            .field("body", 4, 28, 0x07)
1413            .build_minimal();
1414        assert_eq!(b.field_seq.len(), 2);
1415        assert_eq!(b.field_seq[0].common.bitcount, 4);
1416        assert_eq!(b.field_seq[1].common.position, 4);
1417    }
1418
1419    #[test]
1420    fn bitmask_builder_complete_preserves_names() {
1421        let b = TypeObjectBuilder::bitmask("::Perm")
1422            .bit_bound(16)
1423            .flag("READ", 0)
1424            .flag("WRITE", 1)
1425            .build_complete();
1426        assert_eq!(b.detail.type_name, "::Perm");
1427        assert_eq!(b.bit_bound, 16);
1428        assert_eq!(b.flag_seq.len(), 2);
1429        assert_eq!(b.flag_seq[0].detail.name, "READ");
1430        assert_eq!(b.flag_seq[1].detail.name, "WRITE");
1431    }
1432
1433    #[test]
1434    fn bitset_builder_complete_preserves_names() {
1435        let b = TypeObjectBuilder::bitset("::Packed")
1436            .field("header", 0, 4, 0x07)
1437            .field("body", 4, 28, 0x07)
1438            .build_complete();
1439        assert_eq!(b.detail.type_name, "::Packed");
1440        assert_eq!(b.field_seq.len(), 2);
1441        assert_eq!(b.field_seq[0].detail.name, "header");
1442        assert_eq!(b.field_seq[1].detail.name, "body");
1443    }
1444}