1use std::collections::HashMap;
39use std::sync::{PoisonError, RwLock};
40
41use lasso::Spur;
42
43use crate::types::{
44 ArrayTypeId, EnumDef, EnumId, PtrConstTypeId, PtrMutTypeId, StructDef, StructId, Type, TypeKind,
45};
46
47#[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
74pub struct InternedType(u32);
75
76impl InternedType {
77 pub const I8: InternedType = InternedType(0);
79 pub const I16: InternedType = InternedType(1);
80 pub const I32: InternedType = InternedType(2);
81 pub const I64: InternedType = InternedType(3);
82 pub const U8: InternedType = InternedType(4);
83 pub const U16: InternedType = InternedType(5);
84 pub const U32: InternedType = InternedType(6);
85 pub const U64: InternedType = InternedType(7);
86 pub const ISIZE: InternedType = InternedType(8);
87 pub const USIZE: InternedType = InternedType(9);
88 pub const F16: InternedType = InternedType(10);
89 pub const F32: InternedType = InternedType(11);
90 pub const F64: InternedType = InternedType(12);
91 pub const BOOL: InternedType = InternedType(13);
92 pub const UNIT: InternedType = InternedType(14);
93 pub const NEVER: InternedType = InternedType(15);
94 pub const ERROR: InternedType = InternedType(16);
95
96 const PRIMITIVE_COUNT: u32 = 19;
97
98 #[inline]
100 pub fn is_primitive(self) -> bool {
101 self.0 < Self::PRIMITIVE_COUNT
102 }
103
104 #[inline]
106 pub fn index(self) -> u32 {
107 self.0
108 }
109
110 #[inline]
117 pub fn from_raw(index: u32) -> Self {
118 InternedType(index)
119 }
120
121 #[inline]
125 fn from_pool_index(pool_index: u32) -> Self {
126 InternedType(pool_index + Self::PRIMITIVE_COUNT)
127 }
128
129 #[inline]
133 pub fn pool_index(self) -> Option<u32> {
134 if self.is_primitive() {
135 None
136 } else {
137 Some(self.0 - Self::PRIMITIVE_COUNT)
138 }
139 }
140}
141
142impl std::fmt::Debug for InternedType {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 if self.is_primitive() {
145 let name = match self.0 {
146 0 => "i8",
147 1 => "i16",
148 2 => "i32",
149 3 => "i64",
150 4 => "u8",
151 5 => "u16",
152 6 => "u32",
153 7 => "u64",
154 8 => "bool",
155 9 => "()",
156 10 => "!",
157 11 => "<error>",
158 _ => "<reserved>",
159 };
160 write!(f, "InternedType({name})")
161 } else {
162 write!(f, "InternedType(pool:{})", self.0 - Self::PRIMITIVE_COUNT)
163 }
164 }
165}
166
167#[derive(Debug, Clone)]
176pub enum TypeData {
177 Struct(StructData),
181
182 Enum(EnumData),
186
187 Array { element: InternedType, len: u64 },
192
193 PtrConst { pointee: InternedType },
197
198 PtrMut { pointee: InternedType },
202}
203
204#[derive(Debug, Clone)]
209pub struct StructData {
210 pub name: Spur,
212 pub def: StructDef,
216}
217
218#[derive(Debug, Clone)]
223pub struct EnumData {
224 pub name: Spur,
226 pub def: EnumDef,
230}
231
232#[derive(Debug)]
264pub struct TypeInternPool {
265 inner: RwLock<TypeInternPoolInner>,
266}
267
268#[derive(Debug)]
269struct TypeInternPoolInner {
270 types: Vec<TypeData>,
272
273 array_map: HashMap<(InternedType, u64), InternedType>,
275
276 ptr_const_map: HashMap<InternedType, InternedType>,
278
279 ptr_mut_map: HashMap<InternedType, InternedType>,
281
282 struct_by_name: HashMap<Spur, InternedType>,
284
285 enum_by_name: HashMap<Spur, InternedType>,
287}
288
289impl TypeInternPool {
290 pub fn new() -> Self {
292 Self {
293 inner: RwLock::new(TypeInternPoolInner {
294 types: Vec::new(),
295 array_map: HashMap::new(),
296 ptr_const_map: HashMap::new(),
297 ptr_mut_map: HashMap::new(),
298 struct_by_name: HashMap::new(),
299 enum_by_name: HashMap::new(),
300 }),
301 }
302 }
303
304 pub fn register_struct(&self, name: Spur, def: StructDef) -> (StructId, bool) {
309 {
311 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
312 if let Some(&existing) = inner.struct_by_name.get(&name) {
313 let pool_index = existing.pool_index().expect("struct must have pool index");
315 return (StructId::from_pool_index(pool_index), false);
316 }
317 }
318
319 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
321
322 if let Some(&existing) = inner.struct_by_name.get(&name) {
324 let pool_index = existing.pool_index().expect("struct must have pool index");
325 return (StructId::from_pool_index(pool_index), false);
326 }
327
328 let pool_index = inner.types.len() as u32;
330 let interned = InternedType::from_pool_index(pool_index);
331
332 inner.types.push(TypeData::Struct(StructData { name, def }));
333 inner.struct_by_name.insert(name, interned);
334
335 (StructId::from_pool_index(pool_index), true)
336 }
337
338 pub fn reserve_struct_id(&self) -> StructId {
359 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
360
361 let pool_index = inner.types.len() as u32;
364
365 inner.types.push(TypeData::Struct(StructData {
368 name: Spur::default(),
369 def: StructDef {
370 name: String::new(),
371 fields: vec![],
372 is_copy: false,
373 is_handle: false,
374 is_linear: false,
375 destructor: None,
376 is_builtin: false,
377 is_pub: false,
378 file_id: gruel_span::FileId::DEFAULT,
379 },
380 }));
381
382 StructId::from_pool_index(pool_index)
383 }
384
385 pub fn complete_struct_registration(&self, struct_id: StructId, name: Spur, def: StructDef) {
397 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
398 let pool_index = struct_id.0 as usize;
399
400 assert!(
402 pool_index < inner.types.len(),
403 "Invalid reserved struct ID: index {} out of bounds (len {})",
404 pool_index,
405 inner.types.len()
406 );
407
408 assert!(
410 !inner.struct_by_name.contains_key(&name),
411 "Struct with this name already exists"
412 );
413
414 inner.types[pool_index] = TypeData::Struct(StructData { name, def });
416
417 let interned = InternedType::from_pool_index(pool_index as u32);
419 inner.struct_by_name.insert(name, interned);
420 }
421
422 pub fn register_enum(&self, name: Spur, def: EnumDef) -> (EnumId, bool) {
427 {
429 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
430 if let Some(&existing) = inner.enum_by_name.get(&name) {
431 let pool_index = existing.pool_index().expect("enum must have pool index");
432 return (EnumId::from_pool_index(pool_index), false);
433 }
434 }
435
436 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
438
439 if let Some(&existing) = inner.enum_by_name.get(&name) {
441 let pool_index = existing.pool_index().expect("enum must have pool index");
442 return (EnumId::from_pool_index(pool_index), false);
443 }
444
445 let pool_index = inner.types.len() as u32;
447 let interned = InternedType::from_pool_index(pool_index);
448
449 inner.types.push(TypeData::Enum(EnumData { name, def }));
450 inner.enum_by_name.insert(name, interned);
451
452 (EnumId::from_pool_index(pool_index), true)
453 }
454
455 pub fn intern_array(&self, element: InternedType, len: u64) -> InternedType {
460 let key = (element, len);
461
462 {
464 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
465 if let Some(&existing) = inner.array_map.get(&key) {
466 return existing;
467 }
468 }
469
470 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
472
473 if let Some(&existing) = inner.array_map.get(&key) {
475 return existing;
476 }
477
478 let pool_index = inner.types.len() as u32;
480 let interned = InternedType::from_pool_index(pool_index);
481
482 inner.types.push(TypeData::Array { element, len });
483 inner.array_map.insert(key, interned);
484
485 interned
486 }
487
488 pub fn intern_ptr_const(&self, pointee: InternedType) -> InternedType {
493 {
495 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
496 if let Some(&existing) = inner.ptr_const_map.get(&pointee) {
497 return existing;
498 }
499 }
500
501 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
503
504 if let Some(&existing) = inner.ptr_const_map.get(&pointee) {
506 return existing;
507 }
508
509 let pool_index = inner.types.len() as u32;
511 let interned = InternedType::from_pool_index(pool_index);
512
513 inner.types.push(TypeData::PtrConst { pointee });
514 inner.ptr_const_map.insert(pointee, interned);
515
516 interned
517 }
518
519 pub fn intern_ptr_mut(&self, pointee: InternedType) -> InternedType {
524 {
526 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
527 if let Some(&existing) = inner.ptr_mut_map.get(&pointee) {
528 return existing;
529 }
530 }
531
532 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
534
535 if let Some(&existing) = inner.ptr_mut_map.get(&pointee) {
537 return existing;
538 }
539
540 let pool_index = inner.types.len() as u32;
542 let interned = InternedType::from_pool_index(pool_index);
543
544 inner.types.push(TypeData::PtrMut { pointee });
545 inner.ptr_mut_map.insert(pointee, interned);
546
547 interned
548 }
549
550 pub fn get_struct_by_name(&self, name: Spur) -> Option<InternedType> {
553 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
554 inner.struct_by_name.get(&name).copied()
555 }
556
557 pub fn get_enum_by_name(&self, name: Spur) -> Option<InternedType> {
559 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
560 inner.enum_by_name.get(&name).copied()
561 }
562
563 pub fn get_array(&self, element: InternedType, len: u64) -> Option<InternedType> {
565 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
566 inner.array_map.get(&(element, len)).copied()
567 }
568
569 pub fn get(&self, ty: InternedType) -> Option<TypeData> {
577 if ty.is_primitive() {
578 return None;
579 }
580
581 let pool_index = ty.pool_index().expect("non-primitive must have pool index");
582 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
583 Some(inner.types[pool_index as usize].clone())
584 }
585
586 pub fn is_struct(&self, ty: InternedType) -> bool {
588 if ty.is_primitive() {
589 return false;
590 }
591 matches!(self.get(ty), Some(TypeData::Struct(_)))
592 }
593
594 pub fn is_enum(&self, ty: InternedType) -> bool {
596 if ty.is_primitive() {
597 return false;
598 }
599 matches!(self.get(ty), Some(TypeData::Enum(_)))
600 }
601
602 pub fn is_array(&self, ty: InternedType) -> bool {
604 if ty.is_primitive() {
605 return false;
606 }
607 matches!(self.get(ty), Some(TypeData::Array { .. }))
608 }
609
610 pub fn get_struct_def(&self, ty: InternedType) -> Option<StructDef> {
612 match self.get(ty)? {
613 TypeData::Struct(data) => Some(data.def),
614 _ => None,
615 }
616 }
617
618 pub fn get_enum_def(&self, ty: InternedType) -> Option<EnumDef> {
620 match self.get(ty)? {
621 TypeData::Enum(data) => Some(data.def),
622 _ => None,
623 }
624 }
625
626 pub fn get_array_info(&self, ty: InternedType) -> Option<(InternedType, u64)> {
628 match self.get(ty)? {
629 TypeData::Array { element, len } => Some((element, len)),
630 _ => None,
631 }
632 }
633
634 pub fn struct_def(&self, struct_id: StructId) -> StructDef {
650 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
651 let pool_index = struct_id.0 as usize;
652 match &inner.types[pool_index] {
653 TypeData::Struct(data) => data.def.clone(),
654 other => panic!(
655 "Expected struct at pool index {}, got {:?}",
656 pool_index, other
657 ),
658 }
659 }
660
661 pub fn enum_def(&self, enum_id: EnumId) -> EnumDef {
670 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
671 let pool_index = enum_id.0 as usize;
672 match &inner.types[pool_index] {
673 TypeData::Enum(data) => data.def.clone(),
674 other => panic!(
675 "Expected enum at pool index {}, got {:?}",
676 pool_index, other
677 ),
678 }
679 }
680
681 pub fn update_struct_def(&self, struct_id: StructId, new_def: StructDef) {
690 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
691 let pool_index = struct_id.0 as usize;
692 match &mut inner.types[pool_index] {
693 TypeData::Struct(data) => data.def = new_def,
694 other => panic!(
695 "Expected struct at pool index {}, got {:?}",
696 pool_index, other
697 ),
698 }
699 }
700
701 pub fn update_enum_def(&self, enum_id: EnumId, new_def: EnumDef) {
710 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
711 let pool_index = enum_id.0 as usize;
712 match &mut inner.types[pool_index] {
713 TypeData::Enum(data) => data.def = new_def,
714 other => panic!(
715 "Expected enum at pool index {}, got {:?}",
716 pool_index, other
717 ),
718 }
719 }
720
721 #[inline]
725 pub fn struct_id_to_interned(&self, struct_id: StructId) -> InternedType {
726 InternedType::from_pool_index(struct_id.0)
727 }
728
729 #[inline]
733 pub fn enum_id_to_interned(&self, enum_id: EnumId) -> InternedType {
734 InternedType::from_pool_index(enum_id.0)
735 }
736
737 pub fn array_def(&self, array_id: ArrayTypeId) -> (Type, u64) {
751 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
752 let pool_index = array_id.0 as usize;
753 match &inner.types[pool_index] {
754 TypeData::Array { element, len } => {
755 let element_type = Self::interned_to_type_recursive(*element, &inner);
757 (element_type, *len)
758 }
759 other => panic!(
760 "Expected array at pool index {}, got {:?}",
761 pool_index, other
762 ),
763 }
764 }
765
766 pub fn intern_array_from_type(&self, element_type: Type, len: u64) -> ArrayTypeId {
775 let element_interned = Self::type_to_interned_recursive(element_type);
776 let array_interned = self.intern_array(element_interned, len);
777 ArrayTypeId::from_pool_index(
778 array_interned
779 .pool_index()
780 .expect("array must have pool index"),
781 )
782 }
783
784 pub fn get_array_by_type(&self, element_type: Type, len: u64) -> Option<ArrayTypeId> {
788 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
789 let element_interned = Self::type_to_interned_recursive(element_type);
790 let array_interned = inner.array_map.get(&(element_interned, len))?;
791 Some(ArrayTypeId::from_pool_index(
792 array_interned
793 .pool_index()
794 .expect("array must have pool index"),
795 ))
796 }
797
798 pub fn intern_ptr_const_from_type(&self, pointee_type: Type) -> PtrConstTypeId {
804 let pointee_interned = Self::type_to_interned_recursive(pointee_type);
805 let ptr_interned = self.intern_ptr_const(pointee_interned);
806 PtrConstTypeId::from_pool_index(
807 ptr_interned
808 .pool_index()
809 .expect("ptr const must have pool index"),
810 )
811 }
812
813 pub fn intern_ptr_mut_from_type(&self, pointee_type: Type) -> PtrMutTypeId {
819 let pointee_interned = Self::type_to_interned_recursive(pointee_type);
820 let ptr_interned = self.intern_ptr_mut(pointee_interned);
821 PtrMutTypeId::from_pool_index(
822 ptr_interned
823 .pool_index()
824 .expect("ptr mut must have pool index"),
825 )
826 }
827
828 pub fn ptr_const_def(&self, ptr_id: PtrConstTypeId) -> Type {
830 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
831 let pool_index = ptr_id.0 as usize;
832 match &inner.types[pool_index] {
833 TypeData::PtrConst { pointee } => Self::interned_to_type_recursive(*pointee, &inner),
834 other => panic!(
835 "Expected ptr const at pool index {}, got {:?}",
836 pool_index, other
837 ),
838 }
839 }
840
841 pub fn ptr_mut_def(&self, ptr_id: PtrMutTypeId) -> Type {
843 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
844 let pool_index = ptr_id.0 as usize;
845 match &inner.types[pool_index] {
846 TypeData::PtrMut { pointee } => Self::interned_to_type_recursive(*pointee, &inner),
847 other => panic!(
848 "Expected ptr mut at pool index {}, got {:?}",
849 pool_index, other
850 ),
851 }
852 }
853
854 fn interned_to_type_recursive(ty: InternedType, inner: &TypeInternPoolInner) -> Type {
858 if ty.is_primitive() {
859 return match ty.0 {
860 0 => Type::I8,
861 1 => Type::I16,
862 2 => Type::I32,
863 3 => Type::I64,
864 4 => Type::U8,
865 5 => Type::U16,
866 6 => Type::U32,
867 7 => Type::U64,
868 8 => Type::ISIZE,
869 9 => Type::USIZE,
870 10 => Type::F16,
871 11 => Type::F32,
872 12 => Type::F64,
873 13 => Type::BOOL,
874 14 => Type::UNIT,
875 15 => Type::NEVER,
876 16 => Type::ERROR,
877 _ => panic!("Unknown primitive index: {}", ty.0),
878 };
879 }
880
881 let pool_index = ty.pool_index().expect("non-primitive must have pool index");
882 match &inner.types[pool_index as usize] {
883 TypeData::Struct(_) => Type::new_struct(StructId::from_pool_index(pool_index)),
884 TypeData::Enum(_) => Type::new_enum(EnumId::from_pool_index(pool_index)),
885 TypeData::Array { .. } => Type::new_array(ArrayTypeId::from_pool_index(pool_index)),
886 TypeData::PtrConst { .. } => {
887 Type::new_ptr_const(PtrConstTypeId::from_pool_index(pool_index))
888 }
889 TypeData::PtrMut { .. } => Type::new_ptr_mut(PtrMutTypeId::from_pool_index(pool_index)),
890 }
891 }
892
893 fn type_to_interned_recursive(ty: Type) -> InternedType {
898 match ty.kind() {
899 TypeKind::I8 => InternedType::I8,
900 TypeKind::I16 => InternedType::I16,
901 TypeKind::I32 => InternedType::I32,
902 TypeKind::I64 => InternedType::I64,
903 TypeKind::U8 => InternedType::U8,
904 TypeKind::U16 => InternedType::U16,
905 TypeKind::U32 => InternedType::U32,
906 TypeKind::U64 => InternedType::U64,
907 TypeKind::Isize => InternedType::ISIZE,
908 TypeKind::Usize => InternedType::USIZE,
909 TypeKind::F16 => InternedType::F16,
910 TypeKind::F32 => InternedType::F32,
911 TypeKind::F64 => InternedType::F64,
912 TypeKind::Bool => InternedType::BOOL,
913 TypeKind::Unit => InternedType::UNIT,
914 TypeKind::Never => InternedType::NEVER,
915 TypeKind::Error => InternedType::ERROR,
916 TypeKind::Struct(id) => InternedType::from_pool_index(id.pool_index()),
917 TypeKind::Enum(id) => InternedType::from_pool_index(id.pool_index()),
918 TypeKind::Array(id) => InternedType::from_pool_index(id.pool_index()),
919 TypeKind::PtrConst(id) => InternedType::from_pool_index(id.pool_index()),
920 TypeKind::PtrMut(id) => InternedType::from_pool_index(id.pool_index()),
921 TypeKind::Module(_) => panic!("Cannot intern module types"),
922 TypeKind::ComptimeType => panic!("Cannot intern comptime types"),
923 TypeKind::ComptimeStr => panic!("Cannot intern comptime_str types"),
924 TypeKind::ComptimeInt => panic!("Cannot intern comptime_int types"),
925 }
926 }
927
928 #[inline]
932 pub fn array_id_to_interned(&self, array_id: ArrayTypeId) -> InternedType {
933 InternedType::from_pool_index(array_id.0)
934 }
935
936 pub fn all_struct_ids(&self) -> Vec<StructId> {
941 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
942 inner
943 .struct_by_name
944 .values()
945 .map(|interned| {
946 let pool_index = interned.pool_index().expect("struct must have pool index");
947 StructId::from_pool_index(pool_index)
948 })
949 .collect()
950 }
951
952 pub fn all_enum_ids(&self) -> Vec<EnumId> {
957 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
958 inner
959 .enum_by_name
960 .values()
961 .map(|interned| {
962 let pool_index = interned.pool_index().expect("enum must have pool index");
963 EnumId::from_pool_index(pool_index)
964 })
965 .collect()
966 }
967
968 pub fn all_array_ids(&self) -> Vec<ArrayTypeId> {
973 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
974 inner
975 .types
976 .iter()
977 .enumerate()
978 .filter_map(|(idx, data)| match data {
979 TypeData::Array { .. } => Some(ArrayTypeId(idx as u32)),
980 _ => None,
981 })
982 .collect()
983 }
984
985 pub fn len(&self) -> usize {
987 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
988 inner.types.len()
989 }
990
991 pub fn is_empty(&self) -> bool {
993 self.len() == 0
994 }
995
996 pub fn stats(&self) -> TypeInternPoolStats {
998 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
999 let mut struct_count = 0;
1000 let mut enum_count = 0;
1001 let mut array_count = 0;
1002
1003 for data in &inner.types {
1004 match data {
1005 TypeData::Struct(_) => struct_count += 1,
1006 TypeData::Enum(_) => enum_count += 1,
1007 TypeData::Array { .. } => array_count += 1,
1008 TypeData::PtrConst { .. } | TypeData::PtrMut { .. } => {
1009 }
1011 }
1012 }
1013
1014 TypeInternPoolStats {
1015 struct_count,
1016 enum_count,
1017 array_count,
1018 total: inner.types.len(),
1019 }
1020 }
1021
1022 pub fn type_to_interned(&self, ty: Type) -> Option<InternedType> {
1037 match ty.kind() {
1038 TypeKind::I8 => Some(InternedType::I8),
1039 TypeKind::I16 => Some(InternedType::I16),
1040 TypeKind::I32 => Some(InternedType::I32),
1041 TypeKind::I64 => Some(InternedType::I64),
1042 TypeKind::U8 => Some(InternedType::U8),
1043 TypeKind::U16 => Some(InternedType::U16),
1044 TypeKind::U32 => Some(InternedType::U32),
1045 TypeKind::U64 => Some(InternedType::U64),
1046 TypeKind::Isize => Some(InternedType::ISIZE),
1047 TypeKind::Usize => Some(InternedType::USIZE),
1048 TypeKind::F16 => Some(InternedType::F16),
1049 TypeKind::F32 => Some(InternedType::F32),
1050 TypeKind::F64 => Some(InternedType::F64),
1051 TypeKind::Bool => Some(InternedType::BOOL),
1052 TypeKind::Unit => Some(InternedType::UNIT),
1053 TypeKind::Never => Some(InternedType::NEVER),
1054 TypeKind::Error => Some(InternedType::ERROR),
1055 TypeKind::Struct(_)
1059 | TypeKind::Enum(_)
1060 | TypeKind::Array(_)
1061 | TypeKind::PtrConst(_)
1062 | TypeKind::PtrMut(_)
1063 | TypeKind::Module(_) => None,
1064 TypeKind::ComptimeType | TypeKind::ComptimeStr | TypeKind::ComptimeInt => None,
1066 }
1067 }
1068
1069 pub fn interned_to_type(&self, ty: InternedType) -> Option<Type> {
1074 if !ty.is_primitive() {
1075 return None;
1076 }
1077
1078 Some(match ty.0 {
1079 0 => Type::I8,
1080 1 => Type::I16,
1081 2 => Type::I32,
1082 3 => Type::I64,
1083 4 => Type::U8,
1084 5 => Type::U16,
1085 6 => Type::U32,
1086 7 => Type::U64,
1087 8 => Type::ISIZE,
1088 9 => Type::USIZE,
1089 10 => Type::F16,
1090 11 => Type::F32,
1091 12 => Type::F64,
1092 13 => Type::BOOL,
1093 14 => Type::UNIT,
1094 15 => Type::NEVER,
1095 16 => Type::ERROR,
1096 _ => return None,
1097 })
1098 }
1099
1100 pub fn abi_slot_count(&self, ty: Type) -> u32 {
1107 match ty.kind() {
1108 TypeKind::Struct(id) => {
1109 let def = self.struct_def(id);
1110 def.fields.iter().map(|f| self.abi_slot_count(f.ty)).sum()
1111 }
1112 TypeKind::Array(id) => {
1113 let (elem, len) = self.array_def(id);
1114 self.abi_slot_count(elem) * len as u32
1115 }
1116 TypeKind::Unit
1117 | TypeKind::Never
1118 | TypeKind::ComptimeType
1119 | TypeKind::ComptimeStr
1120 | TypeKind::ComptimeInt
1121 | TypeKind::Module(_) => 0,
1122 _ => 1,
1123 }
1124 }
1125
1126 pub fn format_type_name(&self, ty: Type) -> String {
1130 match ty.kind() {
1131 TypeKind::I8 => "i8".to_string(),
1132 TypeKind::I16 => "i16".to_string(),
1133 TypeKind::I32 => "i32".to_string(),
1134 TypeKind::I64 => "i64".to_string(),
1135 TypeKind::U8 => "u8".to_string(),
1136 TypeKind::U16 => "u16".to_string(),
1137 TypeKind::U32 => "u32".to_string(),
1138 TypeKind::U64 => "u64".to_string(),
1139 TypeKind::Isize => "isize".to_string(),
1140 TypeKind::Usize => "usize".to_string(),
1141 TypeKind::F16 => "f16".to_string(),
1142 TypeKind::F32 => "f32".to_string(),
1143 TypeKind::F64 => "f64".to_string(),
1144 TypeKind::Bool => "bool".to_string(),
1145 TypeKind::Unit => "()".to_string(),
1146 TypeKind::Never => "!".to_string(),
1147 TypeKind::Error => "<error>".to_string(),
1148 TypeKind::ComptimeType => "type".to_string(),
1149 TypeKind::ComptimeStr => "comptime_str".to_string(),
1150 TypeKind::ComptimeInt => "comptime_int".to_string(),
1151 TypeKind::Struct(id) => self.struct_def(id).name.clone(),
1152 TypeKind::Enum(id) => self.enum_def(id).name.clone(),
1153 TypeKind::Array(id) => {
1154 let (elem, len) = self.array_def(id);
1155 format!("[{}; {}]", self.format_type_name(elem), len)
1156 }
1157 TypeKind::PtrConst(id) => {
1158 let pointee = self.ptr_const_def(id);
1159 format!("ptr const {}", self.format_type_name(pointee))
1160 }
1161 TypeKind::PtrMut(id) => {
1162 let pointee = self.ptr_mut_def(id);
1163 format!("ptr mut {}", self.format_type_name(pointee))
1164 }
1165 TypeKind::Module(_) => "<module>".to_string(),
1166 }
1167 }
1168}
1169
1170impl Default for TypeInternPool {
1171 fn default() -> Self {
1172 Self::new()
1173 }
1174}
1175
1176impl Clone for TypeInternPool {
1177 fn clone(&self) -> Self {
1182 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1183 Self {
1184 inner: RwLock::new(TypeInternPoolInner {
1185 types: inner.types.clone(),
1186 array_map: inner.array_map.clone(),
1187 ptr_const_map: inner.ptr_const_map.clone(),
1188 ptr_mut_map: inner.ptr_mut_map.clone(),
1189 struct_by_name: inner.struct_by_name.clone(),
1190 enum_by_name: inner.enum_by_name.clone(),
1191 }),
1192 }
1193 }
1194}
1195
1196#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1198pub struct TypeInternPoolStats {
1199 pub struct_count: usize,
1200 pub enum_count: usize,
1201 pub array_count: usize,
1202 pub total: usize,
1203}
1204
1205#[cfg(test)]
1206mod tests {
1207 use super::*;
1208 use crate::types::EnumVariantDef;
1209 use lasso::ThreadedRodeo;
1210
1211 #[test]
1216 fn test_interned_type_primitives() {
1217 assert!(InternedType::I8.is_primitive());
1218 assert!(InternedType::I16.is_primitive());
1219 assert!(InternedType::I32.is_primitive());
1220 assert!(InternedType::I64.is_primitive());
1221 assert!(InternedType::U8.is_primitive());
1222 assert!(InternedType::U16.is_primitive());
1223 assert!(InternedType::U32.is_primitive());
1224 assert!(InternedType::U64.is_primitive());
1225 assert!(InternedType::BOOL.is_primitive());
1226 assert!(InternedType::UNIT.is_primitive());
1227 assert!(InternedType::NEVER.is_primitive());
1228 assert!(InternedType::ERROR.is_primitive());
1229 }
1230
1231 #[test]
1232 fn test_interned_type_indices() {
1233 assert_eq!(InternedType::I8.index(), 0);
1234 assert_eq!(InternedType::I16.index(), 1);
1235 assert_eq!(InternedType::I32.index(), 2);
1236 assert_eq!(InternedType::I64.index(), 3);
1237 assert_eq!(InternedType::U8.index(), 4);
1238 assert_eq!(InternedType::ISIZE.index(), 8);
1239 assert_eq!(InternedType::USIZE.index(), 9);
1240 assert_eq!(InternedType::F16.index(), 10);
1241 assert_eq!(InternedType::F32.index(), 11);
1242 assert_eq!(InternedType::F64.index(), 12);
1243 assert_eq!(InternedType::BOOL.index(), 13);
1244 assert_eq!(InternedType::UNIT.index(), 14);
1245 }
1246
1247 #[test]
1248 fn test_interned_type_pool_index() {
1249 assert_eq!(InternedType::I32.pool_index(), None);
1251 assert_eq!(InternedType::BOOL.pool_index(), None);
1252
1253 let composite = InternedType::from_pool_index(0);
1255 assert_eq!(composite.pool_index(), Some(0));
1256 assert!(!composite.is_primitive());
1257
1258 let composite2 = InternedType::from_pool_index(42);
1259 assert_eq!(composite2.pool_index(), Some(42));
1260 }
1261
1262 #[test]
1263 fn test_interned_type_equality() {
1264 assert_eq!(InternedType::I32, InternedType::I32);
1265 assert_ne!(InternedType::I32, InternedType::I64);
1266 assert_ne!(InternedType::I32, InternedType::from_pool_index(0));
1267 }
1268
1269 #[test]
1270 fn test_interned_type_debug() {
1271 let i32_str = format!("{:?}", InternedType::I32);
1272 assert!(i32_str.contains("i32"));
1273
1274 let composite_str = format!("{:?}", InternedType::from_pool_index(5));
1275 assert!(composite_str.contains("pool:5"));
1276 }
1277
1278 #[test]
1283 fn test_pool_new() {
1284 let pool = TypeInternPool::new();
1285 assert!(pool.is_empty());
1286 assert_eq!(pool.len(), 0);
1287 }
1288
1289 #[test]
1290 fn test_pool_register_struct() {
1291 let pool = TypeInternPool::new();
1292 let interner = ThreadedRodeo::default();
1293 let name = interner.get_or_intern("Point");
1294
1295 let def = StructDef {
1296 name: "Point".to_string(),
1297 fields: vec![],
1298 is_copy: false,
1299 is_handle: false,
1300 is_linear: false,
1301 destructor: None,
1302 is_builtin: false,
1303 is_pub: false,
1304 file_id: gruel_span::FileId::DEFAULT,
1305 };
1306
1307 let (struct_id, is_new) = pool.register_struct(name, def.clone());
1308 assert!(is_new);
1309 assert_eq!(struct_id.pool_index(), 0); assert_eq!(pool.len(), 1);
1311
1312 let (struct_id2, is_new2) = pool.register_struct(name, def);
1314 assert!(!is_new2);
1315 assert_eq!(struct_id, struct_id2);
1316 assert_eq!(pool.len(), 1); }
1318
1319 #[test]
1320 fn test_pool_register_enum() {
1321 let pool = TypeInternPool::new();
1322 let interner = ThreadedRodeo::default();
1323 let name = interner.get_or_intern("Color");
1324
1325 let def = EnumDef {
1326 name: "Color".to_string(),
1327 variants: vec![
1328 EnumVariantDef::unit("Red"),
1329 EnumVariantDef::unit("Green"),
1330 EnumVariantDef::unit("Blue"),
1331 ],
1332 is_pub: false,
1333 file_id: gruel_span::FileId::DEFAULT,
1334 };
1335
1336 let (enum_id, is_new) = pool.register_enum(name, def.clone());
1337 assert!(is_new);
1338 assert_eq!(enum_id.pool_index(), 0); assert_eq!(pool.len(), 1);
1340
1341 let (enum_id2, is_new2) = pool.register_enum(name, def);
1343 assert!(!is_new2);
1344 assert_eq!(enum_id, enum_id2);
1345 }
1346
1347 #[test]
1348 fn test_pool_intern_array() {
1349 let pool = TypeInternPool::new();
1350
1351 let arr1 = pool.intern_array(InternedType::I32, 5);
1353 assert!(!arr1.is_primitive());
1354 assert_eq!(pool.len(), 1);
1355
1356 let arr2 = pool.intern_array(InternedType::I32, 5);
1358 assert_eq!(arr1, arr2);
1359 assert_eq!(pool.len(), 1);
1360
1361 let arr3 = pool.intern_array(InternedType::I32, 10);
1363 assert_ne!(arr1, arr3);
1364 assert_eq!(pool.len(), 2);
1365
1366 let arr4 = pool.intern_array(InternedType::I64, 5);
1368 assert_ne!(arr1, arr4);
1369 assert_eq!(pool.len(), 3);
1370 }
1371
1372 #[test]
1373 fn test_pool_get_struct_by_name() {
1374 let pool = TypeInternPool::new();
1375 let interner = ThreadedRodeo::default();
1376 let name = interner.get_or_intern("Point");
1377
1378 assert!(pool.get_struct_by_name(name).is_none());
1379
1380 let def = StructDef {
1381 name: "Point".to_string(),
1382 fields: vec![],
1383 is_copy: false,
1384 is_handle: false,
1385 is_linear: false,
1386 destructor: None,
1387 is_builtin: false,
1388 is_pub: false,
1389 file_id: gruel_span::FileId::DEFAULT,
1390 };
1391
1392 let (struct_id, _) = pool.register_struct(name, def);
1393 let expected = pool.struct_id_to_interned(struct_id);
1395 assert_eq!(pool.get_struct_by_name(name), Some(expected));
1396 }
1397
1398 #[test]
1399 fn test_pool_get_enum_by_name() {
1400 let pool = TypeInternPool::new();
1401 let interner = ThreadedRodeo::default();
1402 let name = interner.get_or_intern("Status");
1403
1404 assert!(pool.get_enum_by_name(name).is_none());
1405
1406 let def = EnumDef {
1407 name: "Status".to_string(),
1408 variants: vec![
1409 EnumVariantDef::unit("Active"),
1410 EnumVariantDef::unit("Inactive"),
1411 ],
1412 is_pub: false,
1413 file_id: gruel_span::FileId::DEFAULT,
1414 };
1415
1416 let (enum_id, _) = pool.register_enum(name, def);
1417 let expected = pool.enum_id_to_interned(enum_id);
1419 assert_eq!(pool.get_enum_by_name(name), Some(expected));
1420 }
1421
1422 #[test]
1423 fn test_pool_get_array() {
1424 let pool = TypeInternPool::new();
1425
1426 assert!(pool.get_array(InternedType::I32, 5).is_none());
1427
1428 let arr = pool.intern_array(InternedType::I32, 5);
1429 assert_eq!(pool.get_array(InternedType::I32, 5), Some(arr));
1430 assert!(pool.get_array(InternedType::I32, 10).is_none());
1431 }
1432
1433 #[test]
1434 fn test_pool_get_type_data() {
1435 let pool = TypeInternPool::new();
1436 let interner = ThreadedRodeo::default();
1437
1438 assert!(pool.get(InternedType::I32).is_none());
1440
1441 let struct_name = interner.get_or_intern("Point");
1443 let struct_def = StructDef {
1444 name: "Point".to_string(),
1445 fields: vec![],
1446 is_copy: false,
1447 is_handle: false,
1448 is_linear: false,
1449 destructor: None,
1450 is_builtin: false,
1451 is_pub: false,
1452 file_id: gruel_span::FileId::DEFAULT,
1453 };
1454 let (struct_id, _) = pool.register_struct(struct_name, struct_def);
1455 let struct_ty = pool.struct_id_to_interned(struct_id);
1456
1457 let data = pool.get(struct_ty).expect("should get struct data");
1459 assert!(matches!(data, TypeData::Struct(_)));
1460
1461 let arr_ty = pool.intern_array(InternedType::I32, 10);
1463 let arr_data = pool.get(arr_ty).expect("should get array data");
1464 match arr_data {
1465 TypeData::Array { element, len } => {
1466 assert_eq!(element, InternedType::I32);
1467 assert_eq!(len, 10);
1468 }
1469 _ => panic!("expected array data"),
1470 }
1471 }
1472
1473 #[test]
1474 fn test_pool_type_checks() {
1475 let pool = TypeInternPool::new();
1476 let interner = ThreadedRodeo::default();
1477
1478 let struct_name = interner.get_or_intern("Point");
1479 let struct_def = StructDef {
1480 name: "Point".to_string(),
1481 fields: vec![],
1482 is_copy: false,
1483 is_handle: false,
1484 is_linear: false,
1485 destructor: None,
1486 is_builtin: false,
1487 is_pub: false,
1488 file_id: gruel_span::FileId::DEFAULT,
1489 };
1490 let (struct_id, _) = pool.register_struct(struct_name, struct_def);
1491 let struct_ty = pool.struct_id_to_interned(struct_id);
1492
1493 let enum_name = interner.get_or_intern("Color");
1494 let enum_def = EnumDef {
1495 name: "Color".to_string(),
1496 variants: vec![EnumVariantDef::unit("Red")],
1497 is_pub: false,
1498 file_id: gruel_span::FileId::DEFAULT,
1499 };
1500 let (enum_id, _) = pool.register_enum(enum_name, enum_def);
1501 let enum_ty = pool.enum_id_to_interned(enum_id);
1502
1503 let array_ty = pool.intern_array(InternedType::I32, 5);
1504
1505 assert!(pool.is_struct(struct_ty));
1507 assert!(!pool.is_struct(enum_ty));
1508 assert!(!pool.is_struct(array_ty));
1509 assert!(!pool.is_struct(InternedType::I32));
1510
1511 assert!(!pool.is_enum(struct_ty));
1513 assert!(pool.is_enum(enum_ty));
1514 assert!(!pool.is_enum(array_ty));
1515 assert!(!pool.is_enum(InternedType::I32));
1516
1517 assert!(!pool.is_array(struct_ty));
1519 assert!(!pool.is_array(enum_ty));
1520 assert!(pool.is_array(array_ty));
1521 assert!(!pool.is_array(InternedType::I32));
1522 }
1523
1524 #[test]
1525 fn test_pool_get_struct_def() {
1526 let pool = TypeInternPool::new();
1527 let interner = ThreadedRodeo::default();
1528
1529 let name = interner.get_or_intern("Point");
1530 let def = StructDef {
1531 name: "Point".to_string(),
1532 fields: vec![],
1533 is_copy: true,
1534 is_handle: false,
1535 is_linear: false,
1536 destructor: None,
1537 is_builtin: false,
1538 is_pub: false,
1539 file_id: gruel_span::FileId::DEFAULT,
1540 };
1541 let (struct_id, _) = pool.register_struct(name, def.clone());
1542
1543 let retrieved = pool.struct_def(struct_id);
1545 assert_eq!(retrieved.name, def.name);
1546 assert_eq!(retrieved.is_copy, def.is_copy);
1547
1548 let interned = pool.struct_id_to_interned(struct_id);
1550 let retrieved2 = pool
1551 .get_struct_def(interned)
1552 .expect("should get struct def");
1553 assert_eq!(retrieved2.name, def.name);
1554
1555 let array_ty = pool.intern_array(InternedType::I32, 5);
1557 assert!(pool.get_struct_def(array_ty).is_none());
1558 assert!(pool.get_struct_def(InternedType::I32).is_none());
1559 }
1560
1561 #[test]
1562 fn test_pool_get_enum_def() {
1563 let pool = TypeInternPool::new();
1564 let interner = ThreadedRodeo::default();
1565
1566 let name = interner.get_or_intern("Status");
1567 let def = EnumDef {
1568 name: "Status".to_string(),
1569 variants: vec![EnumVariantDef::unit("A"), EnumVariantDef::unit("B")],
1570 is_pub: false,
1571 file_id: gruel_span::FileId::DEFAULT,
1572 };
1573 let (enum_id, _) = pool.register_enum(name, def.clone());
1574
1575 let retrieved = pool.enum_def(enum_id);
1577 assert_eq!(retrieved.name, def.name);
1578 assert_eq!(retrieved.variants.len(), 2);
1579
1580 let interned = pool.enum_id_to_interned(enum_id);
1582 let retrieved2 = pool.get_enum_def(interned).expect("should get enum def");
1583 assert_eq!(retrieved2.name, def.name);
1584
1585 let array_ty = pool.intern_array(InternedType::I32, 5);
1587 assert!(pool.get_enum_def(array_ty).is_none());
1588 assert!(pool.get_enum_def(InternedType::I32).is_none());
1589 }
1590
1591 #[test]
1592 fn test_pool_get_array_info() {
1593 let pool = TypeInternPool::new();
1594
1595 let array_ty = pool.intern_array(InternedType::I64, 100);
1596 let (element, len) = pool
1597 .get_array_info(array_ty)
1598 .expect("should get array info");
1599 assert_eq!(element, InternedType::I64);
1600 assert_eq!(len, 100);
1601
1602 let interner = ThreadedRodeo::default();
1604 let name = interner.get_or_intern("X");
1605 let def = StructDef {
1606 name: "X".to_string(),
1607 fields: vec![],
1608 is_copy: false,
1609 is_handle: false,
1610 is_linear: false,
1611 destructor: None,
1612 is_builtin: false,
1613 is_pub: false,
1614 file_id: gruel_span::FileId::DEFAULT,
1615 };
1616 let (struct_id, _) = pool.register_struct(name, def);
1617 let struct_ty = pool.struct_id_to_interned(struct_id);
1618 assert!(pool.get_array_info(struct_ty).is_none());
1619 assert!(pool.get_array_info(InternedType::I32).is_none());
1620 }
1621
1622 #[test]
1623 fn test_pool_stats() {
1624 let pool = TypeInternPool::new();
1625 let interner = ThreadedRodeo::default();
1626
1627 let stats = pool.stats();
1628 assert_eq!(stats.struct_count, 0);
1629 assert_eq!(stats.enum_count, 0);
1630 assert_eq!(stats.array_count, 0);
1631 assert_eq!(stats.total, 0);
1632
1633 let s1 = interner.get_or_intern("S1");
1635 let s2 = interner.get_or_intern("S2");
1636 let e1 = interner.get_or_intern("E1");
1637
1638 let def = StructDef {
1639 name: "S1".to_string(),
1640 fields: vec![],
1641 is_copy: false,
1642 is_handle: false,
1643 is_linear: false,
1644 destructor: None,
1645 is_builtin: false,
1646 is_pub: false,
1647 file_id: gruel_span::FileId::DEFAULT,
1648 };
1649 pool.register_struct(s1, def.clone());
1650 pool.register_struct(
1651 s2,
1652 StructDef {
1653 name: "S2".to_string(),
1654 ..def
1655 },
1656 );
1657
1658 pool.register_enum(
1659 e1,
1660 EnumDef {
1661 name: "E1".to_string(),
1662 variants: vec![],
1663 is_pub: false,
1664 file_id: gruel_span::FileId::DEFAULT,
1665 },
1666 );
1667
1668 pool.intern_array(InternedType::I32, 5);
1669 pool.intern_array(InternedType::I32, 10);
1670 pool.intern_array(InternedType::BOOL, 3);
1671
1672 let stats = pool.stats();
1673 assert_eq!(stats.struct_count, 2);
1674 assert_eq!(stats.enum_count, 1);
1675 assert_eq!(stats.array_count, 3);
1676 assert_eq!(stats.total, 6);
1677 }
1678
1679 #[test]
1680 fn test_pool_nested_arrays() {
1681 let pool = TypeInternPool::new();
1682
1683 let inner = pool.intern_array(InternedType::I32, 3);
1685
1686 let outer = pool.intern_array(inner, 4);
1688
1689 let (outer_elem, outer_len) = pool.get_array_info(outer).expect("outer array info");
1691 assert_eq!(outer_elem, inner);
1692 assert_eq!(outer_len, 4);
1693
1694 let (inner_elem, inner_len) = pool.get_array_info(inner).expect("inner array info");
1695 assert_eq!(inner_elem, InternedType::I32);
1696 assert_eq!(inner_len, 3);
1697 }
1698
1699 #[test]
1700 fn test_pool_type_to_interned() {
1701 let pool = TypeInternPool::new();
1702
1703 assert_eq!(pool.type_to_interned(Type::I8), Some(InternedType::I8));
1705 assert_eq!(pool.type_to_interned(Type::I16), Some(InternedType::I16));
1706 assert_eq!(pool.type_to_interned(Type::I32), Some(InternedType::I32));
1707 assert_eq!(pool.type_to_interned(Type::I64), Some(InternedType::I64));
1708 assert_eq!(pool.type_to_interned(Type::U8), Some(InternedType::U8));
1709 assert_eq!(pool.type_to_interned(Type::U16), Some(InternedType::U16));
1710 assert_eq!(pool.type_to_interned(Type::U32), Some(InternedType::U32));
1711 assert_eq!(pool.type_to_interned(Type::U64), Some(InternedType::U64));
1712 assert_eq!(pool.type_to_interned(Type::BOOL), Some(InternedType::BOOL));
1713 assert_eq!(pool.type_to_interned(Type::UNIT), Some(InternedType::UNIT));
1714 assert_eq!(
1715 pool.type_to_interned(Type::NEVER),
1716 Some(InternedType::NEVER)
1717 );
1718 assert_eq!(
1719 pool.type_to_interned(Type::ERROR),
1720 Some(InternedType::ERROR)
1721 );
1722
1723 assert!(
1725 pool.type_to_interned(Type::new_struct(crate::types::StructId(0)))
1726 .is_none()
1727 );
1728 assert!(
1729 pool.type_to_interned(Type::new_enum(crate::types::EnumId(0)))
1730 .is_none()
1731 );
1732 assert!(
1733 pool.type_to_interned(Type::new_array(crate::types::ArrayTypeId(0)))
1734 .is_none()
1735 );
1736 }
1737
1738 #[test]
1739 fn test_pool_interned_to_type() {
1740 let pool = TypeInternPool::new();
1741
1742 assert_eq!(pool.interned_to_type(InternedType::I8), Some(Type::I8));
1744 assert_eq!(pool.interned_to_type(InternedType::I16), Some(Type::I16));
1745 assert_eq!(pool.interned_to_type(InternedType::I32), Some(Type::I32));
1746 assert_eq!(pool.interned_to_type(InternedType::I64), Some(Type::I64));
1747 assert_eq!(pool.interned_to_type(InternedType::U8), Some(Type::U8));
1748 assert_eq!(pool.interned_to_type(InternedType::U16), Some(Type::U16));
1749 assert_eq!(pool.interned_to_type(InternedType::U32), Some(Type::U32));
1750 assert_eq!(pool.interned_to_type(InternedType::U64), Some(Type::U64));
1751 assert_eq!(pool.interned_to_type(InternedType::BOOL), Some(Type::BOOL));
1752 assert_eq!(pool.interned_to_type(InternedType::UNIT), Some(Type::UNIT));
1753 assert_eq!(
1754 pool.interned_to_type(InternedType::NEVER),
1755 Some(Type::NEVER)
1756 );
1757 assert_eq!(
1758 pool.interned_to_type(InternedType::ERROR),
1759 Some(Type::ERROR)
1760 );
1761
1762 assert!(
1764 pool.interned_to_type(InternedType::from_pool_index(0))
1765 .is_none()
1766 );
1767 }
1768
1769 #[test]
1774 fn test_pool_concurrent_access() {
1775 use std::sync::Arc;
1776 use std::thread;
1777
1778 let pool = Arc::new(TypeInternPool::new());
1779 let interner = Arc::new(ThreadedRodeo::default());
1780
1781 let names: Vec<Spur> = (0..100)
1783 .map(|i| interner.get_or_intern(format!("Type{}", i)))
1784 .collect();
1785
1786 let handles: Vec<_> = (0..10)
1787 .map(|thread_id| {
1788 let pool = Arc::clone(&pool);
1789 let names = names.clone();
1790 thread::spawn(move || {
1791 for i in 0..10 {
1793 let idx = thread_id * 10 + i;
1794 let name = names[idx];
1795 let def = StructDef {
1796 name: format!("Type{}", idx),
1797 fields: vec![],
1798 is_copy: false,
1799 is_handle: false,
1800 is_linear: false,
1801 destructor: None,
1802 is_builtin: false,
1803 is_pub: false,
1804 file_id: gruel_span::FileId::DEFAULT,
1805 };
1806 pool.register_struct(name, def);
1807 }
1808 })
1809 })
1810 .collect();
1811
1812 for handle in handles {
1813 handle.join().expect("thread panicked");
1814 }
1815
1816 assert_eq!(pool.len(), 100);
1818
1819 for name in &names {
1821 assert!(pool.get_struct_by_name(*name).is_some());
1822 }
1823 }
1824
1825 #[test]
1826 fn test_pool_concurrent_array_interning() {
1827 use std::sync::Arc;
1828 use std::thread;
1829
1830 let pool = Arc::new(TypeInternPool::new());
1831
1832 let handles: Vec<_> = (0..10)
1834 .map(|_| {
1835 let pool = Arc::clone(&pool);
1836 thread::spawn(move || pool.intern_array(InternedType::I32, 42))
1837 })
1838 .collect();
1839
1840 let results: Vec<_> = handles
1841 .into_iter()
1842 .map(|h| h.join().expect("thread panicked"))
1843 .collect();
1844
1845 let first = results[0];
1847 for result in &results {
1848 assert_eq!(*result, first);
1849 }
1850
1851 assert_eq!(pool.stats().array_count, 1);
1853 }
1854
1855 #[test]
1860 fn test_pool_reserve_and_complete_struct() {
1861 let pool = TypeInternPool::new();
1862 let interner = ThreadedRodeo::default();
1863
1864 let struct_id = pool.reserve_struct_id();
1866 assert_eq!(struct_id.pool_index(), 0);
1867 assert_eq!(pool.len(), 1); let name_str = format!("__anon_struct_{}", struct_id.0);
1871 let name = interner.get_or_intern(&name_str);
1872
1873 let def = StructDef {
1874 name: name_str.clone(),
1875 fields: vec![],
1876 is_copy: false,
1877 is_handle: false,
1878 is_linear: false,
1879 destructor: None,
1880 is_builtin: false,
1881 is_pub: false,
1882 file_id: gruel_span::FileId::DEFAULT,
1883 };
1884
1885 pool.complete_struct_registration(struct_id, name, def);
1887
1888 assert_eq!(pool.len(), 1); assert!(pool.get_struct_by_name(name).is_some());
1891
1892 let retrieved = pool.struct_def(struct_id);
1894 assert_eq!(retrieved.name, name_str);
1895 }
1896
1897 #[test]
1898 fn test_pool_reserve_multiple_structs() {
1899 let pool = TypeInternPool::new();
1900 let interner = ThreadedRodeo::default();
1901
1902 let id1 = pool.reserve_struct_id();
1904 let id2 = pool.reserve_struct_id();
1905 let id3 = pool.reserve_struct_id();
1906
1907 assert_eq!(id1.pool_index(), 0);
1908 assert_eq!(id2.pool_index(), 1);
1909 assert_eq!(id3.pool_index(), 2);
1910 assert_eq!(pool.len(), 3);
1911
1912 for (i, id) in [(2, id3), (1, id2), (0, id1)] {
1914 let name_str = format!("__anon_struct_{}", i);
1915 let name = interner.get_or_intern(&name_str);
1916 let def = StructDef {
1917 name: name_str,
1918 fields: vec![],
1919 is_copy: false,
1920 is_handle: false,
1921 is_linear: false,
1922 destructor: None,
1923 is_builtin: false,
1924 is_pub: false,
1925 file_id: gruel_span::FileId::DEFAULT,
1926 };
1927 pool.complete_struct_registration(id, name, def);
1928 }
1929
1930 assert_eq!(pool.stats().struct_count, 3);
1932 }
1933
1934 fn assert_send_sync<T: Send + Sync>() {}
1936
1937 #[test]
1938 fn test_pool_is_send_sync() {
1939 assert_send_sync::<TypeInternPool>();
1940 }
1941}