1use alloc::boxed::Box;
15use alloc::string::String;
16use alloc::vec::Vec;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23#[non_exhaustive]
24pub enum TypeKind {
25 NoType,
27 Boolean,
29 Byte,
31 Int8,
33 UInt8,
35 Int16,
37 UInt16,
39 Int32,
41 UInt32,
43 Int64,
45 UInt64,
47 Float32,
49 Float64,
51 Float128,
53 Char8,
55 Char16,
57 String8,
59 String16,
61 Enumeration,
63 Bitmask,
65 Alias,
67 Array,
69 Sequence,
71 Map,
73 Structure,
75 Union,
77 Bitset,
79 Annotation,
81}
82
83impl TypeKind {
84 #[must_use]
87 pub const fn is_primitive(self) -> bool {
88 matches!(
89 self,
90 Self::Boolean
91 | Self::Byte
92 | Self::Int8
93 | Self::UInt8
94 | Self::Int16
95 | Self::UInt16
96 | Self::Int32
97 | Self::UInt32
98 | Self::Int64
99 | Self::UInt64
100 | Self::Float32
101 | Self::Float64
102 | Self::Float128
103 | Self::Char8
104 | Self::Char16
105 )
106 }
107
108 #[must_use]
111 pub const fn is_aggregable(self) -> bool {
112 matches!(
113 self,
114 Self::Structure
115 | Self::Union
116 | Self::Annotation
117 | Self::Bitset
118 | Self::Bitmask
119 | Self::Enumeration
120 )
121 }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub enum ExtensibilityKind {
127 Final,
129 Appendable,
131 Mutable,
133}
134
135impl Default for ExtensibilityKind {
136 fn default() -> Self {
137 Self::Appendable
138 }
139}
140
141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum TryConstructKind {
147 Discard,
149 UseDefault,
151 Trim,
153}
154
155impl Default for TryConstructKind {
156 fn default() -> Self {
157 Self::Discard
158 }
159}
160
161pub type MemberId = u32;
163
164#[derive(Debug, Clone, PartialEq, Eq)]
173pub struct TypeDescriptor {
174 pub kind: TypeKind,
176 pub name: String,
178 pub base_type: Option<Box<TypeDescriptor>>,
180 pub discriminator_type: Option<Box<TypeDescriptor>>,
182 pub bound: Vec<u32>,
185 pub element_type: Option<Box<TypeDescriptor>>,
187 pub key_element_type: Option<Box<TypeDescriptor>>,
189 pub extensibility_kind: ExtensibilityKind,
191 pub is_nested: bool,
193}
194
195impl TypeDescriptor {
196 #[must_use]
198 pub fn primitive(kind: TypeKind, name: impl Into<String>) -> Self {
199 Self {
200 kind,
201 name: name.into(),
202 base_type: None,
203 discriminator_type: None,
204 bound: Vec::new(),
205 element_type: None,
206 key_element_type: None,
207 extensibility_kind: ExtensibilityKind::default(),
208 is_nested: false,
209 }
210 }
211
212 #[must_use]
214 pub fn structure(name: impl Into<String>) -> Self {
215 Self {
216 kind: TypeKind::Structure,
217 name: name.into(),
218 base_type: None,
219 discriminator_type: None,
220 bound: Vec::new(),
221 element_type: None,
222 key_element_type: None,
223 extensibility_kind: ExtensibilityKind::default(),
224 is_nested: false,
225 }
226 }
227
228 #[must_use]
230 pub fn union(name: impl Into<String>, discriminator: TypeDescriptor) -> Self {
231 Self {
232 kind: TypeKind::Union,
233 name: name.into(),
234 base_type: None,
235 discriminator_type: Some(Box::new(discriminator)),
236 bound: Vec::new(),
237 element_type: None,
238 key_element_type: None,
239 extensibility_kind: ExtensibilityKind::default(),
240 is_nested: false,
241 }
242 }
243
244 #[must_use]
246 pub fn sequence(name: impl Into<String>, element: TypeDescriptor, max: u32) -> Self {
247 Self {
248 kind: TypeKind::Sequence,
249 name: name.into(),
250 base_type: None,
251 discriminator_type: None,
252 bound: alloc::vec![max],
253 element_type: Some(Box::new(element)),
254 key_element_type: None,
255 extensibility_kind: ExtensibilityKind::default(),
256 is_nested: false,
257 }
258 }
259
260 #[must_use]
262 pub fn array(name: impl Into<String>, element: TypeDescriptor, dims: Vec<u32>) -> Self {
263 Self {
264 kind: TypeKind::Array,
265 name: name.into(),
266 base_type: None,
267 discriminator_type: None,
268 bound: dims,
269 element_type: Some(Box::new(element)),
270 key_element_type: None,
271 extensibility_kind: ExtensibilityKind::default(),
272 is_nested: false,
273 }
274 }
275
276 #[must_use]
278 pub fn map(
279 name: impl Into<String>,
280 key: TypeDescriptor,
281 element: TypeDescriptor,
282 max: u32,
283 ) -> Self {
284 Self {
285 kind: TypeKind::Map,
286 name: name.into(),
287 base_type: None,
288 discriminator_type: None,
289 bound: alloc::vec![max],
290 element_type: Some(Box::new(element)),
291 key_element_type: Some(Box::new(key)),
292 extensibility_kind: ExtensibilityKind::default(),
293 is_nested: false,
294 }
295 }
296
297 #[must_use]
299 pub fn string8(bound: u32) -> Self {
300 Self {
301 kind: TypeKind::String8,
302 name: alloc::format!("string<{bound}>"),
303 base_type: None,
304 discriminator_type: None,
305 bound: alloc::vec![bound],
306 element_type: None,
307 key_element_type: None,
308 extensibility_kind: ExtensibilityKind::default(),
309 is_nested: false,
310 }
311 }
312
313 #[must_use]
315 pub fn string16(bound: u32) -> Self {
316 Self {
317 kind: TypeKind::String16,
318 name: alloc::format!("wstring<{bound}>"),
319 base_type: None,
320 discriminator_type: None,
321 bound: alloc::vec![bound],
322 element_type: None,
323 key_element_type: None,
324 extensibility_kind: ExtensibilityKind::default(),
325 is_nested: false,
326 }
327 }
328
329 #[must_use]
331 pub fn enumeration(name: impl Into<String>) -> Self {
332 Self {
333 kind: TypeKind::Enumeration,
334 name: name.into(),
335 base_type: None,
336 discriminator_type: None,
337 bound: Vec::new(),
338 element_type: None,
339 key_element_type: None,
340 extensibility_kind: ExtensibilityKind::default(),
341 is_nested: false,
342 }
343 }
344
345 pub fn is_consistent(&self) -> Result<(), String> {
354 if self.name.is_empty() && self.kind != TypeKind::NoType {
358 return Err(String::from("descriptor without name"));
359 }
360 match self.kind {
361 TypeKind::Union => {
362 let Some(d) = &self.discriminator_type else {
363 return Err(String::from("union without discriminator_type"));
364 };
365 if !is_valid_discriminator(d.kind) {
366 return Err(alloc::format!(
367 "union discriminator must be int/enum/bool, got {:?}",
368 d.kind
369 ));
370 }
371 }
372 TypeKind::Array => {
373 if self.bound.is_empty() {
374 return Err(String::from("array without dimensions"));
375 }
376 if self.bound.contains(&0) {
377 return Err(String::from("array dimension must be > 0"));
378 }
379 if self.element_type.is_none() {
380 return Err(String::from("array without element_type"));
381 }
382 }
383 TypeKind::Sequence | TypeKind::String8 | TypeKind::String16 => {
384 if self.bound.len() != 1 {
385 return Err(String::from("sequence/string needs exactly 1 bound"));
386 }
387 if matches!(self.kind, TypeKind::Sequence) && self.element_type.is_none() {
388 return Err(String::from("sequence without element_type"));
389 }
390 }
391 TypeKind::Map => {
392 if self.bound.len() != 1 {
393 return Err(String::from("map needs exactly 1 bound"));
394 }
395 if self.element_type.is_none() {
396 return Err(String::from("map without value element_type"));
397 }
398 if self.key_element_type.is_none() {
399 return Err(String::from("map without key_element_type"));
400 }
401 }
402 _ => {}
403 }
404 if let Some(b) = &self.base_type {
407 if b.name == self.name && !self.name.is_empty() {
408 return Err(String::from("inheritance cycle: base_type == self"));
409 }
410 }
411 Ok(())
412 }
413}
414
415#[derive(Debug, Clone, PartialEq, Eq)]
421pub struct MemberDescriptor {
422 pub name: String,
424 pub id: MemberId,
426 pub member_type: Box<TypeDescriptor>,
428 pub default_value: Option<String>,
430 pub index: u32,
432 pub label: Vec<i64>,
434 pub try_construct: TryConstructKind,
436 pub is_key: bool,
438 pub is_optional: bool,
440 pub is_must_understand: bool,
442 pub is_shared: bool,
444 pub is_default_label: bool,
446}
447
448impl MemberDescriptor {
449 #[must_use]
452 pub fn new(name: impl Into<String>, id: MemberId, ty: TypeDescriptor) -> Self {
453 Self {
454 name: name.into(),
455 id,
456 member_type: Box::new(ty),
457 default_value: None,
458 index: 0,
459 label: Vec::new(),
460 try_construct: TryConstructKind::default(),
461 is_key: false,
462 is_optional: false,
463 is_must_understand: false,
464 is_shared: false,
465 is_default_label: false,
466 }
467 }
468
469 pub fn is_consistent(&self) -> Result<(), String> {
474 if self.name.is_empty() {
475 return Err(String::from("member without name"));
476 }
477 self.member_type.is_consistent()?;
478 if self.is_default_label && !self.label.is_empty() {
479 return Err(String::from(
480 "member with is_default_label must not have explicit labels",
481 ));
482 }
483 Ok(())
484 }
485}
486
487const fn is_valid_discriminator(kind: TypeKind) -> bool {
490 matches!(
491 kind,
492 TypeKind::Boolean
493 | TypeKind::Byte
494 | TypeKind::Int8
495 | TypeKind::UInt8
496 | TypeKind::Int16
497 | TypeKind::UInt16
498 | TypeKind::Int32
499 | TypeKind::UInt32
500 | TypeKind::Int64
501 | TypeKind::UInt64
502 | TypeKind::Char8
503 | TypeKind::Char16
504 | TypeKind::Enumeration
505 )
506}
507
508#[cfg(test)]
509#[allow(clippy::unwrap_used)]
510mod tests {
511 use super::*;
512
513 #[test]
514 fn type_kind_primitive_set_matches_spec_table_10() {
515 for k in [
516 TypeKind::Boolean,
517 TypeKind::Byte,
518 TypeKind::Int8,
519 TypeKind::UInt8,
520 TypeKind::Int16,
521 TypeKind::UInt16,
522 TypeKind::Int32,
523 TypeKind::UInt32,
524 TypeKind::Int64,
525 TypeKind::UInt64,
526 TypeKind::Float32,
527 TypeKind::Float64,
528 TypeKind::Float128,
529 TypeKind::Char8,
530 TypeKind::Char16,
531 ] {
532 assert!(k.is_primitive(), "{k:?} should be primitive");
533 }
534 for k in [
535 TypeKind::Structure,
536 TypeKind::Union,
537 TypeKind::Sequence,
538 TypeKind::Array,
539 TypeKind::Map,
540 TypeKind::String8,
541 TypeKind::String16,
542 TypeKind::Alias,
543 ] {
544 assert!(!k.is_primitive(), "{k:?} should not be primitive");
545 }
546 }
547
548 #[test]
549 fn type_kind_aggregable_set() {
550 assert!(TypeKind::Structure.is_aggregable());
551 assert!(TypeKind::Union.is_aggregable());
552 assert!(TypeKind::Annotation.is_aggregable());
553 assert!(TypeKind::Bitset.is_aggregable());
554 assert!(TypeKind::Bitmask.is_aggregable());
555 assert!(TypeKind::Enumeration.is_aggregable());
556 assert!(!TypeKind::Int32.is_aggregable());
557 assert!(!TypeKind::Sequence.is_aggregable());
558 }
559
560 #[test]
561 fn descriptor_struct_passes_consistency() {
562 let s = TypeDescriptor::structure("::Foo");
563 assert!(s.is_consistent().is_ok());
564 }
565
566 #[test]
567 fn descriptor_union_without_discriminator_fails() {
568 let mut u = TypeDescriptor::structure("::U");
569 u.kind = TypeKind::Union;
570 let err = u.is_consistent().unwrap_err();
571 assert!(err.contains("discriminator"));
572 }
573
574 #[test]
575 fn descriptor_union_with_invalid_discriminator_fails() {
576 let bad_disc = TypeDescriptor::structure("::S");
577 let u = TypeDescriptor::union("::U", bad_disc);
578 let err = u.is_consistent().unwrap_err();
579 assert!(err.contains("discriminator"));
580 }
581
582 #[test]
583 fn descriptor_array_without_dims_fails() {
584 let mut a = TypeDescriptor::array(
585 "::A",
586 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
587 alloc::vec![3, 3],
588 );
589 a.bound.clear();
590 let err = a.is_consistent().unwrap_err();
591 assert!(err.contains("dimensions"));
592 }
593
594 #[test]
595 fn descriptor_array_with_zero_dim_fails() {
596 let a = TypeDescriptor::array(
597 "::A",
598 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
599 alloc::vec![3, 0, 4],
600 );
601 let err = a.is_consistent().unwrap_err();
602 assert!(err.contains("> 0"));
603 }
604
605 #[test]
606 fn descriptor_sequence_with_element_passes() {
607 let s = TypeDescriptor::sequence(
608 "::S",
609 TypeDescriptor::primitive(TypeKind::Int32, "int32"),
610 100,
611 );
612 assert!(s.is_consistent().is_ok());
613 }
614
615 #[test]
616 fn descriptor_map_requires_both_key_and_value() {
617 let mut m = TypeDescriptor::map(
618 "::M",
619 TypeDescriptor::string8(64),
620 TypeDescriptor::primitive(TypeKind::Int64, "int64"),
621 500,
622 );
623 assert!(m.is_consistent().is_ok());
624 m.key_element_type = None;
625 assert!(m.is_consistent().is_err());
626 }
627
628 #[test]
629 fn descriptor_inheritance_cycle_self_reference_rejected() {
630 let mut s = TypeDescriptor::structure("::Foo");
631 let cycle = TypeDescriptor::structure("::Foo");
632 s.base_type = Some(Box::new(cycle));
633 let err = s.is_consistent().unwrap_err();
634 assert!(err.contains("cycle"));
635 }
636
637 #[test]
638 fn member_descriptor_default_label_with_labels_rejected() {
639 let mut m =
640 MemberDescriptor::new("x", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"));
641 m.is_default_label = true;
642 m.label = alloc::vec![0];
643 let err = m.is_consistent().unwrap_err();
644 assert!(err.contains("default_label"));
645 }
646
647 #[test]
648 fn member_descriptor_empty_name_rejected() {
649 let m = MemberDescriptor::new("", 1, TypeDescriptor::primitive(TypeKind::Int32, "int32"));
650 assert!(m.is_consistent().is_err());
651 }
652
653 #[test]
654 fn try_construct_default_is_discard() {
655 assert_eq!(TryConstructKind::default(), TryConstructKind::Discard);
656 }
657
658 #[test]
659 fn extensibility_default_is_appendable() {
660 assert_eq!(ExtensibilityKind::default(), ExtensibilityKind::Appendable);
661 }
662}