1use rustc_hash::FxHashMap as HashMap;
39use std::sync::{PoisonError, RwLock};
40
41use gruel_builtins::Posture;
42use lasso::Spur;
43
44use crate::layout::Layout;
45use crate::types::{
46 ArrayTypeId, EnumDef, EnumId, MutRefTypeId, MutSliceTypeId, PtrConstTypeId, PtrMutTypeId,
47 RefTypeId, SliceTypeId, StructDef, StructId, Type, TypeKind, VecTypeId,
48};
49
50#[derive(Clone, Copy, PartialEq, Eq, Hash, Default, serde::Serialize, serde::Deserialize)]
77pub struct InternedType(u32);
78
79impl InternedType {
80 pub const I8: InternedType = InternedType(0);
82 pub const I16: InternedType = InternedType(1);
83 pub const I32: InternedType = InternedType(2);
84 pub const I64: InternedType = InternedType(3);
85 pub const U8: InternedType = InternedType(4);
86 pub const U16: InternedType = InternedType(5);
87 pub const U32: InternedType = InternedType(6);
88 pub const U64: InternedType = InternedType(7);
89 pub const ISIZE: InternedType = InternedType(8);
90 pub const USIZE: InternedType = InternedType(9);
91 pub const F16: InternedType = InternedType(10);
92 pub const F32: InternedType = InternedType(11);
93 pub const F64: InternedType = InternedType(12);
94 pub const BOOL: InternedType = InternedType(13);
95 pub const UNIT: InternedType = InternedType(14);
96 pub const NEVER: InternedType = InternedType(15);
97 pub const ERROR: InternedType = InternedType(16);
98 pub const CHAR: InternedType = InternedType(20);
100
101 pub const C_SCHAR: InternedType = InternedType(21);
104 pub const C_SHORT: InternedType = InternedType(22);
105 pub const C_INT: InternedType = InternedType(23);
106 pub const C_LONG: InternedType = InternedType(24);
107 pub const C_LONGLONG: InternedType = InternedType(25);
108 pub const C_UCHAR: InternedType = InternedType(26);
109 pub const C_USHORT: InternedType = InternedType(27);
110 pub const C_UINT: InternedType = InternedType(28);
111 pub const C_ULONG: InternedType = InternedType(29);
112 pub const C_ULONGLONG: InternedType = InternedType(30);
113 pub const C_FLOAT: InternedType = InternedType(31);
114 pub const C_DOUBLE: InternedType = InternedType(32);
115 pub const C_VOID: InternedType = InternedType(33);
116
117 const PRIMITIVE_COUNT: u32 = 34;
118
119 #[inline]
121 pub fn is_primitive(self) -> bool {
122 self.0 < Self::PRIMITIVE_COUNT
123 }
124
125 #[inline]
127 pub fn index(self) -> u32 {
128 self.0
129 }
130
131 #[inline]
138 pub fn from_raw(index: u32) -> Self {
139 InternedType(index)
140 }
141
142 #[inline]
146 fn from_pool_index(pool_index: u32) -> Self {
147 InternedType(pool_index + Self::PRIMITIVE_COUNT)
148 }
149
150 #[inline]
154 pub fn pool_index(self) -> Option<u32> {
155 if self.is_primitive() {
156 None
157 } else {
158 Some(self.0 - Self::PRIMITIVE_COUNT)
159 }
160 }
161}
162
163impl std::fmt::Debug for InternedType {
164 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165 if self.is_primitive() {
166 let name = match self.0 {
167 0 => "i8",
168 1 => "i16",
169 2 => "i32",
170 3 => "i64",
171 4 => "u8",
172 5 => "u16",
173 6 => "u32",
174 7 => "u64",
175 8 => "bool",
176 9 => "()",
177 10 => "!",
178 11 => "<error>",
179 _ => "<reserved>",
180 };
181 write!(f, "InternedType({name})")
182 } else {
183 write!(f, "InternedType(pool:{})", self.0 - Self::PRIMITIVE_COUNT)
184 }
185 }
186}
187
188#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
197pub enum TypeData {
198 Struct(StructData),
202
203 Enum(EnumData),
207
208 Array { element: InternedType, len: u64 },
213
214 PtrConst { pointee: InternedType },
218
219 PtrMut { pointee: InternedType },
223
224 Ref { referent: InternedType },
228
229 MutRef { referent: InternedType },
233
234 Slice { element: InternedType },
238
239 MutSlice { element: InternedType },
243
244 Vec { element: InternedType },
248}
249
250#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
255pub struct StructData {
256 pub name: Spur,
258 pub def: StructDef,
262}
263
264#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
269pub struct EnumData {
270 pub name: Spur,
272 pub def: EnumDef,
276}
277
278#[derive(Debug)]
310pub struct TypeInternPool {
311 inner: RwLock<TypeInternPoolInner>,
312}
313
314#[derive(serde::Serialize, serde::Deserialize)]
325struct TypeInternPoolWire {
326 types: Vec<TypeData>,
327}
328
329impl serde::Serialize for TypeInternPool {
330 fn serialize<S: serde::Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
331 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
332 let wire = TypeInternPoolWire {
333 types: inner.types.clone(),
334 };
335 wire.serialize(ser)
336 }
337}
338
339impl<'de> serde::Deserialize<'de> for TypeInternPool {
340 fn deserialize<D: serde::Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
341 let wire = TypeInternPoolWire::deserialize(de)?;
342 let mut inner = TypeInternPoolInner {
347 types: Vec::with_capacity(wire.types.len()),
348 array_map: HashMap::default(),
349 ptr_const_map: HashMap::default(),
350 ptr_mut_map: HashMap::default(),
351 ref_map: HashMap::default(),
352 mut_ref_map: HashMap::default(),
353 slice_map: HashMap::default(),
354 mut_slice_map: HashMap::default(),
355 vec_map: HashMap::default(),
356 struct_by_name: HashMap::default(),
357 enum_by_name: HashMap::default(),
358 layout_cache: HashMap::default(),
359 };
360 for data in wire.types {
361 let idx = InternedType(InternedType::PRIMITIVE_COUNT + inner.types.len() as u32);
364 match &data {
365 TypeData::Struct(s) => {
366 inner.struct_by_name.insert(s.name, idx);
367 }
368 TypeData::Enum(e) => {
369 inner.enum_by_name.insert(e.name, idx);
370 }
371 TypeData::Array { element, len } => {
372 inner.array_map.insert((*element, *len), idx);
373 }
374 TypeData::PtrConst { pointee } => {
375 inner.ptr_const_map.insert(*pointee, idx);
376 }
377 TypeData::PtrMut { pointee } => {
378 inner.ptr_mut_map.insert(*pointee, idx);
379 }
380 TypeData::Ref { referent } => {
381 inner.ref_map.insert(*referent, idx);
382 }
383 TypeData::MutRef { referent } => {
384 inner.mut_ref_map.insert(*referent, idx);
385 }
386 TypeData::Slice { element } => {
387 inner.slice_map.insert(*element, idx);
388 }
389 TypeData::MutSlice { element } => {
390 inner.mut_slice_map.insert(*element, idx);
391 }
392 TypeData::Vec { element } => {
393 inner.vec_map.insert(*element, idx);
394 }
395 }
396 inner.types.push(data);
397 }
398 Ok(Self {
399 inner: RwLock::new(inner),
400 })
401 }
402}
403
404#[derive(Debug)]
405struct TypeInternPoolInner {
406 types: Vec<TypeData>,
408
409 array_map: HashMap<(InternedType, u64), InternedType>,
411
412 ptr_const_map: HashMap<InternedType, InternedType>,
414
415 ptr_mut_map: HashMap<InternedType, InternedType>,
417
418 ref_map: HashMap<InternedType, InternedType>,
420
421 mut_ref_map: HashMap<InternedType, InternedType>,
423
424 slice_map: HashMap<InternedType, InternedType>,
426
427 mut_slice_map: HashMap<InternedType, InternedType>,
429
430 vec_map: HashMap<InternedType, InternedType>,
432
433 struct_by_name: HashMap<Spur, InternedType>,
435
436 enum_by_name: HashMap<Spur, InternedType>,
438
439 layout_cache: HashMap<Type, Layout>,
443}
444
445impl TypeInternPool {
446 pub fn clone_snapshot(&self) -> Self {
454 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
455 let mut new_inner = TypeInternPoolInner {
456 types: Vec::with_capacity(inner.types.len()),
457 array_map: HashMap::default(),
458 ptr_const_map: HashMap::default(),
459 ptr_mut_map: HashMap::default(),
460 ref_map: HashMap::default(),
461 mut_ref_map: HashMap::default(),
462 slice_map: HashMap::default(),
463 mut_slice_map: HashMap::default(),
464 vec_map: HashMap::default(),
465 struct_by_name: HashMap::default(),
466 enum_by_name: HashMap::default(),
467 layout_cache: HashMap::default(),
468 };
469 for data in &inner.types {
470 let idx = InternedType(InternedType::PRIMITIVE_COUNT + new_inner.types.len() as u32);
471 match data {
472 TypeData::Struct(s) => {
473 new_inner.struct_by_name.insert(s.name, idx);
474 }
475 TypeData::Enum(e) => {
476 new_inner.enum_by_name.insert(e.name, idx);
477 }
478 TypeData::Array { element, len } => {
479 new_inner.array_map.insert((*element, *len), idx);
480 }
481 TypeData::PtrConst { pointee } => {
482 new_inner.ptr_const_map.insert(*pointee, idx);
483 }
484 TypeData::PtrMut { pointee } => {
485 new_inner.ptr_mut_map.insert(*pointee, idx);
486 }
487 TypeData::Ref { referent } => {
488 new_inner.ref_map.insert(*referent, idx);
489 }
490 TypeData::MutRef { referent } => {
491 new_inner.mut_ref_map.insert(*referent, idx);
492 }
493 TypeData::Slice { element } => {
494 new_inner.slice_map.insert(*element, idx);
495 }
496 TypeData::MutSlice { element } => {
497 new_inner.mut_slice_map.insert(*element, idx);
498 }
499 TypeData::Vec { element } => {
500 new_inner.vec_map.insert(*element, idx);
501 }
502 }
503 new_inner.types.push(data.clone());
504 }
505 Self {
506 inner: RwLock::new(new_inner),
507 }
508 }
509
510 pub fn new() -> Self {
512 Self {
513 inner: RwLock::new(TypeInternPoolInner {
514 types: Vec::new(),
515 array_map: HashMap::default(),
516 ptr_const_map: HashMap::default(),
517 ptr_mut_map: HashMap::default(),
518 ref_map: HashMap::default(),
519 mut_ref_map: HashMap::default(),
520 slice_map: HashMap::default(),
521 mut_slice_map: HashMap::default(),
522 vec_map: HashMap::default(),
523 struct_by_name: HashMap::default(),
524 enum_by_name: HashMap::default(),
525 layout_cache: HashMap::default(),
526 }),
527 }
528 }
529
530 pub(crate) fn cached_layout(&self, ty: Type) -> Option<Layout> {
532 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
533 inner.layout_cache.get(&ty).cloned()
534 }
535
536 pub(crate) fn cache_layout(&self, ty: Type, layout: Layout) {
538 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
539 inner.layout_cache.insert(ty, layout);
540 }
541
542 pub fn register_struct(&self, name: Spur, def: StructDef) -> (StructId, bool) {
547 {
549 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
550 if let Some(&existing) = inner.struct_by_name.get(&name) {
551 let pool_index = existing.pool_index().expect("struct must have pool index");
553 return (StructId::from_pool_index(pool_index), false);
554 }
555 }
556
557 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
559
560 if let Some(&existing) = inner.struct_by_name.get(&name) {
562 let pool_index = existing.pool_index().expect("struct must have pool index");
563 return (StructId::from_pool_index(pool_index), false);
564 }
565
566 let pool_index = inner.types.len() as u32;
568 let interned = InternedType::from_pool_index(pool_index);
569
570 inner.types.push(TypeData::Struct(StructData { name, def }));
571 inner.struct_by_name.insert(name, interned);
572
573 (StructId::from_pool_index(pool_index), true)
574 }
575
576 pub fn reserve_struct_id(&self) -> StructId {
597 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
598
599 let pool_index = inner.types.len() as u32;
602
603 inner.types.push(TypeData::Struct(StructData {
606 name: Spur::default(),
607 def: StructDef {
608 name: String::new(),
609 fields: vec![],
610 posture: Posture::Affine,
611 is_clone: false,
612 thread_safety: gruel_builtins::ThreadSafety::Sync,
613 destructor: None,
614 is_builtin: false,
615 is_pub: false,
616 file_id: gruel_util::FileId::DEFAULT,
617 is_c_layout: false,
618 },
619 }));
620
621 StructId::from_pool_index(pool_index)
622 }
623
624 pub fn complete_struct_registration(&self, struct_id: StructId, name: Spur, def: StructDef) {
636 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
637 let pool_index = struct_id.0 as usize;
638
639 assert!(
641 pool_index < inner.types.len(),
642 "Invalid reserved struct ID: index {} out of bounds (len {})",
643 pool_index,
644 inner.types.len()
645 );
646
647 assert!(
649 !inner.struct_by_name.contains_key(&name),
650 "Struct with this name already exists"
651 );
652
653 inner.types[pool_index] = TypeData::Struct(StructData { name, def });
655
656 let interned = InternedType::from_pool_index(pool_index as u32);
658 inner.struct_by_name.insert(name, interned);
659 }
660
661 pub fn register_enum(&self, name: Spur, def: EnumDef) -> (EnumId, bool) {
666 {
668 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
669 if let Some(&existing) = inner.enum_by_name.get(&name) {
670 let pool_index = existing.pool_index().expect("enum must have pool index");
671 return (EnumId::from_pool_index(pool_index), false);
672 }
673 }
674
675 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
677
678 if let Some(&existing) = inner.enum_by_name.get(&name) {
680 let pool_index = existing.pool_index().expect("enum must have pool index");
681 return (EnumId::from_pool_index(pool_index), false);
682 }
683
684 let pool_index = inner.types.len() as u32;
686 let interned = InternedType::from_pool_index(pool_index);
687
688 inner.types.push(TypeData::Enum(EnumData { name, def }));
689 inner.enum_by_name.insert(name, interned);
690
691 (EnumId::from_pool_index(pool_index), true)
692 }
693
694 pub fn intern_array(&self, element: InternedType, len: u64) -> InternedType {
699 let key = (element, len);
700
701 {
703 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
704 if let Some(&existing) = inner.array_map.get(&key) {
705 return existing;
706 }
707 }
708
709 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
711
712 if let Some(&existing) = inner.array_map.get(&key) {
714 return existing;
715 }
716
717 let pool_index = inner.types.len() as u32;
719 let interned = InternedType::from_pool_index(pool_index);
720
721 inner.types.push(TypeData::Array { element, len });
722 inner.array_map.insert(key, interned);
723
724 interned
725 }
726
727 pub fn intern_ptr_const(&self, pointee: InternedType) -> InternedType {
732 {
734 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
735 if let Some(&existing) = inner.ptr_const_map.get(&pointee) {
736 return existing;
737 }
738 }
739
740 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
742
743 if let Some(&existing) = inner.ptr_const_map.get(&pointee) {
745 return existing;
746 }
747
748 let pool_index = inner.types.len() as u32;
750 let interned = InternedType::from_pool_index(pool_index);
751
752 inner.types.push(TypeData::PtrConst { pointee });
753 inner.ptr_const_map.insert(pointee, interned);
754
755 interned
756 }
757
758 pub fn intern_ptr_mut(&self, pointee: InternedType) -> InternedType {
763 {
765 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
766 if let Some(&existing) = inner.ptr_mut_map.get(&pointee) {
767 return existing;
768 }
769 }
770
771 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
773
774 if let Some(&existing) = inner.ptr_mut_map.get(&pointee) {
776 return existing;
777 }
778
779 let pool_index = inner.types.len() as u32;
781 let interned = InternedType::from_pool_index(pool_index);
782
783 inner.types.push(TypeData::PtrMut { pointee });
784 inner.ptr_mut_map.insert(pointee, interned);
785
786 interned
787 }
788
789 pub fn intern_ref(&self, referent: InternedType) -> InternedType {
791 {
792 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
793 if let Some(&existing) = inner.ref_map.get(&referent) {
794 return existing;
795 }
796 }
797 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
798 if let Some(&existing) = inner.ref_map.get(&referent) {
799 return existing;
800 }
801 let pool_index = inner.types.len() as u32;
802 let interned = InternedType::from_pool_index(pool_index);
803 inner.types.push(TypeData::Ref { referent });
804 inner.ref_map.insert(referent, interned);
805 interned
806 }
807
808 pub fn intern_mut_ref(&self, referent: InternedType) -> InternedType {
810 {
811 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
812 if let Some(&existing) = inner.mut_ref_map.get(&referent) {
813 return existing;
814 }
815 }
816 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
817 if let Some(&existing) = inner.mut_ref_map.get(&referent) {
818 return existing;
819 }
820 let pool_index = inner.types.len() as u32;
821 let interned = InternedType::from_pool_index(pool_index);
822 inner.types.push(TypeData::MutRef { referent });
823 inner.mut_ref_map.insert(referent, interned);
824 interned
825 }
826
827 pub fn intern_slice(&self, element: InternedType) -> InternedType {
829 {
830 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
831 if let Some(&existing) = inner.slice_map.get(&element) {
832 return existing;
833 }
834 }
835 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
836 if let Some(&existing) = inner.slice_map.get(&element) {
837 return existing;
838 }
839 let pool_index = inner.types.len() as u32;
840 let interned = InternedType::from_pool_index(pool_index);
841 inner.types.push(TypeData::Slice { element });
842 inner.slice_map.insert(element, interned);
843 interned
844 }
845
846 pub fn intern_mut_slice(&self, element: InternedType) -> InternedType {
848 {
849 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
850 if let Some(&existing) = inner.mut_slice_map.get(&element) {
851 return existing;
852 }
853 }
854 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
855 if let Some(&existing) = inner.mut_slice_map.get(&element) {
856 return existing;
857 }
858 let pool_index = inner.types.len() as u32;
859 let interned = InternedType::from_pool_index(pool_index);
860 inner.types.push(TypeData::MutSlice { element });
861 inner.mut_slice_map.insert(element, interned);
862 interned
863 }
864
865 pub fn intern_vec(&self, element: InternedType) -> InternedType {
867 {
868 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
869 if let Some(&existing) = inner.vec_map.get(&element) {
870 return existing;
871 }
872 }
873 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
874 if let Some(&existing) = inner.vec_map.get(&element) {
875 return existing;
876 }
877 let pool_index = inner.types.len() as u32;
878 let interned = InternedType::from_pool_index(pool_index);
879 inner.types.push(TypeData::Vec { element });
880 inner.vec_map.insert(element, interned);
881 interned
882 }
883
884 pub fn get_struct_by_name(&self, name: Spur) -> Option<InternedType> {
887 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
888 inner.struct_by_name.get(&name).copied()
889 }
890
891 pub fn get_enum_by_name(&self, name: Spur) -> Option<InternedType> {
893 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
894 inner.enum_by_name.get(&name).copied()
895 }
896
897 pub fn get_array(&self, element: InternedType, len: u64) -> Option<InternedType> {
899 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
900 inner.array_map.get(&(element, len)).copied()
901 }
902
903 pub fn get(&self, ty: InternedType) -> Option<TypeData> {
911 if ty.is_primitive() {
912 return None;
913 }
914
915 let pool_index = ty.pool_index().expect("non-primitive must have pool index");
916 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
917 Some(inner.types[pool_index as usize].clone())
918 }
919
920 pub fn is_struct(&self, ty: InternedType) -> bool {
922 if ty.is_primitive() {
923 return false;
924 }
925 matches!(self.get(ty), Some(TypeData::Struct(_)))
926 }
927
928 pub fn is_enum(&self, ty: InternedType) -> bool {
930 if ty.is_primitive() {
931 return false;
932 }
933 matches!(self.get(ty), Some(TypeData::Enum(_)))
934 }
935
936 pub fn is_array(&self, ty: InternedType) -> bool {
938 if ty.is_primitive() {
939 return false;
940 }
941 matches!(self.get(ty), Some(TypeData::Array { .. }))
942 }
943
944 pub fn get_struct_def(&self, ty: InternedType) -> Option<StructDef> {
946 match self.get(ty)? {
947 TypeData::Struct(data) => Some(data.def),
948 _ => None,
949 }
950 }
951
952 pub fn get_enum_def(&self, ty: InternedType) -> Option<EnumDef> {
954 match self.get(ty)? {
955 TypeData::Enum(data) => Some(data.def),
956 _ => None,
957 }
958 }
959
960 pub fn get_array_info(&self, ty: InternedType) -> Option<(InternedType, u64)> {
962 match self.get(ty)? {
963 TypeData::Array { element, len } => Some((element, len)),
964 _ => None,
965 }
966 }
967
968 pub fn struct_def(&self, struct_id: StructId) -> StructDef {
984 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
985 let pool_index = struct_id.0 as usize;
986 match &inner.types[pool_index] {
987 TypeData::Struct(data) => data.def.clone(),
988 other => panic!(
989 "Expected struct at pool index {}, got {:?}",
990 pool_index, other
991 ),
992 }
993 }
994
995 pub fn enum_def(&self, enum_id: EnumId) -> EnumDef {
1004 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1005 let pool_index = enum_id.0 as usize;
1006 match &inner.types[pool_index] {
1007 TypeData::Enum(data) => data.def.clone(),
1008 other => panic!(
1009 "Expected enum at pool index {}, got {:?}",
1010 pool_index, other
1011 ),
1012 }
1013 }
1014
1015 pub fn update_struct_def(&self, struct_id: StructId, new_def: StructDef) {
1024 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
1025 let pool_index = struct_id.0 as usize;
1026 match &mut inner.types[pool_index] {
1027 TypeData::Struct(data) => data.def = new_def,
1028 other => panic!(
1029 "Expected struct at pool index {}, got {:?}",
1030 pool_index, other
1031 ),
1032 }
1033 }
1034
1035 pub fn update_enum_def(&self, enum_id: EnumId, new_def: EnumDef) {
1044 let mut inner = self.inner.write().unwrap_or_else(PoisonError::into_inner);
1045 let pool_index = enum_id.0 as usize;
1046 match &mut inner.types[pool_index] {
1047 TypeData::Enum(data) => data.def = new_def,
1048 other => panic!(
1049 "Expected enum at pool index {}, got {:?}",
1050 pool_index, other
1051 ),
1052 }
1053 }
1054
1055 #[inline]
1059 pub fn struct_id_to_interned(&self, struct_id: StructId) -> InternedType {
1060 InternedType::from_pool_index(struct_id.0)
1061 }
1062
1063 #[inline]
1067 pub fn enum_id_to_interned(&self, enum_id: EnumId) -> InternedType {
1068 InternedType::from_pool_index(enum_id.0)
1069 }
1070
1071 pub fn array_def(&self, array_id: ArrayTypeId) -> (Type, u64) {
1085 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1086 let pool_index = array_id.0 as usize;
1087 match &inner.types[pool_index] {
1088 TypeData::Array { element, len } => {
1089 let element_type = Self::interned_to_type_recursive(*element, &inner);
1091 (element_type, *len)
1092 }
1093 other => panic!(
1094 "Expected array at pool index {}, got {:?}",
1095 pool_index, other
1096 ),
1097 }
1098 }
1099
1100 pub fn intern_array_from_type(&self, element_type: Type, len: u64) -> ArrayTypeId {
1109 let element_interned = Self::type_to_interned_recursive(element_type);
1110 let array_interned = self.intern_array(element_interned, len);
1111 ArrayTypeId::from_pool_index(
1112 array_interned
1113 .pool_index()
1114 .expect("array must have pool index"),
1115 )
1116 }
1117
1118 pub fn get_array_by_type(&self, element_type: Type, len: u64) -> Option<ArrayTypeId> {
1122 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1123 let element_interned = Self::type_to_interned_recursive(element_type);
1124 let array_interned = inner.array_map.get(&(element_interned, len))?;
1125 Some(ArrayTypeId::from_pool_index(
1126 array_interned
1127 .pool_index()
1128 .expect("array must have pool index"),
1129 ))
1130 }
1131
1132 pub fn intern_ptr_const_from_type(&self, pointee_type: Type) -> PtrConstTypeId {
1138 let pointee_interned = Self::type_to_interned_recursive(pointee_type);
1139 let ptr_interned = self.intern_ptr_const(pointee_interned);
1140 PtrConstTypeId::from_pool_index(
1141 ptr_interned
1142 .pool_index()
1143 .expect("ptr const must have pool index"),
1144 )
1145 }
1146
1147 pub fn intern_ptr_mut_from_type(&self, pointee_type: Type) -> PtrMutTypeId {
1153 let pointee_interned = Self::type_to_interned_recursive(pointee_type);
1154 let ptr_interned = self.intern_ptr_mut(pointee_interned);
1155 PtrMutTypeId::from_pool_index(
1156 ptr_interned
1157 .pool_index()
1158 .expect("ptr mut must have pool index"),
1159 )
1160 }
1161
1162 pub fn ptr_const_def(&self, ptr_id: PtrConstTypeId) -> Type {
1164 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1165 let pool_index = ptr_id.0 as usize;
1166 match &inner.types[pool_index] {
1167 TypeData::PtrConst { pointee } => Self::interned_to_type_recursive(*pointee, &inner),
1168 other => panic!(
1169 "Expected ptr const at pool index {}, got {:?}",
1170 pool_index, other
1171 ),
1172 }
1173 }
1174
1175 pub fn ptr_mut_def(&self, ptr_id: PtrMutTypeId) -> Type {
1177 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1178 let pool_index = ptr_id.0 as usize;
1179 match &inner.types[pool_index] {
1180 TypeData::PtrMut { pointee } => Self::interned_to_type_recursive(*pointee, &inner),
1181 other => panic!(
1182 "Expected ptr mut at pool index {}, got {:?}",
1183 pool_index, other
1184 ),
1185 }
1186 }
1187
1188 pub fn intern_ref_from_type(&self, referent_type: Type) -> RefTypeId {
1190 let referent_interned = Self::type_to_interned_recursive(referent_type);
1191 let ref_interned = self.intern_ref(referent_interned);
1192 RefTypeId::from_pool_index(ref_interned.pool_index().expect("ref must have pool index"))
1193 }
1194
1195 pub fn intern_mut_ref_from_type(&self, referent_type: Type) -> MutRefTypeId {
1197 let referent_interned = Self::type_to_interned_recursive(referent_type);
1198 let mut_ref_interned = self.intern_mut_ref(referent_interned);
1199 MutRefTypeId::from_pool_index(
1200 mut_ref_interned
1201 .pool_index()
1202 .expect("mut ref must have pool index"),
1203 )
1204 }
1205
1206 pub fn ref_def(&self, ref_id: RefTypeId) -> Type {
1208 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1209 let pool_index = ref_id.0 as usize;
1210 match &inner.types[pool_index] {
1211 TypeData::Ref { referent } => Self::interned_to_type_recursive(*referent, &inner),
1212 other => panic!("Expected ref at pool index {}, got {:?}", pool_index, other),
1213 }
1214 }
1215
1216 pub fn mut_ref_def(&self, ref_id: MutRefTypeId) -> Type {
1218 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1219 let pool_index = ref_id.0 as usize;
1220 match &inner.types[pool_index] {
1221 TypeData::MutRef { referent } => Self::interned_to_type_recursive(*referent, &inner),
1222 other => panic!(
1223 "Expected mut ref at pool index {}, got {:?}",
1224 pool_index, other
1225 ),
1226 }
1227 }
1228
1229 pub fn intern_slice_from_type(&self, element_type: Type) -> SliceTypeId {
1231 let element_interned = Self::type_to_interned_recursive(element_type);
1232 let slice_interned = self.intern_slice(element_interned);
1233 SliceTypeId::from_pool_index(
1234 slice_interned
1235 .pool_index()
1236 .expect("slice must have pool index"),
1237 )
1238 }
1239
1240 pub fn intern_mut_slice_from_type(&self, element_type: Type) -> MutSliceTypeId {
1242 let element_interned = Self::type_to_interned_recursive(element_type);
1243 let mut_slice_interned = self.intern_mut_slice(element_interned);
1244 MutSliceTypeId::from_pool_index(
1245 mut_slice_interned
1246 .pool_index()
1247 .expect("mut slice must have pool index"),
1248 )
1249 }
1250
1251 pub fn slice_def(&self, slice_id: SliceTypeId) -> Type {
1253 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1254 let pool_index = slice_id.0 as usize;
1255 match &inner.types[pool_index] {
1256 TypeData::Slice { element } => Self::interned_to_type_recursive(*element, &inner),
1257 other => panic!(
1258 "Expected slice at pool index {}, got {:?}",
1259 pool_index, other
1260 ),
1261 }
1262 }
1263
1264 pub fn mut_slice_def(&self, slice_id: MutSliceTypeId) -> Type {
1266 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1267 let pool_index = slice_id.0 as usize;
1268 match &inner.types[pool_index] {
1269 TypeData::MutSlice { element } => Self::interned_to_type_recursive(*element, &inner),
1270 other => panic!(
1271 "Expected mut slice at pool index {}, got {:?}",
1272 pool_index, other
1273 ),
1274 }
1275 }
1276
1277 pub fn intern_vec_from_type(&self, element_type: Type) -> VecTypeId {
1279 let element_interned = Self::type_to_interned_recursive(element_type);
1280 let vec_interned = self.intern_vec(element_interned);
1281 VecTypeId::from_pool_index(vec_interned.pool_index().expect("vec must have pool index"))
1282 }
1283
1284 pub fn vec_def(&self, vec_id: VecTypeId) -> Type {
1286 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1287 let pool_index = vec_id.0 as usize;
1288 match &inner.types[pool_index] {
1289 TypeData::Vec { element } => Self::interned_to_type_recursive(*element, &inner),
1290 other => panic!("Expected vec at pool index {}, got {:?}", pool_index, other),
1291 }
1292 }
1293
1294 pub fn is_thread_safety_type(&self, ty: Type) -> gruel_builtins::ThreadSafety {
1314 use gruel_builtins::ThreadSafety;
1315 match ty.kind() {
1316 TypeKind::PtrConst(_) | TypeKind::PtrMut(_) => ThreadSafety::Unsend,
1321
1322 TypeKind::I8
1326 | TypeKind::I16
1327 | TypeKind::I32
1328 | TypeKind::I64
1329 | TypeKind::U8
1330 | TypeKind::U16
1331 | TypeKind::U32
1332 | TypeKind::U64
1333 | TypeKind::Isize
1334 | TypeKind::Usize
1335 | TypeKind::F16
1336 | TypeKind::F32
1337 | TypeKind::F64
1338 | TypeKind::Bool
1339 | TypeKind::Char
1340 | TypeKind::Unit
1341 | TypeKind::Never
1342 | TypeKind::Error
1343 | TypeKind::CSchar
1348 | TypeKind::CShort
1349 | TypeKind::CInt
1350 | TypeKind::CLong
1351 | TypeKind::CLonglong
1352 | TypeKind::CUchar
1353 | TypeKind::CUshort
1354 | TypeKind::CUint
1355 | TypeKind::CUlong
1356 | TypeKind::CUlonglong
1357 | TypeKind::CFloat
1358 | TypeKind::CDouble
1359 | TypeKind::CVoid => ThreadSafety::Sync,
1360
1361 TypeKind::Array(array_id) => {
1363 let (element_type, _length) = self.array_def(array_id);
1364 self.is_thread_safety_type(element_type)
1365 }
1366 TypeKind::Slice(slice_id) => {
1367 let element_type = self.slice_def(slice_id);
1368 self.is_thread_safety_type(element_type)
1369 }
1370 TypeKind::MutSlice(slice_id) => {
1371 let element_type = self.mut_slice_def(slice_id);
1372 self.is_thread_safety_type(element_type)
1373 }
1374 TypeKind::Vec(vec_id) => {
1375 let element_type = self.vec_def(vec_id);
1376 self.is_thread_safety_type(element_type)
1377 }
1378 TypeKind::Ref(ref_id) => {
1379 let referent = self.ref_def(ref_id);
1380 self.is_thread_safety_type(referent)
1381 }
1382 TypeKind::MutRef(ref_id) => {
1383 let referent = self.mut_ref_def(ref_id);
1384 self.is_thread_safety_type(referent)
1385 }
1386
1387 TypeKind::Struct(struct_id) => self.struct_def(struct_id).thread_safety,
1388 TypeKind::Enum(enum_id) => self.enum_def(enum_id).thread_safety,
1389
1390 TypeKind::Module(_)
1393 | TypeKind::Interface(_)
1394 | TypeKind::ComptimeType
1395 | TypeKind::ComptimeStr
1396 | TypeKind::ComptimeInt => ThreadSafety::Sync,
1397 }
1398 }
1399
1400 pub fn is_type_linear(&self, ty: Type) -> bool {
1410 match ty.kind() {
1411 TypeKind::Struct(struct_id) => self.struct_def(struct_id).posture == Posture::Linear,
1412 TypeKind::Array(array_id) => {
1413 let (element_type, length) = self.array_def(array_id);
1414 length > 0 && self.is_type_linear(element_type)
1415 }
1416 TypeKind::Vec(vec_id) => {
1417 let element_type = self.vec_def(vec_id);
1418 self.is_type_linear(element_type)
1419 }
1420 TypeKind::Enum(enum_id) => {
1429 let def = self.enum_def(enum_id);
1430 def.posture == Posture::Linear
1431 || def
1432 .variants
1433 .iter()
1434 .any(|v| v.fields.iter().any(|f| self.is_type_linear(*f)))
1435 }
1436 _ => false,
1437 }
1438 }
1439
1440 pub fn all_vec_ids(&self) -> Vec<VecTypeId> {
1442 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1443 inner
1444 .types
1445 .iter()
1446 .enumerate()
1447 .filter_map(|(i, td)| match td {
1448 TypeData::Vec { .. } => Some(VecTypeId::from_pool_index(i as u32)),
1449 _ => None,
1450 })
1451 .collect()
1452 }
1453
1454 fn interned_to_type_recursive(ty: InternedType, inner: &TypeInternPoolInner) -> Type {
1458 if ty.is_primitive() {
1459 return match ty.0 {
1460 0 => Type::I8,
1461 1 => Type::I16,
1462 2 => Type::I32,
1463 3 => Type::I64,
1464 4 => Type::U8,
1465 5 => Type::U16,
1466 6 => Type::U32,
1467 7 => Type::U64,
1468 8 => Type::ISIZE,
1469 9 => Type::USIZE,
1470 10 => Type::F16,
1471 11 => Type::F32,
1472 12 => Type::F64,
1473 13 => Type::BOOL,
1474 14 => Type::UNIT,
1475 15 => Type::NEVER,
1476 16 => Type::ERROR,
1477 _ => panic!("Unknown primitive index: {}", ty.0),
1478 };
1479 }
1480
1481 let pool_index = ty.pool_index().expect("non-primitive must have pool index");
1482 match &inner.types[pool_index as usize] {
1483 TypeData::Struct(_) => Type::new_struct(StructId::from_pool_index(pool_index)),
1484 TypeData::Enum(_) => Type::new_enum(EnumId::from_pool_index(pool_index)),
1485 TypeData::Array { .. } => Type::new_array(ArrayTypeId::from_pool_index(pool_index)),
1486 TypeData::PtrConst { .. } => {
1487 Type::new_ptr_const(PtrConstTypeId::from_pool_index(pool_index))
1488 }
1489 TypeData::PtrMut { .. } => Type::new_ptr_mut(PtrMutTypeId::from_pool_index(pool_index)),
1490 TypeData::Ref { .. } => Type::new_ref(RefTypeId::from_pool_index(pool_index)),
1491 TypeData::MutRef { .. } => Type::new_mut_ref(MutRefTypeId::from_pool_index(pool_index)),
1492 TypeData::Slice { .. } => Type::new_slice(SliceTypeId::from_pool_index(pool_index)),
1493 TypeData::MutSlice { .. } => {
1494 Type::new_mut_slice(MutSliceTypeId::from_pool_index(pool_index))
1495 }
1496 TypeData::Vec { .. } => Type::new_vec(VecTypeId::from_pool_index(pool_index)),
1497 }
1498 }
1499
1500 fn type_to_interned_recursive(ty: Type) -> InternedType {
1505 match ty.kind() {
1506 TypeKind::I8 => InternedType::I8,
1507 TypeKind::I16 => InternedType::I16,
1508 TypeKind::I32 => InternedType::I32,
1509 TypeKind::I64 => InternedType::I64,
1510 TypeKind::U8 => InternedType::U8,
1511 TypeKind::U16 => InternedType::U16,
1512 TypeKind::U32 => InternedType::U32,
1513 TypeKind::U64 => InternedType::U64,
1514 TypeKind::Isize => InternedType::ISIZE,
1515 TypeKind::Usize => InternedType::USIZE,
1516 TypeKind::F16 => InternedType::F16,
1517 TypeKind::F32 => InternedType::F32,
1518 TypeKind::F64 => InternedType::F64,
1519 TypeKind::Bool => InternedType::BOOL,
1520 TypeKind::Char => InternedType::CHAR,
1521 TypeKind::Unit => InternedType::UNIT,
1522 TypeKind::Never => InternedType::NEVER,
1523 TypeKind::Error => InternedType::ERROR,
1524 TypeKind::CSchar => InternedType::C_SCHAR,
1526 TypeKind::CShort => InternedType::C_SHORT,
1527 TypeKind::CInt => InternedType::C_INT,
1528 TypeKind::CLong => InternedType::C_LONG,
1529 TypeKind::CLonglong => InternedType::C_LONGLONG,
1530 TypeKind::CUchar => InternedType::C_UCHAR,
1531 TypeKind::CUshort => InternedType::C_USHORT,
1532 TypeKind::CUint => InternedType::C_UINT,
1533 TypeKind::CUlong => InternedType::C_ULONG,
1534 TypeKind::CUlonglong => InternedType::C_ULONGLONG,
1535 TypeKind::CFloat => InternedType::C_FLOAT,
1536 TypeKind::CDouble => InternedType::C_DOUBLE,
1537 TypeKind::CVoid => InternedType::C_VOID,
1538 TypeKind::Struct(id) => InternedType::from_pool_index(id.pool_index()),
1539 TypeKind::Enum(id) => InternedType::from_pool_index(id.pool_index()),
1540 TypeKind::Array(id) => InternedType::from_pool_index(id.pool_index()),
1541 TypeKind::PtrConst(id) => InternedType::from_pool_index(id.pool_index()),
1542 TypeKind::PtrMut(id) => InternedType::from_pool_index(id.pool_index()),
1543 TypeKind::Ref(id) => InternedType::from_pool_index(id.pool_index()),
1544 TypeKind::MutRef(id) => InternedType::from_pool_index(id.pool_index()),
1545 TypeKind::Slice(id) => InternedType::from_pool_index(id.pool_index()),
1546 TypeKind::MutSlice(id) => InternedType::from_pool_index(id.pool_index()),
1547 TypeKind::Vec(id) => InternedType::from_pool_index(id.pool_index()),
1548 TypeKind::Module(_) => panic!("Cannot intern module types"),
1549 TypeKind::Interface(_) => panic!("Cannot intern interface types"),
1550 TypeKind::ComptimeType => panic!("Cannot intern comptime types"),
1551 TypeKind::ComptimeStr => panic!("Cannot intern comptime_str types"),
1552 TypeKind::ComptimeInt => panic!("Cannot intern comptime_int types"),
1553 }
1554 }
1555
1556 #[inline]
1560 pub fn array_id_to_interned(&self, array_id: ArrayTypeId) -> InternedType {
1561 InternedType::from_pool_index(array_id.0)
1562 }
1563
1564 pub fn all_struct_ids(&self) -> Vec<StructId> {
1569 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1570 inner
1571 .struct_by_name
1572 .values()
1573 .map(|interned| {
1574 let pool_index = interned.pool_index().expect("struct must have pool index");
1575 StructId::from_pool_index(pool_index)
1576 })
1577 .collect()
1578 }
1579
1580 pub fn all_enum_ids(&self) -> Vec<EnumId> {
1585 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1586 inner
1587 .enum_by_name
1588 .values()
1589 .map(|interned| {
1590 let pool_index = interned.pool_index().expect("enum must have pool index");
1591 EnumId::from_pool_index(pool_index)
1592 })
1593 .collect()
1594 }
1595
1596 pub fn all_array_ids(&self) -> Vec<ArrayTypeId> {
1601 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1602 inner
1603 .types
1604 .iter()
1605 .enumerate()
1606 .filter_map(|(idx, data)| match data {
1607 TypeData::Array { .. } => Some(ArrayTypeId(idx as u32)),
1608 _ => None,
1609 })
1610 .collect()
1611 }
1612
1613 pub fn len(&self) -> usize {
1615 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1616 inner.types.len()
1617 }
1618
1619 pub fn is_empty(&self) -> bool {
1621 self.len() == 0
1622 }
1623
1624 pub fn stats(&self) -> TypeInternPoolStats {
1626 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1627 let mut struct_count = 0;
1628 let mut enum_count = 0;
1629 let mut array_count = 0;
1630
1631 for data in &inner.types {
1632 match data {
1633 TypeData::Struct(_) => struct_count += 1,
1634 TypeData::Enum(_) => enum_count += 1,
1635 TypeData::Array { .. } => array_count += 1,
1636 TypeData::PtrConst { .. }
1637 | TypeData::PtrMut { .. }
1638 | TypeData::Ref { .. }
1639 | TypeData::MutRef { .. }
1640 | TypeData::Slice { .. }
1641 | TypeData::MutSlice { .. }
1642 | TypeData::Vec { .. } => {
1643 }
1645 }
1646 }
1647
1648 TypeInternPoolStats {
1649 struct_count,
1650 enum_count,
1651 array_count,
1652 total: inner.types.len(),
1653 }
1654 }
1655
1656 pub fn type_to_interned(&self, ty: Type) -> Option<InternedType> {
1671 match ty.kind() {
1672 TypeKind::I8 => Some(InternedType::I8),
1673 TypeKind::I16 => Some(InternedType::I16),
1674 TypeKind::I32 => Some(InternedType::I32),
1675 TypeKind::I64 => Some(InternedType::I64),
1676 TypeKind::U8 => Some(InternedType::U8),
1677 TypeKind::U16 => Some(InternedType::U16),
1678 TypeKind::U32 => Some(InternedType::U32),
1679 TypeKind::U64 => Some(InternedType::U64),
1680 TypeKind::Isize => Some(InternedType::ISIZE),
1681 TypeKind::Usize => Some(InternedType::USIZE),
1682 TypeKind::F16 => Some(InternedType::F16),
1683 TypeKind::F32 => Some(InternedType::F32),
1684 TypeKind::F64 => Some(InternedType::F64),
1685 TypeKind::Bool => Some(InternedType::BOOL),
1686 TypeKind::Char => Some(InternedType::CHAR),
1687 TypeKind::Unit => Some(InternedType::UNIT),
1688 TypeKind::Never => Some(InternedType::NEVER),
1689 TypeKind::Error => Some(InternedType::ERROR),
1690 TypeKind::CSchar => Some(InternedType::C_SCHAR),
1692 TypeKind::CShort => Some(InternedType::C_SHORT),
1693 TypeKind::CInt => Some(InternedType::C_INT),
1694 TypeKind::CLong => Some(InternedType::C_LONG),
1695 TypeKind::CLonglong => Some(InternedType::C_LONGLONG),
1696 TypeKind::CUchar => Some(InternedType::C_UCHAR),
1697 TypeKind::CUshort => Some(InternedType::C_USHORT),
1698 TypeKind::CUint => Some(InternedType::C_UINT),
1699 TypeKind::CUlong => Some(InternedType::C_ULONG),
1700 TypeKind::CUlonglong => Some(InternedType::C_ULONGLONG),
1701 TypeKind::CFloat => Some(InternedType::C_FLOAT),
1702 TypeKind::CDouble => Some(InternedType::C_DOUBLE),
1703 TypeKind::CVoid => Some(InternedType::C_VOID),
1704 TypeKind::Struct(_)
1708 | TypeKind::Enum(_)
1709 | TypeKind::Array(_)
1710 | TypeKind::PtrConst(_)
1711 | TypeKind::PtrMut(_)
1712 | TypeKind::Ref(_)
1713 | TypeKind::MutRef(_)
1714 | TypeKind::Slice(_)
1715 | TypeKind::MutSlice(_)
1716 | TypeKind::Vec(_)
1717 | TypeKind::Module(_)
1718 | TypeKind::Interface(_) => None,
1719 TypeKind::ComptimeType | TypeKind::ComptimeStr | TypeKind::ComptimeInt => None,
1721 }
1722 }
1723
1724 pub fn interned_to_type(&self, ty: InternedType) -> Option<Type> {
1729 if !ty.is_primitive() {
1730 return None;
1731 }
1732
1733 Some(match ty.0 {
1734 0 => Type::I8,
1735 1 => Type::I16,
1736 2 => Type::I32,
1737 3 => Type::I64,
1738 4 => Type::U8,
1739 5 => Type::U16,
1740 6 => Type::U32,
1741 7 => Type::U64,
1742 8 => Type::ISIZE,
1743 9 => Type::USIZE,
1744 10 => Type::F16,
1745 11 => Type::F32,
1746 12 => Type::F64,
1747 13 => Type::BOOL,
1748 14 => Type::UNIT,
1749 15 => Type::NEVER,
1750 16 => Type::ERROR,
1751 20 => Type::CHAR,
1752 21 => Type::C_SCHAR,
1754 22 => Type::C_SHORT,
1755 23 => Type::C_INT,
1756 24 => Type::C_LONG,
1757 25 => Type::C_LONGLONG,
1758 26 => Type::C_UCHAR,
1759 27 => Type::C_USHORT,
1760 28 => Type::C_UINT,
1761 29 => Type::C_ULONG,
1762 30 => Type::C_ULONGLONG,
1763 31 => Type::C_FLOAT,
1764 32 => Type::C_DOUBLE,
1765 33 => Type::C_VOID,
1766 _ => return None,
1767 })
1768 }
1769
1770 pub fn abi_slot_count(&self, ty: Type) -> u32 {
1777 match ty.kind() {
1778 TypeKind::Struct(id) => {
1779 let def = self.struct_def(id);
1780 def.fields.iter().map(|f| self.abi_slot_count(f.ty)).sum()
1781 }
1782 TypeKind::Array(id) => {
1783 let (elem, len) = self.array_def(id);
1784 self.abi_slot_count(elem) * len as u32
1785 }
1786 TypeKind::Unit
1787 | TypeKind::Never
1788 | TypeKind::ComptimeType
1789 | TypeKind::ComptimeStr
1790 | TypeKind::ComptimeInt
1791 | TypeKind::Module(_) => 0,
1792 TypeKind::Slice(_) | TypeKind::MutSlice(_) | TypeKind::Interface(_) => 2,
1794 TypeKind::Vec(_) => 3,
1796 _ => 1,
1797 }
1798 }
1799
1800 pub fn format_type_name(&self, ty: Type) -> String {
1808 match ty.kind() {
1809 TypeKind::I8 => "i8".to_string(),
1810 TypeKind::I16 => "i16".to_string(),
1811 TypeKind::I32 => "i32".to_string(),
1812 TypeKind::I64 => "i64".to_string(),
1813 TypeKind::U8 => "u8".to_string(),
1814 TypeKind::U16 => "u16".to_string(),
1815 TypeKind::U32 => "u32".to_string(),
1816 TypeKind::U64 => "u64".to_string(),
1817 TypeKind::Isize => "isize".to_string(),
1818 TypeKind::Usize => "usize".to_string(),
1819 TypeKind::F16 => "f16".to_string(),
1820 TypeKind::F32 => "f32".to_string(),
1821 TypeKind::F64 => "f64".to_string(),
1822 TypeKind::Bool => "bool".to_string(),
1823 TypeKind::Char => "char".to_string(),
1824 TypeKind::Unit => "()".to_string(),
1825 TypeKind::Never => "!".to_string(),
1826 TypeKind::Error => "<error>".to_string(),
1827 TypeKind::CSchar => "c_schar".to_string(),
1829 TypeKind::CShort => "c_short".to_string(),
1830 TypeKind::CInt => "c_int".to_string(),
1831 TypeKind::CLong => "c_long".to_string(),
1832 TypeKind::CLonglong => "c_longlong".to_string(),
1833 TypeKind::CUchar => "c_uchar".to_string(),
1834 TypeKind::CUshort => "c_ushort".to_string(),
1835 TypeKind::CUint => "c_uint".to_string(),
1836 TypeKind::CUlong => "c_ulong".to_string(),
1837 TypeKind::CUlonglong => "c_ulonglong".to_string(),
1838 TypeKind::CFloat => "c_float".to_string(),
1839 TypeKind::CDouble => "c_double".to_string(),
1840 TypeKind::CVoid => "c_void".to_string(),
1841 TypeKind::ComptimeType => "type".to_string(),
1842 TypeKind::ComptimeStr => "comptime_str".to_string(),
1843 TypeKind::ComptimeInt => "comptime_int".to_string(),
1844 TypeKind::Struct(id) => self.struct_def(id).name.clone(),
1845 TypeKind::Enum(id) => self.enum_def(id).name.clone(),
1846 TypeKind::Array(id) => {
1847 let (elem, len) = self.array_def(id);
1848 format!("[{}; {}]", self.format_type_name(elem), len)
1849 }
1850 TypeKind::PtrConst(id) => {
1851 let pointee = self.ptr_const_def(id);
1852 format!("Ptr({})", self.format_type_name(pointee))
1853 }
1854 TypeKind::PtrMut(id) => {
1855 let pointee = self.ptr_mut_def(id);
1856 format!("MutPtr({})", self.format_type_name(pointee))
1857 }
1858 TypeKind::Ref(id) => {
1859 let referent = self.ref_def(id);
1860 format!("Ref({})", self.format_type_name(referent))
1861 }
1862 TypeKind::MutRef(id) => {
1863 let referent = self.mut_ref_def(id);
1864 format!("MutRef({})", self.format_type_name(referent))
1865 }
1866 TypeKind::Slice(id) => {
1867 let element = self.slice_def(id);
1868 format!("Slice({})", self.format_type_name(element))
1869 }
1870 TypeKind::MutSlice(id) => {
1871 let element = self.mut_slice_def(id);
1872 format!("MutSlice({})", self.format_type_name(element))
1873 }
1874 TypeKind::Vec(id) => {
1875 let element = self.vec_def(id);
1876 format!("Vec({})", self.format_type_name(element))
1877 }
1878 TypeKind::Module(_) => "<module>".to_string(),
1879 TypeKind::Interface(id) => format!("<interface#{}>", id.0),
1884 }
1885 }
1886}
1887
1888impl Default for TypeInternPool {
1889 fn default() -> Self {
1890 Self::new()
1891 }
1892}
1893
1894impl Clone for TypeInternPool {
1895 fn clone(&self) -> Self {
1900 let inner = self.inner.read().unwrap_or_else(PoisonError::into_inner);
1901 Self {
1902 inner: RwLock::new(TypeInternPoolInner {
1903 types: inner.types.clone(),
1904 array_map: inner.array_map.clone(),
1905 ptr_const_map: inner.ptr_const_map.clone(),
1906 ptr_mut_map: inner.ptr_mut_map.clone(),
1907 ref_map: inner.ref_map.clone(),
1908 mut_ref_map: inner.mut_ref_map.clone(),
1909 slice_map: inner.slice_map.clone(),
1910 mut_slice_map: inner.mut_slice_map.clone(),
1911 vec_map: inner.vec_map.clone(),
1912 struct_by_name: inner.struct_by_name.clone(),
1913 enum_by_name: inner.enum_by_name.clone(),
1914 layout_cache: inner.layout_cache.clone(),
1915 }),
1916 }
1917 }
1918}
1919
1920#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1922pub struct TypeInternPoolStats {
1923 pub struct_count: usize,
1924 pub enum_count: usize,
1925 pub array_count: usize,
1926 pub total: usize,
1927}
1928
1929#[cfg(test)]
1930mod tests {
1931 use super::*;
1932 use crate::types::EnumVariantDef;
1933 use lasso::ThreadedRodeo;
1934
1935 #[test]
1940 fn type_intern_pool_round_trips_through_serde() {
1941 let pool = TypeInternPool::new();
1944 let inner_array = pool.intern_array(InternedType::I32, 4);
1945 let outer_array = pool.intern_array(inner_array, 2);
1946 let ptr = pool.intern_ptr_const(InternedType::I64);
1947
1948 let bytes =
1949 bincode::serde::encode_to_vec(&pool, bincode::config::standard()).expect("serialize");
1950 let (restored, _): (TypeInternPool, _) =
1951 bincode::serde::decode_from_slice(&bytes, bincode::config::standard())
1952 .expect("deserialize");
1953
1954 assert_eq!(restored.intern_array(InternedType::I32, 4), inner_array);
1958 assert_eq!(restored.intern_array(inner_array, 2), outer_array);
1959 assert_eq!(restored.intern_ptr_const(InternedType::I64), ptr);
1960 }
1961
1962 #[test]
1963 fn test_interned_type_primitives() {
1964 assert!(InternedType::I8.is_primitive());
1965 assert!(InternedType::I16.is_primitive());
1966 assert!(InternedType::I32.is_primitive());
1967 assert!(InternedType::I64.is_primitive());
1968 assert!(InternedType::U8.is_primitive());
1969 assert!(InternedType::U16.is_primitive());
1970 assert!(InternedType::U32.is_primitive());
1971 assert!(InternedType::U64.is_primitive());
1972 assert!(InternedType::BOOL.is_primitive());
1973 assert!(InternedType::UNIT.is_primitive());
1974 assert!(InternedType::NEVER.is_primitive());
1975 assert!(InternedType::ERROR.is_primitive());
1976 }
1977
1978 #[test]
1979 fn test_interned_type_indices() {
1980 assert_eq!(InternedType::I8.index(), 0);
1981 assert_eq!(InternedType::I16.index(), 1);
1982 assert_eq!(InternedType::I32.index(), 2);
1983 assert_eq!(InternedType::I64.index(), 3);
1984 assert_eq!(InternedType::U8.index(), 4);
1985 assert_eq!(InternedType::ISIZE.index(), 8);
1986 assert_eq!(InternedType::USIZE.index(), 9);
1987 assert_eq!(InternedType::F16.index(), 10);
1988 assert_eq!(InternedType::F32.index(), 11);
1989 assert_eq!(InternedType::F64.index(), 12);
1990 assert_eq!(InternedType::BOOL.index(), 13);
1991 assert_eq!(InternedType::UNIT.index(), 14);
1992 }
1993
1994 #[test]
1995 fn test_interned_type_pool_index() {
1996 assert_eq!(InternedType::I32.pool_index(), None);
1998 assert_eq!(InternedType::BOOL.pool_index(), None);
1999
2000 let composite = InternedType::from_pool_index(0);
2002 assert_eq!(composite.pool_index(), Some(0));
2003 assert!(!composite.is_primitive());
2004
2005 let composite2 = InternedType::from_pool_index(42);
2006 assert_eq!(composite2.pool_index(), Some(42));
2007 }
2008
2009 #[test]
2010 fn test_interned_type_equality() {
2011 assert_eq!(InternedType::I32, InternedType::I32);
2012 assert_ne!(InternedType::I32, InternedType::I64);
2013 assert_ne!(InternedType::I32, InternedType::from_pool_index(0));
2014 }
2015
2016 #[test]
2017 fn test_interned_type_debug() {
2018 let i32_str = format!("{:?}", InternedType::I32);
2019 assert!(i32_str.contains("i32"));
2020
2021 let composite_str = format!("{:?}", InternedType::from_pool_index(5));
2022 assert!(composite_str.contains("pool:5"));
2023 }
2024
2025 #[test]
2030 fn test_pool_new() {
2031 let pool = TypeInternPool::new();
2032 assert!(pool.is_empty());
2033 assert_eq!(pool.len(), 0);
2034 }
2035
2036 #[test]
2037 fn test_pool_register_struct() {
2038 let pool = TypeInternPool::new();
2039 let interner = ThreadedRodeo::default();
2040 let name = interner.get_or_intern("Point");
2041
2042 let def = StructDef {
2043 name: "Point".to_string(),
2044 fields: vec![],
2045 posture: Posture::Affine,
2046 is_clone: false,
2047 thread_safety: gruel_builtins::ThreadSafety::Sync,
2048 destructor: None,
2049 is_builtin: false,
2050 is_pub: false,
2051 file_id: gruel_util::FileId::DEFAULT,
2052 is_c_layout: false,
2053 };
2054
2055 let (struct_id, is_new) = pool.register_struct(name, def.clone());
2056 assert!(is_new);
2057 assert_eq!(struct_id.pool_index(), 0); assert_eq!(pool.len(), 1);
2059
2060 let (struct_id2, is_new2) = pool.register_struct(name, def);
2062 assert!(!is_new2);
2063 assert_eq!(struct_id, struct_id2);
2064 assert_eq!(pool.len(), 1); }
2066
2067 #[test]
2068 fn test_pool_register_enum() {
2069 let pool = TypeInternPool::new();
2070 let interner = ThreadedRodeo::default();
2071 let name = interner.get_or_intern("Color");
2072
2073 let def = EnumDef {
2074 name: "Color".to_string(),
2075 variants: vec![
2076 EnumVariantDef::unit("Red"),
2077 EnumVariantDef::unit("Green"),
2078 EnumVariantDef::unit("Blue"),
2079 ],
2080 posture: Posture::Affine,
2081 thread_safety: gruel_builtins::ThreadSafety::Sync,
2082 is_pub: false,
2083 file_id: gruel_util::FileId::DEFAULT,
2084 destructor: None,
2085 is_c_layout: false,
2086 };
2087
2088 let (enum_id, is_new) = pool.register_enum(name, def.clone());
2089 assert!(is_new);
2090 assert_eq!(enum_id.pool_index(), 0); assert_eq!(pool.len(), 1);
2092
2093 let (enum_id2, is_new2) = pool.register_enum(name, def);
2095 assert!(!is_new2);
2096 assert_eq!(enum_id, enum_id2);
2097 }
2098
2099 #[test]
2100 fn test_pool_intern_array() {
2101 let pool = TypeInternPool::new();
2102
2103 let arr1 = pool.intern_array(InternedType::I32, 5);
2105 assert!(!arr1.is_primitive());
2106 assert_eq!(pool.len(), 1);
2107
2108 let arr2 = pool.intern_array(InternedType::I32, 5);
2110 assert_eq!(arr1, arr2);
2111 assert_eq!(pool.len(), 1);
2112
2113 let arr3 = pool.intern_array(InternedType::I32, 10);
2115 assert_ne!(arr1, arr3);
2116 assert_eq!(pool.len(), 2);
2117
2118 let arr4 = pool.intern_array(InternedType::I64, 5);
2120 assert_ne!(arr1, arr4);
2121 assert_eq!(pool.len(), 3);
2122 }
2123
2124 #[test]
2125 fn test_pool_get_struct_by_name() {
2126 let pool = TypeInternPool::new();
2127 let interner = ThreadedRodeo::default();
2128 let name = interner.get_or_intern("Point");
2129
2130 assert!(pool.get_struct_by_name(name).is_none());
2131
2132 let def = StructDef {
2133 name: "Point".to_string(),
2134 fields: vec![],
2135 posture: Posture::Affine,
2136 is_clone: false,
2137 thread_safety: gruel_builtins::ThreadSafety::Sync,
2138 destructor: None,
2139 is_builtin: false,
2140 is_pub: false,
2141 file_id: gruel_util::FileId::DEFAULT,
2142 is_c_layout: false,
2143 };
2144
2145 let (struct_id, _) = pool.register_struct(name, def);
2146 let expected = pool.struct_id_to_interned(struct_id);
2148 assert_eq!(pool.get_struct_by_name(name), Some(expected));
2149 }
2150
2151 #[test]
2152 fn test_pool_get_enum_by_name() {
2153 let pool = TypeInternPool::new();
2154 let interner = ThreadedRodeo::default();
2155 let name = interner.get_or_intern("Status");
2156
2157 assert!(pool.get_enum_by_name(name).is_none());
2158
2159 let def = EnumDef {
2160 name: "Status".to_string(),
2161 variants: vec![
2162 EnumVariantDef::unit("Active"),
2163 EnumVariantDef::unit("Inactive"),
2164 ],
2165 posture: Posture::Affine,
2166 thread_safety: gruel_builtins::ThreadSafety::Sync,
2167 is_pub: false,
2168 file_id: gruel_util::FileId::DEFAULT,
2169 destructor: None,
2170 is_c_layout: false,
2171 };
2172
2173 let (enum_id, _) = pool.register_enum(name, def);
2174 let expected = pool.enum_id_to_interned(enum_id);
2176 assert_eq!(pool.get_enum_by_name(name), Some(expected));
2177 }
2178
2179 #[test]
2180 fn test_pool_get_array() {
2181 let pool = TypeInternPool::new();
2182
2183 assert!(pool.get_array(InternedType::I32, 5).is_none());
2184
2185 let arr = pool.intern_array(InternedType::I32, 5);
2186 assert_eq!(pool.get_array(InternedType::I32, 5), Some(arr));
2187 assert!(pool.get_array(InternedType::I32, 10).is_none());
2188 }
2189
2190 #[test]
2191 fn test_pool_get_type_data() {
2192 let pool = TypeInternPool::new();
2193 let interner = ThreadedRodeo::default();
2194
2195 assert!(pool.get(InternedType::I32).is_none());
2197
2198 let struct_name = interner.get_or_intern("Point");
2200 let struct_def = StructDef {
2201 name: "Point".to_string(),
2202 fields: vec![],
2203 posture: Posture::Affine,
2204 is_clone: false,
2205 thread_safety: gruel_builtins::ThreadSafety::Sync,
2206 destructor: None,
2207 is_builtin: false,
2208 is_pub: false,
2209 file_id: gruel_util::FileId::DEFAULT,
2210 is_c_layout: false,
2211 };
2212 let (struct_id, _) = pool.register_struct(struct_name, struct_def);
2213 let struct_ty = pool.struct_id_to_interned(struct_id);
2214
2215 let data = pool.get(struct_ty).expect("should get struct data");
2217 assert!(matches!(data, TypeData::Struct(_)));
2218
2219 let arr_ty = pool.intern_array(InternedType::I32, 10);
2221 let arr_data = pool.get(arr_ty).expect("should get array data");
2222 match arr_data {
2223 TypeData::Array { element, len } => {
2224 assert_eq!(element, InternedType::I32);
2225 assert_eq!(len, 10);
2226 }
2227 _ => panic!("expected array data"),
2228 }
2229 }
2230
2231 #[test]
2232 fn test_pool_type_checks() {
2233 let pool = TypeInternPool::new();
2234 let interner = ThreadedRodeo::default();
2235
2236 let struct_name = interner.get_or_intern("Point");
2237 let struct_def = StructDef {
2238 name: "Point".to_string(),
2239 fields: vec![],
2240 posture: Posture::Affine,
2241 is_clone: false,
2242 thread_safety: gruel_builtins::ThreadSafety::Sync,
2243 destructor: None,
2244 is_builtin: false,
2245 is_pub: false,
2246 file_id: gruel_util::FileId::DEFAULT,
2247 is_c_layout: false,
2248 };
2249 let (struct_id, _) = pool.register_struct(struct_name, struct_def);
2250 let struct_ty = pool.struct_id_to_interned(struct_id);
2251
2252 let enum_name = interner.get_or_intern("Color");
2253 let enum_def = EnumDef {
2254 name: "Color".to_string(),
2255 variants: vec![EnumVariantDef::unit("Red")],
2256 posture: Posture::Affine,
2257 thread_safety: gruel_builtins::ThreadSafety::Sync,
2258 is_pub: false,
2259 file_id: gruel_util::FileId::DEFAULT,
2260 destructor: None,
2261 is_c_layout: false,
2262 };
2263 let (enum_id, _) = pool.register_enum(enum_name, enum_def);
2264 let enum_ty = pool.enum_id_to_interned(enum_id);
2265
2266 let array_ty = pool.intern_array(InternedType::I32, 5);
2267
2268 assert!(pool.is_struct(struct_ty));
2270 assert!(!pool.is_struct(enum_ty));
2271 assert!(!pool.is_struct(array_ty));
2272 assert!(!pool.is_struct(InternedType::I32));
2273
2274 assert!(!pool.is_enum(struct_ty));
2276 assert!(pool.is_enum(enum_ty));
2277 assert!(!pool.is_enum(array_ty));
2278 assert!(!pool.is_enum(InternedType::I32));
2279
2280 assert!(!pool.is_array(struct_ty));
2282 assert!(!pool.is_array(enum_ty));
2283 assert!(pool.is_array(array_ty));
2284 assert!(!pool.is_array(InternedType::I32));
2285 }
2286
2287 #[test]
2288 fn test_pool_get_struct_def() {
2289 let pool = TypeInternPool::new();
2290 let interner = ThreadedRodeo::default();
2291
2292 let name = interner.get_or_intern("Point");
2293 let def = StructDef {
2294 name: "Point".to_string(),
2295 fields: vec![],
2296 posture: Posture::Copy,
2297 is_clone: false,
2298 thread_safety: gruel_builtins::ThreadSafety::Sync,
2299 destructor: None,
2300 is_builtin: false,
2301 is_pub: false,
2302 file_id: gruel_util::FileId::DEFAULT,
2303 is_c_layout: false,
2304 };
2305 let (struct_id, _) = pool.register_struct(name, def.clone());
2306
2307 let retrieved = pool.struct_def(struct_id);
2309 assert_eq!(retrieved.name, def.name);
2310 assert_eq!(retrieved.posture, def.posture);
2311
2312 let interned = pool.struct_id_to_interned(struct_id);
2314 let retrieved2 = pool
2315 .get_struct_def(interned)
2316 .expect("should get struct def");
2317 assert_eq!(retrieved2.name, def.name);
2318
2319 let array_ty = pool.intern_array(InternedType::I32, 5);
2321 assert!(pool.get_struct_def(array_ty).is_none());
2322 assert!(pool.get_struct_def(InternedType::I32).is_none());
2323 }
2324
2325 #[test]
2326 fn test_pool_get_enum_def() {
2327 let pool = TypeInternPool::new();
2328 let interner = ThreadedRodeo::default();
2329
2330 let name = interner.get_or_intern("Status");
2331 let def = EnumDef {
2332 name: "Status".to_string(),
2333 variants: vec![EnumVariantDef::unit("A"), EnumVariantDef::unit("B")],
2334 posture: Posture::Affine,
2335 thread_safety: gruel_builtins::ThreadSafety::Sync,
2336 is_pub: false,
2337 file_id: gruel_util::FileId::DEFAULT,
2338 destructor: None,
2339 is_c_layout: false,
2340 };
2341 let (enum_id, _) = pool.register_enum(name, def.clone());
2342
2343 let retrieved = pool.enum_def(enum_id);
2345 assert_eq!(retrieved.name, def.name);
2346 assert_eq!(retrieved.variants.len(), 2);
2347
2348 let interned = pool.enum_id_to_interned(enum_id);
2350 let retrieved2 = pool.get_enum_def(interned).expect("should get enum def");
2351 assert_eq!(retrieved2.name, def.name);
2352
2353 let array_ty = pool.intern_array(InternedType::I32, 5);
2355 assert!(pool.get_enum_def(array_ty).is_none());
2356 assert!(pool.get_enum_def(InternedType::I32).is_none());
2357 }
2358
2359 #[test]
2360 fn test_pool_get_array_info() {
2361 let pool = TypeInternPool::new();
2362
2363 let array_ty = pool.intern_array(InternedType::I64, 100);
2364 let (element, len) = pool
2365 .get_array_info(array_ty)
2366 .expect("should get array info");
2367 assert_eq!(element, InternedType::I64);
2368 assert_eq!(len, 100);
2369
2370 let interner = ThreadedRodeo::default();
2372 let name = interner.get_or_intern("X");
2373 let def = StructDef {
2374 name: "X".to_string(),
2375 fields: vec![],
2376 posture: Posture::Affine,
2377 is_clone: false,
2378 thread_safety: gruel_builtins::ThreadSafety::Sync,
2379 destructor: None,
2380 is_builtin: false,
2381 is_pub: false,
2382 file_id: gruel_util::FileId::DEFAULT,
2383 is_c_layout: false,
2384 };
2385 let (struct_id, _) = pool.register_struct(name, def);
2386 let struct_ty = pool.struct_id_to_interned(struct_id);
2387 assert!(pool.get_array_info(struct_ty).is_none());
2388 assert!(pool.get_array_info(InternedType::I32).is_none());
2389 }
2390
2391 #[test]
2392 fn test_pool_stats() {
2393 let pool = TypeInternPool::new();
2394 let interner = ThreadedRodeo::default();
2395
2396 let stats = pool.stats();
2397 assert_eq!(stats.struct_count, 0);
2398 assert_eq!(stats.enum_count, 0);
2399 assert_eq!(stats.array_count, 0);
2400 assert_eq!(stats.total, 0);
2401
2402 let s1 = interner.get_or_intern("S1");
2404 let s2 = interner.get_or_intern("S2");
2405 let e1 = interner.get_or_intern("E1");
2406
2407 let def = StructDef {
2408 name: "S1".to_string(),
2409 fields: vec![],
2410 posture: Posture::Affine,
2411 is_clone: false,
2412 thread_safety: gruel_builtins::ThreadSafety::Sync,
2413 destructor: None,
2414 is_builtin: false,
2415 is_pub: false,
2416 file_id: gruel_util::FileId::DEFAULT,
2417 is_c_layout: false,
2418 };
2419 pool.register_struct(s1, def.clone());
2420 pool.register_struct(
2421 s2,
2422 StructDef {
2423 name: "S2".to_string(),
2424 ..def
2425 },
2426 );
2427
2428 pool.register_enum(
2429 e1,
2430 EnumDef {
2431 name: "E1".to_string(),
2432 variants: vec![],
2433 posture: Posture::Affine,
2434 thread_safety: gruel_builtins::ThreadSafety::Sync,
2435 is_pub: false,
2436 file_id: gruel_util::FileId::DEFAULT,
2437 destructor: None,
2438 is_c_layout: false,
2439 },
2440 );
2441
2442 pool.intern_array(InternedType::I32, 5);
2443 pool.intern_array(InternedType::I32, 10);
2444 pool.intern_array(InternedType::BOOL, 3);
2445
2446 let stats = pool.stats();
2447 assert_eq!(stats.struct_count, 2);
2448 assert_eq!(stats.enum_count, 1);
2449 assert_eq!(stats.array_count, 3);
2450 assert_eq!(stats.total, 6);
2451 }
2452
2453 #[test]
2454 fn test_pool_nested_arrays() {
2455 let pool = TypeInternPool::new();
2456
2457 let inner = pool.intern_array(InternedType::I32, 3);
2459
2460 let outer = pool.intern_array(inner, 4);
2462
2463 let (outer_elem, outer_len) = pool.get_array_info(outer).expect("outer array info");
2465 assert_eq!(outer_elem, inner);
2466 assert_eq!(outer_len, 4);
2467
2468 let (inner_elem, inner_len) = pool.get_array_info(inner).expect("inner array info");
2469 assert_eq!(inner_elem, InternedType::I32);
2470 assert_eq!(inner_len, 3);
2471 }
2472
2473 #[test]
2474 fn test_pool_type_to_interned() {
2475 let pool = TypeInternPool::new();
2476
2477 assert_eq!(pool.type_to_interned(Type::I8), Some(InternedType::I8));
2479 assert_eq!(pool.type_to_interned(Type::I16), Some(InternedType::I16));
2480 assert_eq!(pool.type_to_interned(Type::I32), Some(InternedType::I32));
2481 assert_eq!(pool.type_to_interned(Type::I64), Some(InternedType::I64));
2482 assert_eq!(pool.type_to_interned(Type::U8), Some(InternedType::U8));
2483 assert_eq!(pool.type_to_interned(Type::U16), Some(InternedType::U16));
2484 assert_eq!(pool.type_to_interned(Type::U32), Some(InternedType::U32));
2485 assert_eq!(pool.type_to_interned(Type::U64), Some(InternedType::U64));
2486 assert_eq!(pool.type_to_interned(Type::BOOL), Some(InternedType::BOOL));
2487 assert_eq!(pool.type_to_interned(Type::UNIT), Some(InternedType::UNIT));
2488 assert_eq!(
2489 pool.type_to_interned(Type::NEVER),
2490 Some(InternedType::NEVER)
2491 );
2492 assert_eq!(
2493 pool.type_to_interned(Type::ERROR),
2494 Some(InternedType::ERROR)
2495 );
2496
2497 assert!(
2499 pool.type_to_interned(Type::new_struct(crate::types::StructId(0)))
2500 .is_none()
2501 );
2502 assert!(
2503 pool.type_to_interned(Type::new_enum(crate::types::EnumId(0)))
2504 .is_none()
2505 );
2506 assert!(
2507 pool.type_to_interned(Type::new_array(crate::types::ArrayTypeId(0)))
2508 .is_none()
2509 );
2510 }
2511
2512 #[test]
2513 fn test_pool_interned_to_type() {
2514 let pool = TypeInternPool::new();
2515
2516 assert_eq!(pool.interned_to_type(InternedType::I8), Some(Type::I8));
2518 assert_eq!(pool.interned_to_type(InternedType::I16), Some(Type::I16));
2519 assert_eq!(pool.interned_to_type(InternedType::I32), Some(Type::I32));
2520 assert_eq!(pool.interned_to_type(InternedType::I64), Some(Type::I64));
2521 assert_eq!(pool.interned_to_type(InternedType::U8), Some(Type::U8));
2522 assert_eq!(pool.interned_to_type(InternedType::U16), Some(Type::U16));
2523 assert_eq!(pool.interned_to_type(InternedType::U32), Some(Type::U32));
2524 assert_eq!(pool.interned_to_type(InternedType::U64), Some(Type::U64));
2525 assert_eq!(pool.interned_to_type(InternedType::BOOL), Some(Type::BOOL));
2526 assert_eq!(pool.interned_to_type(InternedType::UNIT), Some(Type::UNIT));
2527 assert_eq!(
2528 pool.interned_to_type(InternedType::NEVER),
2529 Some(Type::NEVER)
2530 );
2531 assert_eq!(
2532 pool.interned_to_type(InternedType::ERROR),
2533 Some(Type::ERROR)
2534 );
2535
2536 assert!(
2538 pool.interned_to_type(InternedType::from_pool_index(0))
2539 .is_none()
2540 );
2541 }
2542
2543 #[test]
2548 fn test_pool_concurrent_access() {
2549 use std::sync::Arc;
2550 use std::thread;
2551
2552 let pool = Arc::new(TypeInternPool::new());
2553 let interner = Arc::new(ThreadedRodeo::default());
2554
2555 let names: Vec<Spur> = (0..100)
2557 .map(|i| interner.get_or_intern(format!("Type{}", i)))
2558 .collect();
2559
2560 let handles: Vec<_> = (0..10)
2561 .map(|thread_id| {
2562 let pool = Arc::clone(&pool);
2563 let names = names.clone();
2564 thread::spawn(move || {
2565 for i in 0..10 {
2567 let idx = thread_id * 10 + i;
2568 let name = names[idx];
2569 let def = StructDef {
2570 name: format!("Type{}", idx),
2571 fields: vec![],
2572 posture: Posture::Affine,
2573 is_clone: false,
2574 thread_safety: gruel_builtins::ThreadSafety::Sync,
2575 destructor: None,
2576 is_builtin: false,
2577 is_pub: false,
2578 file_id: gruel_util::FileId::DEFAULT,
2579 is_c_layout: false,
2580 };
2581 pool.register_struct(name, def);
2582 }
2583 })
2584 })
2585 .collect();
2586
2587 for handle in handles {
2588 handle.join().expect("thread panicked");
2589 }
2590
2591 assert_eq!(pool.len(), 100);
2593
2594 for name in &names {
2596 assert!(pool.get_struct_by_name(*name).is_some());
2597 }
2598 }
2599
2600 #[test]
2601 fn test_pool_concurrent_array_interning() {
2602 use std::sync::Arc;
2603 use std::thread;
2604
2605 let pool = Arc::new(TypeInternPool::new());
2606
2607 let handles: Vec<_> = (0..10)
2609 .map(|_| {
2610 let pool = Arc::clone(&pool);
2611 thread::spawn(move || pool.intern_array(InternedType::I32, 42))
2612 })
2613 .collect();
2614
2615 let results: Vec<_> = handles
2616 .into_iter()
2617 .map(|h| h.join().expect("thread panicked"))
2618 .collect();
2619
2620 let first = results[0];
2622 for result in &results {
2623 assert_eq!(*result, first);
2624 }
2625
2626 assert_eq!(pool.stats().array_count, 1);
2628 }
2629
2630 #[test]
2635 fn test_pool_reserve_and_complete_struct() {
2636 let pool = TypeInternPool::new();
2637 let interner = ThreadedRodeo::default();
2638
2639 let struct_id = pool.reserve_struct_id();
2641 assert_eq!(struct_id.pool_index(), 0);
2642 assert_eq!(pool.len(), 1); let name_str = format!("__anon_struct_{}", struct_id.0);
2646 let name = interner.get_or_intern(&name_str);
2647
2648 let def = StructDef {
2649 name: name_str.clone(),
2650 fields: vec![],
2651 posture: Posture::Affine,
2652 is_clone: false,
2653 thread_safety: gruel_builtins::ThreadSafety::Sync,
2654 destructor: None,
2655 is_builtin: false,
2656 is_pub: false,
2657 file_id: gruel_util::FileId::DEFAULT,
2658 is_c_layout: false,
2659 };
2660
2661 pool.complete_struct_registration(struct_id, name, def);
2663
2664 assert_eq!(pool.len(), 1); assert!(pool.get_struct_by_name(name).is_some());
2667
2668 let retrieved = pool.struct_def(struct_id);
2670 assert_eq!(retrieved.name, name_str);
2671 }
2672
2673 #[test]
2674 fn test_pool_reserve_multiple_structs() {
2675 let pool = TypeInternPool::new();
2676 let interner = ThreadedRodeo::default();
2677
2678 let id1 = pool.reserve_struct_id();
2680 let id2 = pool.reserve_struct_id();
2681 let id3 = pool.reserve_struct_id();
2682
2683 assert_eq!(id1.pool_index(), 0);
2684 assert_eq!(id2.pool_index(), 1);
2685 assert_eq!(id3.pool_index(), 2);
2686 assert_eq!(pool.len(), 3);
2687
2688 for (i, id) in [(2, id3), (1, id2), (0, id1)] {
2690 let name_str = format!("__anon_struct_{}", i);
2691 let name = interner.get_or_intern(&name_str);
2692 let def = StructDef {
2693 name: name_str,
2694 fields: vec![],
2695 posture: Posture::Affine,
2696 is_clone: false,
2697 thread_safety: gruel_builtins::ThreadSafety::Sync,
2698 destructor: None,
2699 is_builtin: false,
2700 is_pub: false,
2701 file_id: gruel_util::FileId::DEFAULT,
2702 is_c_layout: false,
2703 };
2704 pool.complete_struct_registration(id, name, def);
2705 }
2706
2707 assert_eq!(pool.stats().struct_count, 3);
2709 }
2710
2711 fn assert_send_sync<T: Send + Sync>() {}
2713
2714 #[test]
2715 fn test_pool_is_send_sync() {
2716 assert_send_sync::<TypeInternPool>();
2717 }
2718
2719 #[test]
2726 fn thread_safety_primitives_are_sync() {
2727 use gruel_builtins::ThreadSafety;
2728 let pool = TypeInternPool::new();
2729 for ty in [
2730 Type::I8,
2731 Type::I16,
2732 Type::I32,
2733 Type::I64,
2734 Type::U8,
2735 Type::U16,
2736 Type::U32,
2737 Type::U64,
2738 Type::ISIZE,
2739 Type::USIZE,
2740 Type::F16,
2741 Type::F32,
2742 Type::F64,
2743 Type::BOOL,
2744 Type::UNIT,
2745 Type::NEVER,
2746 ] {
2747 assert_eq!(
2748 pool.is_thread_safety_type(ty),
2749 ThreadSafety::Sync,
2750 "{:?} should be Sync",
2751 ty
2752 );
2753 }
2754 }
2755
2756 #[test]
2759 fn thread_safety_raw_ptr_is_unsend() {
2760 use gruel_builtins::ThreadSafety;
2761 let pool = TypeInternPool::new();
2762 let ptr = pool.intern_ptr_const_from_type(Type::I32);
2763 let mutptr = pool.intern_ptr_mut_from_type(Type::U8);
2764 assert_eq!(
2765 pool.is_thread_safety_type(Type::new_ptr_const(ptr)),
2766 ThreadSafety::Unsend
2767 );
2768 assert_eq!(
2769 pool.is_thread_safety_type(Type::new_ptr_mut(mutptr)),
2770 ThreadSafety::Unsend
2771 );
2772 }
2773
2774 #[test]
2777 fn thread_safety_array_of_ptr_is_unsend() {
2778 use gruel_builtins::ThreadSafety;
2779 let pool = TypeInternPool::new();
2780 let mutptr_ty = Type::new_ptr_mut(pool.intern_ptr_mut_from_type(Type::I32));
2781 let arr_id = pool.intern_array_from_type(mutptr_ty, 4);
2782 assert_eq!(
2783 pool.is_thread_safety_type(Type::new_array(arr_id)),
2784 ThreadSafety::Unsend
2785 );
2786 }
2787
2788 #[test]
2790 fn thread_safety_array_of_i32_is_sync() {
2791 use gruel_builtins::ThreadSafety;
2792 let pool = TypeInternPool::new();
2793 let arr_id = pool.intern_array_from_type(Type::I32, 8);
2794 assert_eq!(
2795 pool.is_thread_safety_type(Type::new_array(arr_id)),
2796 ThreadSafety::Sync
2797 );
2798 }
2799
2800 #[test]
2803 fn thread_safety_vec_of_ptr_is_unsend() {
2804 use gruel_builtins::ThreadSafety;
2805 let pool = TypeInternPool::new();
2806 let mutptr_ty = Type::new_ptr_mut(pool.intern_ptr_mut_from_type(Type::I32));
2807 let vec_id = pool.intern_vec_from_type(mutptr_ty);
2808 assert_eq!(
2809 pool.is_thread_safety_type(Type::new_vec(vec_id)),
2810 ThreadSafety::Unsend
2811 );
2812 }
2813
2814 #[test]
2819 fn thread_safety_struct_with_ptr_field_infers_unsend() {
2820 use crate::types::StructField;
2821 use gruel_builtins::ThreadSafety;
2822
2823 let pool = TypeInternPool::new();
2824 let interner = ThreadedRodeo::default();
2825 let mutptr_ty = Type::new_ptr_mut(pool.intern_ptr_mut_from_type(Type::U8));
2826
2827 let inferred = [Type::I32, mutptr_ty, Type::USIZE]
2830 .iter()
2831 .map(|t| pool.is_thread_safety_type(*t))
2832 .min()
2833 .unwrap();
2834 assert_eq!(inferred, ThreadSafety::Unsend);
2835
2836 let name = interner.get_or_intern("Buf");
2837 let def = StructDef {
2838 name: "Buf".to_string(),
2839 fields: vec![
2840 StructField {
2841 name: "len".into(),
2842 ty: Type::USIZE,
2843 is_pub: false,
2844 },
2845 StructField {
2846 name: "ptr".into(),
2847 ty: mutptr_ty,
2848 is_pub: false,
2849 },
2850 ],
2851 posture: Posture::Affine,
2852 is_clone: false,
2853 thread_safety: inferred,
2854 destructor: None,
2855 is_builtin: false,
2856 is_pub: false,
2857 file_id: gruel_util::FileId::DEFAULT,
2858 is_c_layout: false,
2859 };
2860 let (sid, _) = pool.register_struct(name, def);
2861 assert_eq!(
2862 pool.is_thread_safety_type(Type::new_struct(sid)),
2863 ThreadSafety::Unsend
2864 );
2865 }
2866
2867 #[test]
2870 fn thread_safety_nested_struct_with_ptr_is_unsend() {
2871 use crate::types::StructField;
2872 use gruel_builtins::ThreadSafety;
2873
2874 let pool = TypeInternPool::new();
2875 let interner = ThreadedRodeo::default();
2876 let mutptr_ty = Type::new_ptr_mut(pool.intern_ptr_mut_from_type(Type::U8));
2877
2878 let inner_name = interner.get_or_intern("Inner");
2880 let inner_def = StructDef {
2881 name: "Inner".to_string(),
2882 fields: vec![StructField {
2883 name: "ptr".into(),
2884 ty: mutptr_ty,
2885 is_pub: false,
2886 }],
2887 posture: Posture::Affine,
2888 is_clone: false,
2889 thread_safety: ThreadSafety::Unsend,
2890 destructor: None,
2891 is_builtin: false,
2892 is_pub: false,
2893 file_id: gruel_util::FileId::DEFAULT,
2894 is_c_layout: false,
2895 };
2896 let (inner_sid, _) = pool.register_struct(inner_name, inner_def);
2897 let inner_ty = Type::new_struct(inner_sid);
2898
2899 let outer_inferred = [Type::I32, inner_ty]
2901 .iter()
2902 .map(|t| pool.is_thread_safety_type(*t))
2903 .min()
2904 .unwrap();
2905 assert_eq!(outer_inferred, ThreadSafety::Unsend);
2906
2907 let outer_name = interner.get_or_intern("Outer");
2908 let outer_def = StructDef {
2909 name: "Outer".to_string(),
2910 fields: vec![
2911 StructField {
2912 name: "tag".into(),
2913 ty: Type::I32,
2914 is_pub: false,
2915 },
2916 StructField {
2917 name: "inner".into(),
2918 ty: inner_ty,
2919 is_pub: false,
2920 },
2921 ],
2922 posture: Posture::Affine,
2923 is_clone: false,
2924 thread_safety: outer_inferred,
2925 destructor: None,
2926 is_builtin: false,
2927 is_pub: false,
2928 file_id: gruel_util::FileId::DEFAULT,
2929 is_c_layout: false,
2930 };
2931 let (outer_sid, _) = pool.register_struct(outer_name, outer_def);
2932 assert_eq!(
2933 pool.is_thread_safety_type(Type::new_struct(outer_sid)),
2934 ThreadSafety::Unsend
2935 );
2936 }
2937
2938 #[test]
2941 fn thread_safety_ref_inherits_referent() {
2942 use gruel_builtins::ThreadSafety;
2943 let pool = TypeInternPool::new();
2944 let mutptr_ty = Type::new_ptr_mut(pool.intern_ptr_mut_from_type(Type::U8));
2945 let ref_id = pool.intern_ref_from_type(mutptr_ty);
2946 assert_eq!(
2947 pool.is_thread_safety_type(Type::new_ref(ref_id)),
2948 ThreadSafety::Unsend
2949 );
2950
2951 let ref_i32 = pool.intern_ref_from_type(Type::I32);
2952 assert_eq!(
2953 pool.is_thread_safety_type(Type::new_ref(ref_i32)),
2954 ThreadSafety::Sync
2955 );
2956 }
2957}