1use gruel_builtins::{Posture, ThreadSafety};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
12pub struct StructId(pub u32);
13
14impl StructId {
15 #[inline]
20 pub fn from_pool_index(pool_index: u32) -> Self {
21 StructId(pool_index)
22 }
23
24 #[inline]
28 pub fn pool_index(self) -> u32 {
29 self.0
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
38pub struct EnumId(pub u32);
39
40impl EnumId {
41 #[inline]
46 pub fn from_pool_index(pool_index: u32) -> Self {
47 EnumId(pool_index)
48 }
49
50 #[inline]
54 pub fn pool_index(self) -> u32 {
55 self.0
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
62pub struct ArrayTypeId(pub u32);
63
64impl ArrayTypeId {
65 #[inline]
70 pub fn from_pool_index(pool_index: u32) -> Self {
71 ArrayTypeId(pool_index)
72 }
73
74 #[inline]
78 pub fn pool_index(self) -> u32 {
79 self.0
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
86pub struct PtrConstTypeId(pub u32);
87
88impl PtrConstTypeId {
89 #[inline]
91 pub fn from_pool_index(pool_index: u32) -> Self {
92 PtrConstTypeId(pool_index)
93 }
94
95 #[inline]
97 pub fn pool_index(self) -> u32 {
98 self.0
99 }
100}
101
102#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
105pub struct PtrMutTypeId(pub u32);
106
107impl PtrMutTypeId {
108 #[inline]
110 pub fn from_pool_index(pool_index: u32) -> Self {
111 PtrMutTypeId(pool_index)
112 }
113
114 #[inline]
116 pub fn pool_index(self) -> u32 {
117 self.0
118 }
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
124pub struct RefTypeId(pub u32);
125
126impl RefTypeId {
127 #[inline]
128 pub fn from_pool_index(pool_index: u32) -> Self {
129 RefTypeId(pool_index)
130 }
131
132 #[inline]
133 pub fn pool_index(self) -> u32 {
134 self.0
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
141pub struct MutRefTypeId(pub u32);
142
143impl MutRefTypeId {
144 #[inline]
145 pub fn from_pool_index(pool_index: u32) -> Self {
146 MutRefTypeId(pool_index)
147 }
148
149 #[inline]
150 pub fn pool_index(self) -> u32 {
151 self.0
152 }
153}
154
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
157pub struct SliceTypeId(pub u32);
158
159impl SliceTypeId {
160 #[inline]
161 pub fn from_pool_index(pool_index: u32) -> Self {
162 SliceTypeId(pool_index)
163 }
164
165 #[inline]
166 pub fn pool_index(self) -> u32 {
167 self.0
168 }
169}
170
171#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
173pub struct MutSliceTypeId(pub u32);
174
175impl MutSliceTypeId {
176 #[inline]
177 pub fn from_pool_index(pool_index: u32) -> Self {
178 MutSliceTypeId(pool_index)
179 }
180
181 #[inline]
182 pub fn pool_index(self) -> u32 {
183 self.0
184 }
185}
186
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
189pub struct VecTypeId(pub u32);
190
191impl VecTypeId {
192 #[inline]
193 pub fn from_pool_index(pool_index: u32) -> Self {
194 VecTypeId(pool_index)
195 }
196
197 #[inline]
198 pub fn pool_index(self) -> u32 {
199 self.0
200 }
201}
202
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
211pub struct InterfaceId(pub u32);
212
213impl InterfaceId {
214 #[inline]
215 pub fn from_pool_index(pool_index: u32) -> Self {
216 InterfaceId(pool_index)
217 }
218
219 #[inline]
220 pub fn pool_index(self) -> u32 {
221 self.0
222 }
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
230pub struct ModuleId(pub u32);
231
232impl ModuleId {
233 #[inline]
235 pub fn new(index: u32) -> Self {
236 ModuleId(index)
237 }
238
239 #[inline]
241 pub fn index(self) -> u32 {
242 self.0
243 }
244}
245
246#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
256pub enum TypeKind {
257 I8,
259 I16,
261 I32,
263 I64,
265 U8,
267 U16,
269 U32,
271 U64,
273 Isize,
275 Usize,
277 F16,
279 F32,
281 F64,
283 Bool,
285 Char,
287 Unit,
289 CSchar,
291 CShort,
293 CInt,
296 CLong,
299 CLonglong,
301 CUchar,
303 CUshort,
305 CUint,
307 CUlong,
309 CUlonglong,
311 CFloat,
313 CDouble,
315 CVoid,
320 Struct(StructId),
322 Enum(EnumId),
324 Interface(InterfaceId),
328 Array(ArrayTypeId),
330 PtrConst(PtrConstTypeId),
332 PtrMut(PtrMutTypeId),
334 Ref(RefTypeId),
336 MutRef(MutRefTypeId),
338 Slice(SliceTypeId),
340 MutSlice(MutSliceTypeId),
342 Vec(VecTypeId),
344 Module(ModuleId),
346 Error,
348 Never,
350 ComptimeType,
352 ComptimeStr,
354 ComptimeInt,
356}
357
358#[derive(Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
399pub struct Type(u32);
400
401impl Default for Type {
402 fn default() -> Self {
403 Type::UNIT
404 }
405}
406
407impl std::fmt::Debug for Type {
408 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409 match self.kind() {
411 TypeKind::I8 => write!(f, "Type::I8"),
412 TypeKind::I16 => write!(f, "Type::I16"),
413 TypeKind::I32 => write!(f, "Type::I32"),
414 TypeKind::I64 => write!(f, "Type::I64"),
415 TypeKind::U8 => write!(f, "Type::U8"),
416 TypeKind::U16 => write!(f, "Type::U16"),
417 TypeKind::U32 => write!(f, "Type::U32"),
418 TypeKind::U64 => write!(f, "Type::U64"),
419 TypeKind::Isize => write!(f, "Type::ISIZE"),
420 TypeKind::Usize => write!(f, "Type::USIZE"),
421 TypeKind::F16 => write!(f, "Type::F16"),
422 TypeKind::F32 => write!(f, "Type::F32"),
423 TypeKind::F64 => write!(f, "Type::F64"),
424 TypeKind::Bool => write!(f, "Type::BOOL"),
425 TypeKind::Char => write!(f, "Type::CHAR"),
426 TypeKind::Unit => write!(f, "Type::UNIT"),
427 TypeKind::Error => write!(f, "Type::ERROR"),
428 TypeKind::Never => write!(f, "Type::NEVER"),
429 TypeKind::ComptimeType => write!(f, "Type::COMPTIME_TYPE"),
430 TypeKind::ComptimeStr => write!(f, "Type::COMPTIME_STR"),
431 TypeKind::ComptimeInt => write!(f, "Type::COMPTIME_INT"),
432 TypeKind::CSchar => write!(f, "Type::C_SCHAR"),
433 TypeKind::CShort => write!(f, "Type::C_SHORT"),
434 TypeKind::CInt => write!(f, "Type::C_INT"),
435 TypeKind::CLong => write!(f, "Type::C_LONG"),
436 TypeKind::CLonglong => write!(f, "Type::C_LONGLONG"),
437 TypeKind::CUchar => write!(f, "Type::C_UCHAR"),
438 TypeKind::CUshort => write!(f, "Type::C_USHORT"),
439 TypeKind::CUint => write!(f, "Type::C_UINT"),
440 TypeKind::CUlong => write!(f, "Type::C_ULONG"),
441 TypeKind::CUlonglong => write!(f, "Type::C_ULONGLONG"),
442 TypeKind::CFloat => write!(f, "Type::C_FLOAT"),
443 TypeKind::CDouble => write!(f, "Type::C_DOUBLE"),
444 TypeKind::CVoid => write!(f, "Type::C_VOID"),
445 TypeKind::Struct(id) => write!(f, "Type::new_struct(StructId({}))", id.0),
446 TypeKind::Enum(id) => write!(f, "Type::new_enum(EnumId({}))", id.0),
447 TypeKind::Array(id) => write!(f, "Type::new_array(ArrayTypeId({}))", id.0),
448 TypeKind::PtrConst(id) => write!(f, "Type::new_ptr_const(PtrConstTypeId({}))", id.0),
449 TypeKind::PtrMut(id) => write!(f, "Type::new_ptr_mut(PtrMutTypeId({}))", id.0),
450 TypeKind::Ref(id) => write!(f, "Type::new_ref(RefTypeId({}))", id.0),
451 TypeKind::MutRef(id) => write!(f, "Type::new_mut_ref(MutRefTypeId({}))", id.0),
452 TypeKind::Slice(id) => write!(f, "Type::new_slice(SliceTypeId({}))", id.0),
453 TypeKind::MutSlice(id) => write!(f, "Type::new_mut_slice(MutSliceTypeId({}))", id.0),
454 TypeKind::Vec(id) => write!(f, "Type::new_vec(VecTypeId({}))", id.0),
455 TypeKind::Module(id) => write!(f, "Type::new_module(ModuleId({}))", id.0),
456 TypeKind::Interface(id) => write!(f, "Type::new_interface(InterfaceId({}))", id.0),
457 }
458 }
459}
460
461const TAG_STRUCT: u32 = 100;
465const TAG_ENUM: u32 = 101;
466const TAG_ARRAY: u32 = 102;
467const TAG_MODULE: u32 = 103;
468const TAG_PTR_CONST: u32 = 104;
469const TAG_PTR_MUT: u32 = 105;
470const TAG_INTERFACE: u32 = 106;
471const TAG_REF: u32 = 107;
472const TAG_MUT_REF: u32 = 108;
473const TAG_SLICE: u32 = 109;
474const TAG_MUT_SLICE: u32 = 110;
475const TAG_VEC: u32 = 111;
476
477impl Type {
479 pub const I8: Type = Type(0);
481 pub const I16: Type = Type(1);
483 pub const I32: Type = Type(2);
485 pub const I64: Type = Type(3);
487 pub const U8: Type = Type(4);
489 pub const U16: Type = Type(5);
491 pub const U32: Type = Type(6);
493 pub const U64: Type = Type(7);
495 pub const ISIZE: Type = Type(8);
497 pub const USIZE: Type = Type(9);
499 pub const F16: Type = Type(10);
501 pub const F32: Type = Type(11);
503 pub const F64: Type = Type(12);
505 pub const BOOL: Type = Type(13);
507 pub const UNIT: Type = Type(14);
509 pub const ERROR: Type = Type(15);
511 pub const NEVER: Type = Type(16);
513 pub const COMPTIME_TYPE: Type = Type(17);
515 pub const COMPTIME_STR: Type = Type(18);
517 pub const COMPTIME_INT: Type = Type(19);
519 pub const CHAR: Type = Type(20);
521
522 pub const C_SCHAR: Type = Type(21);
526 pub const C_SHORT: Type = Type(22);
528 pub const C_INT: Type = Type(23);
530 pub const C_LONG: Type = Type(24);
532 pub const C_LONGLONG: Type = Type(25);
534 pub const C_UCHAR: Type = Type(26);
536 pub const C_USHORT: Type = Type(27);
538 pub const C_UINT: Type = Type(28);
540 pub const C_ULONG: Type = Type(29);
542 pub const C_ULONGLONG: Type = Type(30);
544 pub const C_FLOAT: Type = Type(31);
546 pub const C_DOUBLE: Type = Type(32);
548 pub const C_VOID: Type = Type(33);
550}
551
552impl Type {
554 #[inline]
556 pub const fn new_struct(id: StructId) -> Type {
557 Type(TAG_STRUCT | (id.0 << 8))
558 }
559
560 #[inline]
562 pub const fn new_enum(id: EnumId) -> Type {
563 Type(TAG_ENUM | (id.0 << 8))
564 }
565
566 #[inline]
568 pub const fn new_array(id: ArrayTypeId) -> Type {
569 Type(TAG_ARRAY | (id.0 << 8))
570 }
571
572 #[inline]
574 pub const fn new_ptr_const(id: PtrConstTypeId) -> Type {
575 Type(TAG_PTR_CONST | (id.0 << 8))
576 }
577
578 #[inline]
580 pub const fn new_ptr_mut(id: PtrMutTypeId) -> Type {
581 Type(TAG_PTR_MUT | (id.0 << 8))
582 }
583
584 #[inline]
586 pub const fn new_ref(id: RefTypeId) -> Type {
587 Type(TAG_REF | (id.0 << 8))
588 }
589
590 #[inline]
592 pub const fn new_mut_ref(id: MutRefTypeId) -> Type {
593 Type(TAG_MUT_REF | (id.0 << 8))
594 }
595
596 #[inline]
598 pub const fn new_slice(id: SliceTypeId) -> Type {
599 Type(TAG_SLICE | (id.0 << 8))
600 }
601
602 #[inline]
604 pub const fn new_mut_slice(id: MutSliceTypeId) -> Type {
605 Type(TAG_MUT_SLICE | (id.0 << 8))
606 }
607
608 #[inline]
610 pub const fn new_vec(id: VecTypeId) -> Type {
611 Type(TAG_VEC | (id.0 << 8))
612 }
613
614 #[inline]
616 pub const fn new_module(id: ModuleId) -> Type {
617 Type(TAG_MODULE | (id.0 << 8))
618 }
619
620 #[inline]
622 pub const fn new_interface(id: InterfaceId) -> Type {
623 Type(TAG_INTERFACE | (id.0 << 8))
624 }
625}
626
627impl StructDef {
628 pub fn is_tuple_shaped(&self) -> bool {
632 if !self.name.starts_with("__anon_struct_") {
633 return false;
634 }
635 if self.fields.is_empty() {
636 return false;
637 }
638 self.fields
639 .iter()
640 .enumerate()
641 .all(|(i, f)| f.name == i.to_string())
642 }
643
644 pub fn tuple_display_name<F>(&self, mut fmt_ty: F) -> Option<String>
648 where
649 F: FnMut(Type) -> String,
650 {
651 if !self.is_tuple_shaped() {
652 return None;
653 }
654 let mut s = String::from("(");
655 for (i, f) in self.fields.iter().enumerate() {
656 if i > 0 {
657 s.push_str(", ");
658 }
659 s.push_str(&fmt_ty(f.ty));
660 }
661 if self.fields.len() == 1 {
662 s.push(',');
663 }
664 s.push(')');
665 Some(s)
666 }
667}
668
669#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
679pub struct InterfaceDef {
680 pub name: String,
682 pub methods: Vec<InterfaceMethodReq>,
684 pub is_pub: bool,
686 pub file_id: gruel_util::FileId,
688}
689
690#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
698pub enum IfaceTy {
699 SelfType,
701 Concrete(Type),
703}
704
705impl IfaceTy {
706 pub fn substitute_self(&self, candidate: Type) -> Type {
709 match self {
710 IfaceTy::SelfType => candidate,
711 IfaceTy::Concrete(t) => *t,
712 }
713 }
714
715 pub fn is_self(&self) -> bool {
717 matches!(self, IfaceTy::SelfType)
718 }
719}
720
721#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
728pub enum ReceiverMode {
729 ByValue,
731 MutRef,
733 Ref,
735}
736
737impl ReceiverMode {
738 pub fn render(&self) -> &'static str {
740 match self {
741 ReceiverMode::ByValue => "self",
742 ReceiverMode::MutRef => "self: MutRef(Self)",
743 ReceiverMode::Ref => "self: Ref(Self)",
744 }
745 }
746}
747
748#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
753pub struct InterfaceMethodReq {
754 pub name: String,
756 pub receiver: ReceiverMode,
758 pub param_types: Vec<IfaceTy>,
760 pub return_type: IfaceTy,
762 #[serde(default)]
769 pub is_unchecked: bool,
770}
771
772impl InterfaceDef {
773 pub fn find_method(&self, name: &str) -> Option<(usize, &InterfaceMethodReq)> {
776 self.methods
777 .iter()
778 .enumerate()
779 .find(|(_, m)| m.name == name)
780 }
781}
782
783#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
785pub struct StructDef {
786 pub name: String,
788 pub fields: Vec<StructField>,
790 pub posture: Posture,
796 pub is_clone: bool,
801 pub thread_safety: ThreadSafety,
810 pub destructor: Option<String>,
812 pub is_builtin: bool,
817 pub is_pub: bool,
819 pub file_id: gruel_util::FileId,
821 #[serde(default)]
826 pub is_c_layout: bool,
827}
828
829#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
831pub struct StructField {
832 pub name: String,
834 pub ty: Type,
836 pub is_pub: bool,
841}
842
843impl StructDef {
844 pub fn find_field(&self, name: &str) -> Option<(usize, &StructField)> {
846 self.fields.iter().enumerate().find(|(_, f)| f.name == name)
847 }
848
849 pub fn field_count(&self) -> usize {
851 self.fields.len()
852 }
853}
854
855#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
857pub struct EnumVariantDef {
858 pub name: String,
860 pub fields: Vec<Type>,
863 pub field_names: Vec<String>,
866}
867
868impl EnumVariantDef {
869 pub fn unit(name: impl Into<String>) -> Self {
871 Self {
872 name: name.into(),
873 fields: Vec::new(),
874 field_names: Vec::new(),
875 }
876 }
877
878 pub fn has_data(&self) -> bool {
880 !self.fields.is_empty()
881 }
882
883 pub fn is_struct_variant(&self) -> bool {
885 !self.field_names.is_empty()
886 }
887
888 pub fn find_field(&self, name: &str) -> Option<usize> {
890 self.field_names.iter().position(|n| n == name)
891 }
892}
893
894#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
896pub struct EnumDef {
897 pub name: String,
899 pub variants: Vec<EnumVariantDef>,
901 pub posture: Posture,
906 pub thread_safety: ThreadSafety,
909 pub is_pub: bool,
911 pub file_id: gruel_util::FileId,
913 pub destructor: Option<String>,
916 #[serde(default)]
921 pub is_c_layout: bool,
922}
923
924impl EnumDef {
925 pub fn variant_count(&self) -> usize {
927 self.variants.len()
928 }
929
930 pub fn find_variant(&self, name: &str) -> Option<usize> {
932 self.variants.iter().position(|v| v.name == name)
933 }
934
935 pub fn has_data_variants(&self) -> bool {
937 self.variants.iter().any(|v| v.has_data())
938 }
939
940 pub fn is_unit_only(&self) -> bool {
942 !self.has_data_variants()
943 }
944
945 pub fn discriminant_type(&self) -> Type {
952 if self.is_c_layout {
953 return Type::C_INT;
954 }
955 let count = self.variants.len();
956 if count == 0 {
957 Type::NEVER } else if count <= 256 {
959 Type::U8
960 } else if count <= 65536 {
961 Type::U16
962 } else if count <= 4_294_967_296 {
963 Type::U32
964 } else {
965 Type::U64
966 }
967 }
968}
969
970#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
976pub struct ModuleDef {
977 pub import_path: String,
979 pub file_path: String,
981 pub functions: rustc_hash::FxHashMap<String, String>,
984 pub structs: Vec<String>,
986 pub enums: Vec<String>,
988}
989
990impl ModuleDef {
991 pub fn new(import_path: String, file_path: String) -> Self {
993 Self {
994 import_path,
995 file_path,
996 functions: rustc_hash::FxHashMap::default(),
997 structs: Vec::new(),
998 enums: Vec::new(),
999 }
1000 }
1001
1002 pub fn find_function(&self, name: &str) -> Option<&str> {
1005 self.functions.get(name).map(|s| s.as_str())
1006 }
1007}
1008
1009impl Type {
1010 #[inline]
1031 pub fn kind(&self) -> TypeKind {
1032 self.try_kind().unwrap_or_else(|| {
1033 panic!(
1034 "invalid Type encoding: raw value {:#010x} (tag={}, id={}). \
1035 This indicates data corruption or a bug in Type construction. \
1036 Valid tags are 0-33 (primitives, including ADR-0086 C named types) \
1037 or 100-111 (composites).",
1038 self.0,
1039 self.0 & 0xFF,
1040 self.0 >> 8
1041 )
1042 })
1043 }
1044
1045 #[inline]
1063 pub fn try_kind(&self) -> Option<TypeKind> {
1064 let tag = self.0 & 0xFF;
1065 match tag {
1066 0 => Some(TypeKind::I8),
1067 1 => Some(TypeKind::I16),
1068 2 => Some(TypeKind::I32),
1069 3 => Some(TypeKind::I64),
1070 4 => Some(TypeKind::U8),
1071 5 => Some(TypeKind::U16),
1072 6 => Some(TypeKind::U32),
1073 7 => Some(TypeKind::U64),
1074 8 => Some(TypeKind::Isize),
1075 9 => Some(TypeKind::Usize),
1076 10 => Some(TypeKind::F16),
1077 11 => Some(TypeKind::F32),
1078 12 => Some(TypeKind::F64),
1079 13 => Some(TypeKind::Bool),
1080 14 => Some(TypeKind::Unit),
1081 15 => Some(TypeKind::Error),
1082 16 => Some(TypeKind::Never),
1083 17 => Some(TypeKind::ComptimeType),
1084 18 => Some(TypeKind::ComptimeStr),
1085 19 => Some(TypeKind::ComptimeInt),
1086 20 => Some(TypeKind::Char),
1087 21 => Some(TypeKind::CSchar),
1088 22 => Some(TypeKind::CShort),
1089 23 => Some(TypeKind::CInt),
1090 24 => Some(TypeKind::CLong),
1091 25 => Some(TypeKind::CLonglong),
1092 26 => Some(TypeKind::CUchar),
1093 27 => Some(TypeKind::CUshort),
1094 28 => Some(TypeKind::CUint),
1095 29 => Some(TypeKind::CUlong),
1096 30 => Some(TypeKind::CUlonglong),
1097 31 => Some(TypeKind::CFloat),
1098 32 => Some(TypeKind::CDouble),
1099 33 => Some(TypeKind::CVoid),
1100 TAG_STRUCT => Some(TypeKind::Struct(StructId(self.0 >> 8))),
1101 TAG_ENUM => Some(TypeKind::Enum(EnumId(self.0 >> 8))),
1102 TAG_ARRAY => Some(TypeKind::Array(ArrayTypeId(self.0 >> 8))),
1103 TAG_PTR_CONST => Some(TypeKind::PtrConst(PtrConstTypeId(self.0 >> 8))),
1104 TAG_PTR_MUT => Some(TypeKind::PtrMut(PtrMutTypeId(self.0 >> 8))),
1105 TAG_REF => Some(TypeKind::Ref(RefTypeId(self.0 >> 8))),
1106 TAG_MUT_REF => Some(TypeKind::MutRef(MutRefTypeId(self.0 >> 8))),
1107 TAG_SLICE => Some(TypeKind::Slice(SliceTypeId(self.0 >> 8))),
1108 TAG_MUT_SLICE => Some(TypeKind::MutSlice(MutSliceTypeId(self.0 >> 8))),
1109 TAG_VEC => Some(TypeKind::Vec(VecTypeId(self.0 >> 8))),
1110 TAG_MODULE => Some(TypeKind::Module(ModuleId(self.0 >> 8))),
1111 TAG_INTERFACE => Some(TypeKind::Interface(InterfaceId(self.0 >> 8))),
1112 _ => None,
1113 }
1114 }
1115
1116 pub fn name(&self) -> &'static str {
1120 match self.kind() {
1121 TypeKind::I8 => "i8",
1122 TypeKind::I16 => "i16",
1123 TypeKind::I32 => "i32",
1124 TypeKind::I64 => "i64",
1125 TypeKind::U8 => "u8",
1126 TypeKind::U16 => "u16",
1127 TypeKind::U32 => "u32",
1128 TypeKind::U64 => "u64",
1129 TypeKind::Isize => "isize",
1130 TypeKind::Usize => "usize",
1131 TypeKind::F16 => "f16",
1132 TypeKind::F32 => "f32",
1133 TypeKind::F64 => "f64",
1134 TypeKind::Bool => "bool",
1135 TypeKind::Char => "char",
1136 TypeKind::Unit => "()",
1137 TypeKind::Struct(_) => "<struct>",
1138 TypeKind::Enum(_) => "<enum>",
1139 TypeKind::Array(_) => "<array>",
1140 TypeKind::PtrConst(_) => "<ptr const>",
1141 TypeKind::PtrMut(_) => "<ptr mut>",
1142 TypeKind::Ref(_) => "<ref>",
1143 TypeKind::MutRef(_) => "<mut ref>",
1144 TypeKind::Slice(_) => "<slice>",
1145 TypeKind::MutSlice(_) => "<mut slice>",
1146 TypeKind::Vec(_) => "<vec>",
1147 TypeKind::Module(_) => "<module>",
1148 TypeKind::Interface(_) => "<interface>",
1149 TypeKind::Error => "<error>",
1150 TypeKind::Never => "!",
1151 TypeKind::ComptimeType => "type",
1152 TypeKind::ComptimeStr => "comptime_str",
1153 TypeKind::ComptimeInt => "comptime_int",
1154 TypeKind::CSchar => "c_schar",
1155 TypeKind::CShort => "c_short",
1156 TypeKind::CInt => "c_int",
1157 TypeKind::CLong => "c_long",
1158 TypeKind::CLonglong => "c_longlong",
1159 TypeKind::CUchar => "c_uchar",
1160 TypeKind::CUshort => "c_ushort",
1161 TypeKind::CUint => "c_uint",
1162 TypeKind::CUlong => "c_ulong",
1163 TypeKind::CUlonglong => "c_ulonglong",
1164 TypeKind::CFloat => "c_float",
1165 TypeKind::CDouble => "c_double",
1166 TypeKind::CVoid => "c_void",
1167 }
1168 }
1169
1170 pub fn safe_name_with_pool(&self, pool: Option<&crate::intern_pool::TypeInternPool>) -> String {
1183 match self.try_kind() {
1184 Some(TypeKind::Struct(struct_id)) => {
1185 if let Some(pool) = pool {
1186 let def = pool.struct_def(struct_id);
1187 if let Some(tuple_name) =
1189 def.tuple_display_name(|ty| ty.safe_name_with_pool(Some(pool)))
1190 {
1191 return tuple_name;
1192 }
1193 return def.name.clone();
1194 }
1195 format!("<struct#{}>", struct_id.0)
1196 }
1197 Some(TypeKind::Enum(enum_id)) => {
1198 if let Some(pool) = pool {
1199 let def = pool.enum_def(enum_id);
1200 return def.name.clone();
1201 }
1202 format!("<enum#{}>", enum_id.0)
1203 }
1204 Some(_kind) => self.name().to_string(),
1205 None => format!("<invalid type encoding: {:#x}>", self.0),
1206 }
1207 }
1208
1209 #[inline]
1214 pub fn is_integer(&self) -> bool {
1215 self.0 <= 9 || (self.0 >= 21 && self.0 <= 30)
1216 }
1217
1218 #[inline]
1220 pub fn is_error(&self) -> bool {
1221 *self == Type::ERROR
1222 }
1223
1224 #[inline]
1226 pub fn is_never(&self) -> bool {
1227 *self == Type::NEVER
1228 }
1229
1230 #[inline]
1232 pub fn is_comptime_type(&self) -> bool {
1233 *self == Type::COMPTIME_TYPE
1234 }
1235
1236 #[inline]
1238 pub fn is_comptime_str(&self) -> bool {
1239 *self == Type::COMPTIME_STR
1240 }
1241
1242 #[inline]
1244 pub fn is_comptime_int(&self) -> bool {
1245 *self == Type::COMPTIME_INT
1246 }
1247
1248 #[inline]
1250 pub fn is_struct(&self) -> bool {
1251 (self.0 & 0xFF) == TAG_STRUCT
1252 }
1253
1254 #[inline]
1256 pub fn as_struct(&self) -> Option<StructId> {
1257 if self.is_struct() {
1258 Some(StructId(self.0 >> 8))
1259 } else {
1260 None
1261 }
1262 }
1263
1264 #[inline]
1266 pub fn is_array(&self) -> bool {
1267 (self.0 & 0xFF) == TAG_ARRAY
1268 }
1269
1270 #[inline]
1272 pub fn as_array(&self) -> Option<ArrayTypeId> {
1273 if self.is_array() {
1274 Some(ArrayTypeId(self.0 >> 8))
1275 } else {
1276 None
1277 }
1278 }
1279
1280 #[inline]
1282 pub fn is_enum(&self) -> bool {
1283 (self.0 & 0xFF) == TAG_ENUM
1284 }
1285
1286 #[inline]
1288 pub fn as_enum(&self) -> Option<EnumId> {
1289 if self.is_enum() {
1290 Some(EnumId(self.0 >> 8))
1291 } else {
1292 None
1293 }
1294 }
1295
1296 #[inline]
1298 pub fn is_module(&self) -> bool {
1299 (self.0 & 0xFF) == TAG_MODULE
1300 }
1301
1302 #[inline]
1304 pub fn as_module(&self) -> Option<ModuleId> {
1305 if self.is_module() {
1306 Some(ModuleId(self.0 >> 8))
1307 } else {
1308 None
1309 }
1310 }
1311
1312 #[inline]
1314 pub fn is_ptr_const(&self) -> bool {
1315 (self.0 & 0xFF) == TAG_PTR_CONST
1316 }
1317
1318 #[inline]
1320 pub fn as_ptr_const(&self) -> Option<PtrConstTypeId> {
1321 if self.is_ptr_const() {
1322 Some(PtrConstTypeId(self.0 >> 8))
1323 } else {
1324 None
1325 }
1326 }
1327
1328 #[inline]
1330 pub fn is_ptr_mut(&self) -> bool {
1331 (self.0 & 0xFF) == TAG_PTR_MUT
1332 }
1333
1334 #[inline]
1336 pub fn as_ptr_mut(&self) -> Option<PtrMutTypeId> {
1337 if self.is_ptr_mut() {
1338 Some(PtrMutTypeId(self.0 >> 8))
1339 } else {
1340 None
1341 }
1342 }
1343
1344 #[inline]
1346 pub fn is_ptr(&self) -> bool {
1347 let tag = self.0 & 0xFF;
1348 tag == TAG_PTR_CONST || tag == TAG_PTR_MUT
1349 }
1350
1351 #[inline]
1353 pub fn is_ref(&self) -> bool {
1354 (self.0 & 0xFF) == TAG_REF
1355 }
1356
1357 #[inline]
1359 pub fn as_ref_type(&self) -> Option<RefTypeId> {
1360 if self.is_ref() {
1361 Some(RefTypeId(self.0 >> 8))
1362 } else {
1363 None
1364 }
1365 }
1366
1367 #[inline]
1369 pub fn is_mut_ref(&self) -> bool {
1370 (self.0 & 0xFF) == TAG_MUT_REF
1371 }
1372
1373 #[inline]
1375 pub fn as_mut_ref_type(&self) -> Option<MutRefTypeId> {
1376 if self.is_mut_ref() {
1377 Some(MutRefTypeId(self.0 >> 8))
1378 } else {
1379 None
1380 }
1381 }
1382
1383 #[inline]
1385 pub fn is_any_ref(&self) -> bool {
1386 let tag = self.0 & 0xFF;
1387 tag == TAG_REF || tag == TAG_MUT_REF
1388 }
1389
1390 #[inline]
1392 pub fn is_slice(&self) -> bool {
1393 (self.0 & 0xFF) == TAG_SLICE
1394 }
1395
1396 #[inline]
1398 pub fn as_slice_type(&self) -> Option<SliceTypeId> {
1399 if self.is_slice() {
1400 Some(SliceTypeId(self.0 >> 8))
1401 } else {
1402 None
1403 }
1404 }
1405
1406 #[inline]
1408 pub fn is_mut_slice(&self) -> bool {
1409 (self.0 & 0xFF) == TAG_MUT_SLICE
1410 }
1411
1412 #[inline]
1414 pub fn as_mut_slice_type(&self) -> Option<MutSliceTypeId> {
1415 if self.is_mut_slice() {
1416 Some(MutSliceTypeId(self.0 >> 8))
1417 } else {
1418 None
1419 }
1420 }
1421
1422 #[inline]
1424 pub fn is_any_slice(&self) -> bool {
1425 let tag = self.0 & 0xFF;
1426 tag == TAG_SLICE || tag == TAG_MUT_SLICE
1427 }
1428
1429 #[inline]
1431 pub fn is_vec(&self) -> bool {
1432 (self.0 & 0xFF) == TAG_VEC
1433 }
1434
1435 #[inline]
1437 pub fn as_vec_type(&self) -> Option<VecTypeId> {
1438 if self.is_vec() {
1439 Some(VecTypeId(self.0 >> 8))
1440 } else {
1441 None
1442 }
1443 }
1444
1445 #[inline]
1449 pub fn is_signed(&self) -> bool {
1450 self.0 <= 3 || self.0 == 8 || (self.0 >= 21 && self.0 <= 25)
1451 }
1452
1453 #[inline]
1457 pub fn is_float(&self) -> bool {
1458 (self.0 >= 10 && self.0 <= 12) || self.0 == 31 || self.0 == 32
1459 }
1460
1461 #[inline]
1463 pub fn is_numeric(&self) -> bool {
1464 self.0 <= 12 || (self.0 >= 21 && self.0 <= 32)
1465 }
1466
1467 pub fn is_copy(&self) -> bool {
1484 let tag = self.0 & 0xFF;
1485 match tag {
1486 0..=14 => true,
1488 15..=19 => true,
1490 20 => true,
1492 21..=32 => true,
1494 33 => false,
1498 TAG_ENUM => true,
1500 TAG_MODULE => true,
1502 TAG_STRUCT => false,
1504 TAG_ARRAY => false,
1506 _ => false,
1507 }
1508 }
1509
1510 pub fn is_copy_in_pool(&self, type_pool: &crate::intern_pool::TypeInternPool) -> bool {
1515 if let Some(struct_id) = self.as_struct() {
1516 type_pool.struct_def(struct_id).posture == Posture::Copy
1517 } else {
1518 self.is_copy()
1519 }
1520 }
1521
1522 #[inline]
1525 pub fn is_64_bit(&self) -> bool {
1526 self.0 == 3 || self.0 == 7
1527 }
1528
1529 #[inline]
1532 pub fn is_pointer_sized(&self) -> bool {
1533 self.0 == 8 || self.0 == 9
1534 }
1535
1536 pub fn can_coerce_to(&self, target: &Type) -> bool {
1543 self.is_never() || self.is_error() || self == target
1544 }
1545
1546 #[inline]
1550 #[must_use]
1551 pub fn is_unsigned(&self) -> bool {
1552 (self.0 >= 4 && self.0 <= 7) || self.0 == 9 || (self.0 >= 26 && self.0 <= 30)
1553 }
1554
1555 #[must_use]
1563 pub fn literal_fits(&self, value: u64) -> bool {
1564 match self.0 {
1565 0 => value <= i8::MAX as u64, 1 => value <= i16::MAX as u64, 2 => value <= i32::MAX as u64, 3 => value <= i64::MAX as u64, 4 => value <= u8::MAX as u64, 5 => value <= u16::MAX as u64, 6 => value <= u32::MAX as u64, 7 => true, 8 => value <= i64::MAX as u64, 9 => true, 21 => value <= i8::MAX as u64, 22 => value <= i16::MAX as u64, 23 => value <= i32::MAX as u64, 24 => value <= i64::MAX as u64, 25 => value <= i64::MAX as u64, 26 => value <= u8::MAX as u64, 27 => value <= u16::MAX as u64, 28 => value <= u32::MAX as u64, 29 => true, 30 => true, _ => false,
1588 }
1589 }
1590
1591 #[must_use]
1596 pub fn negated_literal_fits(&self, value: u64) -> bool {
1597 match self.0 {
1598 0 => value <= (i8::MIN as i64).unsigned_abs(), 1 => value <= (i16::MIN as i64).unsigned_abs(), 2 => value <= (i32::MIN as i64).unsigned_abs(), 3 => value <= (i64::MIN).unsigned_abs(), 8 => value <= (i64::MIN).unsigned_abs(), 21 => value <= (i8::MIN as i64).unsigned_abs(), 22 => value <= (i16::MIN as i64).unsigned_abs(), 23 => value <= (i32::MIN as i64).unsigned_abs(), 24 => value <= (i64::MIN).unsigned_abs(), 25 => value <= (i64::MIN).unsigned_abs(), _ => false,
1610 }
1611 }
1612
1613 #[inline]
1617 pub fn as_u32(&self) -> u32 {
1618 self.0
1619 }
1620
1621 #[inline]
1631 pub fn from_u32(v: u32) -> Self {
1632 Type(v)
1633 }
1634
1635 #[inline]
1651 pub fn try_from_u32(v: u32) -> Option<Self> {
1652 if Self::is_valid_encoding(v) {
1653 Some(Type(v))
1654 } else {
1655 None
1656 }
1657 }
1658
1659 #[inline]
1663 pub fn is_valid_encoding(v: u32) -> bool {
1664 let tag = v & 0xFF;
1665 match tag {
1666 0..=19 => true,
1668 TAG_STRUCT | TAG_ENUM | TAG_ARRAY | TAG_PTR_CONST | TAG_PTR_MUT | TAG_MODULE
1670 | TAG_INTERFACE | TAG_REF | TAG_MUT_REF => true,
1671 _ => false,
1673 }
1674 }
1675
1676 #[inline]
1680 pub fn is_valid(&self) -> bool {
1681 Self::is_valid_encoding(self.0)
1682 }
1683}
1684
1685impl std::fmt::Display for Type {
1686 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1687 write!(f, "{}", self.name())
1688 }
1689}
1690
1691#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
1693pub enum PtrMutability {
1694 Const,
1696 Mut,
1698}
1699
1700pub fn parse_pointer_type_syntax(type_name: &str) -> Option<(String, PtrMutability)> {
1704 let type_name = type_name.trim();
1705 if let Some(rest) = type_name.strip_prefix("ptr const ") {
1706 Some((rest.trim().to_string(), PtrMutability::Const))
1707 } else {
1708 type_name
1709 .strip_prefix("ptr mut ")
1710 .map(|rest| (rest.trim().to_string(), PtrMutability::Mut))
1711 }
1712}
1713
1714pub fn parse_type_call_syntax(s: &str) -> Option<(String, Vec<String>)> {
1720 let s = s.trim();
1721 if !s.ends_with(')') {
1722 return None;
1723 }
1724 let open = s.find('(')?;
1725 let callee = s[..open].trim().to_string();
1726 if callee.is_empty() {
1727 return None;
1728 }
1729 if !callee.chars().all(|c| c.is_alphanumeric() || c == '_') {
1731 return None;
1732 }
1733 let inner = &s[open + 1..s.len() - 1];
1734 let mut args: Vec<String> = Vec::new();
1735 let mut depth: i32 = 0;
1736 let mut current = String::new();
1737 for ch in inner.chars() {
1738 match ch {
1739 '(' | '[' => {
1740 depth += 1;
1741 current.push(ch);
1742 }
1743 ')' | ']' => {
1744 depth -= 1;
1745 current.push(ch);
1746 }
1747 ',' if depth == 0 => {
1748 args.push(current.trim().to_string());
1749 current.clear();
1750 }
1751 _ => current.push(ch),
1752 }
1753 }
1754 let trimmed = current.trim();
1755 if !trimmed.is_empty() {
1756 args.push(trimmed.to_string());
1757 }
1758 if args.is_empty() {
1759 return None;
1760 }
1761 Some((callee, args))
1762}
1763
1764pub fn parse_array_type_syntax(type_name: &str) -> Option<(String, u64)> {
1769 let type_name = type_name.trim();
1770 if !type_name.starts_with('[') || !type_name.ends_with(']') {
1771 return None;
1772 }
1773
1774 let inner = &type_name[1..type_name.len() - 1];
1776
1777 let mut bracket_depth = 0;
1780 let mut semi_pos = None;
1781 for (i, ch) in inner.char_indices() {
1782 match ch {
1783 '[' => bracket_depth += 1,
1784 ']' => bracket_depth -= 1,
1785 ';' if bracket_depth == 0 => semi_pos = Some(i),
1786 _ => {}
1787 }
1788 }
1789
1790 let semi_pos = semi_pos?;
1791 let element_type = inner[..semi_pos].trim().to_string();
1792 let length_str = inner[semi_pos + 1..].trim();
1793 let length: u64 = length_str.parse().ok()?;
1794
1795 Some((element_type, length))
1796}
1797
1798pub fn parse_tuple_type_syntax(type_name: &str) -> Option<Vec<String>> {
1810 let type_name = type_name.trim();
1811 if !type_name.starts_with('(') || !type_name.ends_with(')') {
1812 return None;
1813 }
1814 let inner = type_name[1..type_name.len() - 1].trim();
1815 if inner.is_empty() {
1817 return None;
1818 }
1819
1820 let mut parts: Vec<String> = Vec::new();
1822 let mut depth_paren = 0i32;
1823 let mut depth_bracket = 0i32;
1824 let mut last = 0usize;
1825 for (i, ch) in inner.char_indices() {
1826 match ch {
1827 '(' => depth_paren += 1,
1828 ')' => depth_paren -= 1,
1829 '[' => depth_bracket += 1,
1830 ']' => depth_bracket -= 1,
1831 ',' if depth_paren == 0 && depth_bracket == 0 => {
1832 parts.push(inner[last..i].trim().to_string());
1833 last = i + 1;
1834 }
1835 _ => {}
1836 }
1837 }
1838 let tail = inner[last..].trim();
1839 if parts.is_empty() {
1841 return None;
1842 }
1843 if !tail.is_empty() {
1845 parts.push(tail.to_string());
1846 }
1847 if parts.iter().any(|p| p.is_empty()) {
1849 return None;
1850 }
1851 Some(parts)
1852}
1853
1854#[cfg(test)]
1855mod tests {
1856 use super::*;
1857
1858 #[test]
1859 fn test_parse_tuple_pair() {
1860 assert_eq!(
1861 parse_tuple_type_syntax("(i32, bool)"),
1862 Some(vec!["i32".into(), "bool".into()])
1863 );
1864 }
1865
1866 #[test]
1867 fn test_parse_tuple_singleton() {
1868 assert_eq!(parse_tuple_type_syntax("(i32,)"), Some(vec!["i32".into()]));
1869 }
1870
1871 #[test]
1872 fn test_parse_tuple_triple_with_trailing_comma() {
1873 assert_eq!(
1874 parse_tuple_type_syntax("(i32, u8, bool,)"),
1875 Some(vec!["i32".into(), "u8".into(), "bool".into()])
1876 );
1877 }
1878
1879 #[test]
1880 fn test_parse_tuple_nested() {
1881 assert_eq!(
1882 parse_tuple_type_syntax("((i32, u8), bool)"),
1883 Some(vec!["(i32, u8)".into(), "bool".into()])
1884 );
1885 }
1886
1887 #[test]
1888 fn test_parse_tuple_with_array_element() {
1889 assert_eq!(
1890 parse_tuple_type_syntax("([i32; 3], bool)"),
1891 Some(vec!["[i32; 3]".into(), "bool".into()])
1892 );
1893 }
1894
1895 #[test]
1896 fn test_parse_tuple_unit_is_not_tuple() {
1897 assert_eq!(parse_tuple_type_syntax("()"), None);
1898 }
1899
1900 #[test]
1901 fn test_parse_tuple_single_paren_is_not_tuple() {
1902 assert_eq!(parse_tuple_type_syntax("(i32)"), None);
1904 }
1905
1906 #[test]
1907 fn test_parse_tuple_non_tuple() {
1908 assert_eq!(parse_tuple_type_syntax("i32"), None);
1909 assert_eq!(parse_tuple_type_syntax("[i32; 3]"), None);
1910 }
1911
1912 #[test]
1915 fn test_struct_id_equality() {
1916 let id1 = StructId(0);
1917 let id2 = StructId(0);
1918 let id3 = StructId(1);
1919 assert_eq!(id1, id2);
1920 assert_ne!(id1, id3);
1921 }
1922
1923 #[test]
1924 fn test_enum_id_equality() {
1925 let id1 = EnumId(0);
1926 let id2 = EnumId(0);
1927 let id3 = EnumId(1);
1928 assert_eq!(id1, id2);
1929 assert_ne!(id1, id3);
1930 }
1931
1932 #[test]
1933 fn test_array_type_id_equality() {
1934 let id1 = ArrayTypeId(0);
1935 let id2 = ArrayTypeId(0);
1936 let id3 = ArrayTypeId(1);
1937 assert_eq!(id1, id2);
1938 assert_ne!(id1, id3);
1939 }
1940
1941 #[test]
1944 fn test_type_name_integers() {
1945 assert_eq!(Type::I8.name(), "i8");
1946 assert_eq!(Type::I16.name(), "i16");
1947 assert_eq!(Type::I32.name(), "i32");
1948 assert_eq!(Type::I64.name(), "i64");
1949 assert_eq!(Type::U8.name(), "u8");
1950 assert_eq!(Type::U16.name(), "u16");
1951 assert_eq!(Type::U32.name(), "u32");
1952 assert_eq!(Type::U64.name(), "u64");
1953 }
1954
1955 #[test]
1956 fn test_type_name_other() {
1957 assert_eq!(Type::BOOL.name(), "bool");
1958 assert_eq!(Type::UNIT.name(), "()");
1959 assert_eq!(Type::ERROR.name(), "<error>");
1960 assert_eq!(Type::NEVER.name(), "!");
1961 }
1962
1963 #[test]
1964 fn test_type_name_composite() {
1965 assert_eq!(Type::new_struct(StructId(0)).name(), "<struct>");
1966 assert_eq!(Type::new_enum(EnumId(0)).name(), "<enum>");
1967 assert_eq!(Type::new_array(ArrayTypeId(0)).name(), "<array>");
1968 }
1969
1970 #[test]
1973 fn test_is_integer_signed() {
1974 assert!(Type::I8.is_integer());
1975 assert!(Type::I16.is_integer());
1976 assert!(Type::I32.is_integer());
1977 assert!(Type::I64.is_integer());
1978 }
1979
1980 #[test]
1981 fn test_is_integer_unsigned() {
1982 assert!(Type::U8.is_integer());
1983 assert!(Type::U16.is_integer());
1984 assert!(Type::U32.is_integer());
1985 assert!(Type::U64.is_integer());
1986 }
1987
1988 #[test]
1989 fn test_is_integer_non_integers() {
1990 assert!(!Type::BOOL.is_integer());
1991 assert!(!Type::UNIT.is_integer());
1992 assert!(!Type::new_struct(StructId(0)).is_integer());
1993 assert!(!Type::new_enum(EnumId(0)).is_integer());
1994 assert!(!Type::new_array(ArrayTypeId(0)).is_integer());
1995 assert!(!Type::ERROR.is_integer());
1996 assert!(!Type::NEVER.is_integer());
1997 }
1998
1999 #[test]
2002 fn test_is_signed() {
2003 assert!(Type::I8.is_signed());
2004 assert!(Type::I16.is_signed());
2005 assert!(Type::I32.is_signed());
2006 assert!(Type::I64.is_signed());
2007
2008 assert!(!Type::U8.is_signed());
2009 assert!(!Type::U16.is_signed());
2010 assert!(!Type::U32.is_signed());
2011 assert!(!Type::U64.is_signed());
2012 assert!(!Type::BOOL.is_signed());
2013 }
2014
2015 #[test]
2018 fn test_is_unsigned() {
2019 assert!(Type::U8.is_unsigned());
2020 assert!(Type::U16.is_unsigned());
2021 assert!(Type::U32.is_unsigned());
2022 assert!(Type::U64.is_unsigned());
2023
2024 assert!(!Type::I8.is_unsigned());
2025 assert!(!Type::I16.is_unsigned());
2026 assert!(!Type::I32.is_unsigned());
2027 assert!(!Type::I64.is_unsigned());
2028 assert!(!Type::BOOL.is_unsigned());
2029 }
2030
2031 #[test]
2034 fn test_is_64_bit() {
2035 assert!(Type::I64.is_64_bit());
2036 assert!(Type::U64.is_64_bit());
2037
2038 assert!(!Type::I8.is_64_bit());
2039 assert!(!Type::I16.is_64_bit());
2040 assert!(!Type::I32.is_64_bit());
2041 assert!(!Type::U8.is_64_bit());
2042 assert!(!Type::U16.is_64_bit());
2043 assert!(!Type::U32.is_64_bit());
2044 assert!(!Type::BOOL.is_64_bit());
2045 }
2046
2047 #[test]
2050 fn test_is_error() {
2051 assert!(Type::ERROR.is_error());
2052 assert!(!Type::I32.is_error());
2053 assert!(!Type::NEVER.is_error());
2054 }
2055
2056 #[test]
2059 fn test_is_never() {
2060 assert!(Type::NEVER.is_never());
2061 assert!(!Type::I32.is_never());
2062 assert!(!Type::ERROR.is_never());
2063 }
2064
2065 #[test]
2068 fn test_is_struct() {
2069 assert!(Type::new_struct(StructId(0)).is_struct());
2070 assert!(Type::new_struct(StructId(42)).is_struct());
2071 assert!(!Type::I32.is_struct());
2072 assert!(!Type::new_enum(EnumId(0)).is_struct());
2073 }
2074
2075 #[test]
2076 fn test_as_struct() {
2077 assert_eq!(Type::new_struct(StructId(5)).as_struct(), Some(StructId(5)));
2078 assert_eq!(Type::I32.as_struct(), None);
2079 assert_eq!(Type::new_enum(EnumId(0)).as_struct(), None);
2080 }
2081
2082 #[test]
2085 fn test_is_enum() {
2086 assert!(Type::new_enum(EnumId(0)).is_enum());
2087 assert!(Type::new_enum(EnumId(42)).is_enum());
2088 assert!(!Type::I32.is_enum());
2089 assert!(!Type::new_struct(StructId(0)).is_enum());
2090 }
2091
2092 #[test]
2093 fn test_as_enum() {
2094 assert_eq!(Type::new_enum(EnumId(5)).as_enum(), Some(EnumId(5)));
2095 assert_eq!(Type::I32.as_enum(), None);
2096 assert_eq!(Type::new_struct(StructId(0)).as_enum(), None);
2097 }
2098
2099 #[test]
2102 fn test_is_array() {
2103 assert!(Type::new_array(ArrayTypeId(0)).is_array());
2104 assert!(Type::new_array(ArrayTypeId(42)).is_array());
2105 assert!(!Type::I32.is_array());
2106 assert!(!Type::new_struct(StructId(0)).is_array());
2107 }
2108
2109 #[test]
2110 fn test_as_array() {
2111 assert_eq!(
2112 Type::new_array(ArrayTypeId(5)).as_array(),
2113 Some(ArrayTypeId(5))
2114 );
2115 assert_eq!(Type::I32.as_array(), None);
2116 assert_eq!(Type::new_struct(StructId(0)).as_array(), None);
2117 }
2118
2119 #[test]
2122 fn test_is_copy_primitives() {
2123 assert!(Type::I8.is_copy());
2125 assert!(Type::I16.is_copy());
2126 assert!(Type::I32.is_copy());
2127 assert!(Type::I64.is_copy());
2128 assert!(Type::U8.is_copy());
2129 assert!(Type::U16.is_copy());
2130 assert!(Type::U32.is_copy());
2131 assert!(Type::U64.is_copy());
2132
2133 assert!(Type::BOOL.is_copy());
2135 assert!(Type::UNIT.is_copy());
2136 }
2137
2138 #[test]
2139 fn test_is_copy_special() {
2140 assert!(Type::new_enum(EnumId(0)).is_copy());
2142
2143 assert!(Type::NEVER.is_copy());
2145 assert!(Type::ERROR.is_copy());
2146 }
2147
2148 #[test]
2149 fn test_is_copy_move_types() {
2150 assert!(!Type::new_struct(StructId(0)).is_copy());
2152 assert!(!Type::new_array(ArrayTypeId(0)).is_copy());
2153 }
2154
2155 #[test]
2158 fn test_can_coerce_to_same_type() {
2159 assert!(Type::I32.can_coerce_to(&Type::I32));
2160 assert!(Type::BOOL.can_coerce_to(&Type::BOOL));
2161 assert!(Type::new_struct(StructId(0)).can_coerce_to(&Type::new_struct(StructId(0))));
2162 }
2163
2164 #[test]
2165 fn test_can_coerce_to_never_coerces_to_anything() {
2166 assert!(Type::NEVER.can_coerce_to(&Type::I32));
2167 assert!(Type::NEVER.can_coerce_to(&Type::BOOL));
2168 assert!(Type::NEVER.can_coerce_to(&Type::new_struct(StructId(0))));
2169 }
2170
2171 #[test]
2172 fn test_can_coerce_to_error_coerces_to_anything() {
2173 assert!(Type::ERROR.can_coerce_to(&Type::I32));
2174 assert!(Type::ERROR.can_coerce_to(&Type::BOOL));
2175 assert!(Type::ERROR.can_coerce_to(&Type::new_struct(StructId(0))));
2176 }
2177
2178 #[test]
2179 fn test_can_coerce_to_different_types_fail() {
2180 assert!(!Type::I32.can_coerce_to(&Type::BOOL));
2181 assert!(!Type::BOOL.can_coerce_to(&Type::I32));
2182 assert!(!Type::I32.can_coerce_to(&Type::I64));
2183 assert!(!Type::new_struct(StructId(0)).can_coerce_to(&Type::I32));
2184 }
2185
2186 #[test]
2189 fn test_literal_fits_i8() {
2190 assert!(Type::I8.literal_fits(0));
2191 assert!(Type::I8.literal_fits(127)); assert!(!Type::I8.literal_fits(128));
2193 }
2194
2195 #[test]
2196 fn test_literal_fits_i16() {
2197 assert!(Type::I16.literal_fits(0));
2198 assert!(Type::I16.literal_fits(32767)); assert!(!Type::I16.literal_fits(32768));
2200 }
2201
2202 #[test]
2203 fn test_literal_fits_i32() {
2204 assert!(Type::I32.literal_fits(0));
2205 assert!(Type::I32.literal_fits(2147483647)); assert!(!Type::I32.literal_fits(2147483648));
2207 }
2208
2209 #[test]
2210 fn test_literal_fits_i64() {
2211 assert!(Type::I64.literal_fits(0));
2212 assert!(Type::I64.literal_fits(9223372036854775807)); assert!(!Type::I64.literal_fits(9223372036854775808));
2214 }
2215
2216 #[test]
2217 fn test_literal_fits_u8() {
2218 assert!(Type::U8.literal_fits(0));
2219 assert!(Type::U8.literal_fits(255)); assert!(!Type::U8.literal_fits(256));
2221 }
2222
2223 #[test]
2224 fn test_literal_fits_u16() {
2225 assert!(Type::U16.literal_fits(0));
2226 assert!(Type::U16.literal_fits(65535)); assert!(!Type::U16.literal_fits(65536));
2228 }
2229
2230 #[test]
2231 fn test_literal_fits_u32() {
2232 assert!(Type::U32.literal_fits(0));
2233 assert!(Type::U32.literal_fits(4294967295)); assert!(!Type::U32.literal_fits(4294967296));
2235 }
2236
2237 #[test]
2238 fn test_literal_fits_u64() {
2239 assert!(Type::U64.literal_fits(0));
2240 assert!(Type::U64.literal_fits(u64::MAX)); }
2242
2243 #[test]
2244 fn test_literal_fits_non_integer() {
2245 assert!(!Type::BOOL.literal_fits(0));
2246 assert!(!Type::new_struct(StructId(0)).literal_fits(0));
2247 assert!(!Type::UNIT.literal_fits(0));
2248 }
2249
2250 #[test]
2253 fn test_negated_literal_fits_i8() {
2254 assert!(Type::I8.negated_literal_fits(128)); assert!(!Type::I8.negated_literal_fits(129));
2256 }
2257
2258 #[test]
2259 fn test_negated_literal_fits_i16() {
2260 assert!(Type::I16.negated_literal_fits(32768)); assert!(!Type::I16.negated_literal_fits(32769));
2262 }
2263
2264 #[test]
2265 fn test_negated_literal_fits_i32() {
2266 assert!(Type::I32.negated_literal_fits(2147483648)); assert!(!Type::I32.negated_literal_fits(2147483649));
2268 }
2269
2270 #[test]
2271 fn test_negated_literal_fits_i64() {
2272 assert!(Type::I64.negated_literal_fits(9223372036854775808)); assert!(!Type::I64.negated_literal_fits(9223372036854775809));
2274 }
2275
2276 #[test]
2277 fn test_negated_literal_fits_unsigned() {
2278 assert!(!Type::U8.negated_literal_fits(1));
2280 assert!(!Type::U16.negated_literal_fits(1));
2281 assert!(!Type::U32.negated_literal_fits(1));
2282 assert!(!Type::U64.negated_literal_fits(1));
2283 }
2284
2285 #[test]
2286 fn test_negated_literal_fits_non_integer() {
2287 assert!(!Type::BOOL.negated_literal_fits(1));
2288 assert!(!Type::new_struct(StructId(0)).negated_literal_fits(1));
2289 }
2290
2291 #[test]
2294 fn test_type_display() {
2295 assert_eq!(format!("{}", Type::I32), "i32");
2296 assert_eq!(format!("{}", Type::BOOL), "bool");
2297 assert_eq!(format!("{}", Type::NEVER), "!");
2298 }
2299
2300 #[test]
2303 fn test_type_default() {
2304 assert_eq!(Type::default(), Type::UNIT);
2305 }
2306
2307 #[test]
2310 fn test_struct_def_find_field() {
2311 let def = StructDef {
2312 name: "Point".to_string(),
2313 fields: vec![
2314 StructField {
2315 name: "x".to_string(),
2316 ty: Type::I32,
2317
2318 is_pub: true,
2319 },
2320 StructField {
2321 name: "y".to_string(),
2322 ty: Type::I32,
2323
2324 is_pub: true,
2325 },
2326 ],
2327 posture: Posture::Affine,
2328 is_clone: false,
2329 thread_safety: ThreadSafety::Sync,
2330 destructor: None,
2331 is_builtin: false,
2332 is_pub: false,
2333 file_id: gruel_util::FileId::DEFAULT,
2334 is_c_layout: false,
2335 };
2336
2337 let (idx, field) = def.find_field("x").unwrap();
2338 assert_eq!(idx, 0);
2339 assert_eq!(field.name, "x");
2340 assert_eq!(field.ty, Type::I32);
2341
2342 let (idx, field) = def.find_field("y").unwrap();
2343 assert_eq!(idx, 1);
2344 assert_eq!(field.name, "y");
2345
2346 assert!(def.find_field("z").is_none());
2347 }
2348
2349 #[test]
2350 fn test_struct_def_field_count() {
2351 let empty = StructDef {
2352 name: "Empty".to_string(),
2353 fields: vec![],
2354 posture: Posture::Affine,
2355 is_clone: false,
2356 thread_safety: ThreadSafety::Sync,
2357 destructor: None,
2358 is_builtin: false,
2359 is_pub: false,
2360 file_id: gruel_util::FileId::DEFAULT,
2361 is_c_layout: false,
2362 };
2363 assert_eq!(empty.field_count(), 0);
2364
2365 let with_fields = StructDef {
2366 name: "Data".to_string(),
2367 fields: vec![
2368 StructField {
2369 name: "a".to_string(),
2370 ty: Type::I32,
2371
2372 is_pub: true,
2373 },
2374 StructField {
2375 name: "b".to_string(),
2376 ty: Type::BOOL,
2377
2378 is_pub: true,
2379 },
2380 StructField {
2381 name: "c".to_string(),
2382 ty: Type::I64,
2383
2384 is_pub: true,
2385 },
2386 ],
2387 posture: Posture::Affine,
2388 is_clone: false,
2389 thread_safety: ThreadSafety::Sync,
2390 destructor: None,
2391 is_builtin: false,
2392 is_pub: false,
2393 file_id: gruel_util::FileId::DEFAULT,
2394 is_c_layout: false,
2395 };
2396 assert_eq!(with_fields.field_count(), 3);
2397 }
2398
2399 #[test]
2402 fn test_enum_def_variant_count() {
2403 let empty = EnumDef {
2404 name: "Empty".to_string(),
2405 variants: vec![],
2406 posture: Posture::Affine,
2407 thread_safety: ThreadSafety::Sync,
2408 is_pub: false,
2409 file_id: gruel_util::FileId::DEFAULT,
2410 destructor: None,
2411 is_c_layout: false,
2412 };
2413 assert_eq!(empty.variant_count(), 0);
2414
2415 let color = EnumDef {
2416 name: "Color".to_string(),
2417 variants: vec![
2418 EnumVariantDef::unit("Red"),
2419 EnumVariantDef::unit("Green"),
2420 EnumVariantDef::unit("Blue"),
2421 ],
2422 posture: Posture::Affine,
2423 thread_safety: ThreadSafety::Sync,
2424 is_pub: false,
2425 file_id: gruel_util::FileId::DEFAULT,
2426 destructor: None,
2427 is_c_layout: false,
2428 };
2429 assert_eq!(color.variant_count(), 3);
2430 }
2431
2432 #[test]
2433 fn test_enum_def_find_variant() {
2434 let color = EnumDef {
2435 name: "Color".to_string(),
2436 variants: vec![
2437 EnumVariantDef::unit("Red"),
2438 EnumVariantDef::unit("Green"),
2439 EnumVariantDef::unit("Blue"),
2440 ],
2441 posture: Posture::Affine,
2442 thread_safety: ThreadSafety::Sync,
2443 is_pub: false,
2444 file_id: gruel_util::FileId::DEFAULT,
2445 destructor: None,
2446 is_c_layout: false,
2447 };
2448
2449 assert_eq!(color.find_variant("Red"), Some(0));
2450 assert_eq!(color.find_variant("Green"), Some(1));
2451 assert_eq!(color.find_variant("Blue"), Some(2));
2452 assert_eq!(color.find_variant("Yellow"), None);
2453 }
2454
2455 #[test]
2456 fn test_enum_def_discriminant_type_empty() {
2457 let empty = EnumDef {
2458 name: "Empty".to_string(),
2459 variants: vec![],
2460 posture: Posture::Affine,
2461 thread_safety: ThreadSafety::Sync,
2462 is_pub: false,
2463 file_id: gruel_util::FileId::DEFAULT,
2464 destructor: None,
2465 is_c_layout: false,
2466 };
2467 assert_eq!(empty.discriminant_type(), Type::NEVER);
2468 }
2469
2470 #[test]
2471 fn test_enum_def_discriminant_type_small() {
2472 let small = EnumDef {
2474 name: "Small".to_string(),
2475 variants: vec![EnumVariantDef::unit("A")],
2476 posture: Posture::Affine,
2477 thread_safety: ThreadSafety::Sync,
2478 is_pub: false,
2479 file_id: gruel_util::FileId::DEFAULT,
2480 destructor: None,
2481 is_c_layout: false,
2482 };
2483 assert_eq!(small.discriminant_type(), Type::U8);
2484
2485 let max_u8 = EnumDef {
2486 name: "MaxU8".to_string(),
2487 variants: (0..256)
2488 .map(|i| EnumVariantDef::unit(format!("V{}", i)))
2489 .collect(),
2490 posture: Posture::Affine,
2491 thread_safety: ThreadSafety::Sync,
2492 is_pub: false,
2493 file_id: gruel_util::FileId::DEFAULT,
2494 destructor: None,
2495 is_c_layout: false,
2496 };
2497 assert_eq!(max_u8.discriminant_type(), Type::U8);
2498 }
2499
2500 #[test]
2501 fn test_enum_def_discriminant_type_medium() {
2502 let medium = EnumDef {
2504 name: "Medium".to_string(),
2505 variants: (0..257)
2506 .map(|i| EnumVariantDef::unit(format!("V{}", i)))
2507 .collect(),
2508 posture: Posture::Affine,
2509 thread_safety: ThreadSafety::Sync,
2510 is_pub: false,
2511 file_id: gruel_util::FileId::DEFAULT,
2512 destructor: None,
2513 is_c_layout: false,
2514 };
2515 assert_eq!(medium.discriminant_type(), Type::U16);
2516 }
2517
2518 #[test]
2521 fn test_comptime_type_name() {
2522 assert_eq!(Type::COMPTIME_TYPE.name(), "type");
2523 }
2524
2525 #[test]
2526 fn test_comptime_type_is_copy() {
2527 assert!(Type::COMPTIME_TYPE.is_copy());
2528 }
2529
2530 #[test]
2531 fn test_comptime_type_is_comptime_type() {
2532 assert!(Type::COMPTIME_TYPE.is_comptime_type());
2533 assert!(!Type::I32.is_comptime_type());
2534 assert!(!Type::BOOL.is_comptime_type());
2535 }
2536
2537 #[test]
2538 fn test_comptime_type_not_integer() {
2539 assert!(!Type::COMPTIME_TYPE.is_integer());
2540 }
2541
2542 #[test]
2543 fn test_comptime_type_not_signed() {
2544 assert!(!Type::COMPTIME_TYPE.is_signed());
2545 }
2546
2547 #[test]
2548 fn test_comptime_type_not_64_bit() {
2549 assert!(!Type::COMPTIME_TYPE.is_64_bit());
2550 }
2551
2552 #[test]
2553 fn test_comptime_type_can_coerce_to_itself() {
2554 assert!(Type::COMPTIME_TYPE.can_coerce_to(&Type::COMPTIME_TYPE));
2555 }
2556
2557 #[test]
2558 fn test_comptime_type_cannot_coerce_to_runtime_types() {
2559 assert!(!Type::COMPTIME_TYPE.can_coerce_to(&Type::I32));
2560 assert!(!Type::COMPTIME_TYPE.can_coerce_to(&Type::BOOL));
2561 }
2562
2563 #[test]
2566 fn test_is_valid_encoding_primitives() {
2567 for i in 0..=19u32 {
2569 assert!(
2570 Type::is_valid_encoding(i),
2571 "primitive tag {} should be valid",
2572 i
2573 );
2574 }
2575 }
2576
2577 #[test]
2578 fn test_is_valid_encoding_composites() {
2579 assert!(Type::is_valid_encoding(100)); assert!(Type::is_valid_encoding(101)); assert!(Type::is_valid_encoding(102)); assert!(Type::is_valid_encoding(103)); assert!(Type::is_valid_encoding(104)); assert!(Type::is_valid_encoding(105)); assert!(Type::is_valid_encoding(100 | (42 << 8))); assert!(Type::is_valid_encoding(101 | (100 << 8))); }
2591
2592 #[test]
2593 fn test_is_valid_encoding_invalid() {
2594 for tag in 20..100u32 {
2596 assert!(
2597 !Type::is_valid_encoding(tag),
2598 "tag {} should be invalid",
2599 tag
2600 );
2601 }
2602
2603 for tag in 109..=255u32 {
2605 assert!(
2606 !Type::is_valid_encoding(tag),
2607 "tag {} should be invalid",
2608 tag
2609 );
2610 }
2611 }
2612
2613 #[test]
2614 fn test_try_from_u32_valid() {
2615 assert!(Type::try_from_u32(0).is_some()); assert!(Type::try_from_u32(2).is_some()); assert!(Type::try_from_u32(10).is_some()); assert!(Type::try_from_u32(100).is_some()); assert!(Type::try_from_u32(100 | (42 << 8)).is_some()); }
2624
2625 #[test]
2626 fn test_try_from_u32_invalid() {
2627 assert!(Type::try_from_u32(50).is_none());
2629 assert!(Type::try_from_u32(99).is_none());
2630 assert!(Type::try_from_u32(109).is_none());
2631 assert!(Type::try_from_u32(255).is_none());
2632 }
2633
2634 #[test]
2635 fn test_try_kind_valid() {
2636 assert_eq!(Type::I32.try_kind(), Some(TypeKind::I32));
2637 assert_eq!(Type::BOOL.try_kind(), Some(TypeKind::Bool));
2638 assert_eq!(
2639 Type::new_struct(StructId(42)).try_kind(),
2640 Some(TypeKind::Struct(StructId(42)))
2641 );
2642 }
2643
2644 #[test]
2645 fn test_try_kind_invalid() {
2646 let invalid = Type::from_u32(50); assert!(invalid.try_kind().is_none());
2649
2650 let invalid2 = Type::from_u32(200); assert!(invalid2.try_kind().is_none());
2652 }
2653
2654 #[test]
2655 fn test_is_valid_method() {
2656 assert!(Type::I32.is_valid());
2657 assert!(Type::new_struct(StructId(0)).is_valid());
2658
2659 let invalid = Type::from_u32(50);
2661 assert!(!invalid.is_valid());
2662 }
2663
2664 #[test]
2665 #[should_panic(expected = "invalid Type encoding")]
2666 fn test_kind_panics_on_invalid() {
2667 let invalid = Type::from_u32(50);
2668 let _ = invalid.kind(); }
2670
2671 #[test]
2672 fn test_roundtrip_encoding() {
2673 let types = [
2675 Type::I8,
2676 Type::I16,
2677 Type::I32,
2678 Type::I64,
2679 Type::U8,
2680 Type::U16,
2681 Type::U32,
2682 Type::U64,
2683 Type::BOOL,
2684 Type::UNIT,
2685 Type::ERROR,
2686 Type::NEVER,
2687 Type::COMPTIME_TYPE,
2688 Type::COMPTIME_STR,
2689 Type::new_struct(StructId(0)),
2690 Type::new_struct(StructId(1000)),
2691 Type::new_enum(EnumId(5)),
2692 Type::new_array(ArrayTypeId(10)),
2693 Type::new_ptr_const(PtrConstTypeId(20)),
2694 Type::new_ptr_mut(PtrMutTypeId(30)),
2695 Type::new_module(ModuleId(40)),
2696 ];
2697
2698 for ty in types {
2699 let encoded = ty.as_u32();
2700 let decoded = Type::from_u32(encoded);
2701 assert_eq!(ty, decoded, "roundtrip failed for {:?}", ty);
2702 assert!(
2703 decoded.is_valid(),
2704 "{:?} should be valid after roundtrip",
2705 ty
2706 );
2707 }
2708 }
2709}