1pub mod ffi;
13
14use std::ffi::c_void;
15use std::{
16 alloc::Layout,
17 borrow::Cow,
18 collections::VecDeque,
19 fmt::{self, Formatter},
20 fmt::{Debug, Display},
21 hash::{Hash, Hasher},
22 ops::Deref,
23 ptr::NonNull,
24 sync::{atomic::AtomicUsize, atomic::Ordering, Arc, Once},
25};
26
27use itertools::izip;
28use once_cell::sync::Lazy;
29use parking_lot::{lock_api::MutexGuard, Mutex, RawMutex, RwLock};
30
31use mun_abi::{self as abi, static_type_map::StaticTypeMap};
32
33use crate::{type_table::TypeTable, TryFromAbiError};
34
35static GLOBAL_TYPE_STORE: Lazy<Arc<TypeDataStore>> = Lazy::new(Default::default);
36
37#[derive(Default)]
44struct TypeDataStore {
45 types: Mutex<VecDeque<Box<TypeData>>>,
46}
47
48#[derive(Clone, Debug)]
50pub struct TypeCollectionStats {
51 pub collected_types: usize,
52 pub remaining_types: usize,
53}
54
55#[derive(Eq, PartialEq)]
59enum Mark {
60 Used,
61 Unused,
62 Initializing,
63}
64
65impl TypeDataStore {
66 pub fn collect_garbage(&self) -> TypeCollectionStats {
68 let mut lock = self.types.lock();
69
70 let mut queue = VecDeque::new();
72 for ty in lock.iter_mut() {
73 if ty.mark != Mark::Initializing {
74 if ty.external_references.load(Ordering::Acquire) > 0 {
75 ty.mark = Mark::Used;
76 queue.push_back(unsafe {
77 NonNull::new_unchecked(Box::as_mut(ty) as *mut TypeData)
78 });
79 } else {
80 ty.mark = Mark::Unused
81 };
82 }
83 }
84
85 while let Some(ty) = queue.pop_back() {
87 let ty = unsafe { ty.as_ref() };
88 match &ty.data {
89 TypeDataKind::Struct(s) => {
90 for field in s.fields.iter() {
91 let mut field_ty = field.type_info;
92 let field_ty = unsafe { field_ty.as_mut() };
93 if field_ty.mark == Mark::Unused {
94 field_ty.mark = Mark::Used;
95 queue.push_back(field.type_info);
96 }
97 }
98 }
99 TypeDataKind::Pointer(p) => {
100 let mut pointee = p.pointee;
101 let pointee = unsafe { pointee.as_mut() };
102 if pointee.mark == Mark::Unused {
103 pointee.mark = Mark::Used;
104 queue.push_back(p.pointee);
105 }
106 }
107 TypeDataKind::Array(a) => {
108 let mut element_ty = a.element_ty;
109 let element_ty = unsafe { element_ty.as_mut() };
110 if element_ty.mark == Mark::Unused {
111 element_ty.mark = Mark::Used;
112 queue.push_back(a.element_ty);
113 }
114 }
115 TypeDataKind::Primitive(_) | TypeDataKind::Uninitialized => {}
116 }
117
118 for indirection in [
122 &ty.mutable_pointer_type,
123 &ty.immutable_pointer_type,
124 &ty.array_type,
125 ] {
126 let read_lock = indirection.read();
127 if let &Some(mut indirection_ref) = read_lock.deref() {
128 let reference = unsafe { indirection_ref.as_mut() };
129 if reference.mark == Mark::Unused {
130 reference.mark = Mark::Used;
131 queue.push_back(indirection_ref);
132 }
133 }
134 }
135 }
136
137 let mut types_removed = 0;
139 let mut index = 0;
140 while index < lock.len() {
141 let ty = &(&*lock)[index];
142 if ty.mark == Mark::Unused {
143 lock.swap_remove_back(index);
144 types_removed += 1;
145 } else {
146 index += 1;
147 }
148 }
149
150 TypeCollectionStats {
151 collected_types: types_removed,
152 remaining_types: lock.len(),
153 }
154 }
155
156 pub fn try_from_abi<'abi>(
159 self: &Arc<Self>,
160 definitions: impl Iterator<Item = &'abi abi::TypeDefinition<'abi>>,
161 mut type_table: TypeTable,
162 ) -> Result<(TypeTable, Vec<Type>), TryFromAbiError<'abi>> {
163 let mut entries = self.types.lock();
165
166 let mut types = Vec::new();
168 let mut definition_and_type = Vec::with_capacity(definitions.size_hint().0);
169 for type_def in definitions {
170 let ty = self.allocate_inner(
171 type_def.name().to_owned(),
172 Layout::from_size_align(type_def.size_in_bytes(), type_def.alignment())
173 .expect("invalid abi type definition layout"),
174 TypeDataKind::Uninitialized,
175 &mut entries,
176 );
177 type_table.insert_concrete_type(*type_def.as_concrete(), ty.clone());
178 types.push(ty.clone());
179 definition_and_type.push((type_def, ty));
180 }
181
182 std::mem::drop(entries);
183
184 for (type_def, mut ty) in definition_and_type {
186 let inner_ty = unsafe { ty.inner.as_mut() };
189 let type_data = match &type_def.data {
190 abi::TypeDefinitionData::Struct(s) => {
191 StructData::try_from_abi(s, &type_table)?.into()
192 }
193 };
194 inner_ty.data = type_data;
195
196 inner_ty.mark = Mark::Used;
200 }
201
202 Ok((type_table, types))
203 }
204
205 fn allocate_inner(
206 self: &Arc<Self>,
207 name: impl Into<String>,
208 layout: Layout,
209 data: TypeDataKind,
210 entries: &mut MutexGuard<'_, RawMutex, VecDeque<Box<TypeData>>>,
211 ) -> Type {
212 entries.push_back(Box::new(TypeData {
213 name: name.into(),
214 layout,
215 data,
216 external_references: AtomicUsize::new(0),
217 immutable_pointer_type: Default::default(),
218 mutable_pointer_type: Default::default(),
219 array_type: Default::default(),
220 mark: Mark::Initializing,
221 }));
222
223 let entry = unsafe {
227 NonNull::new_unchecked(
228 entries.back().expect("didnt insert").deref() as *const TypeData as *mut _,
229 )
230 };
231
232 unsafe { Type::new_unchecked(entry, self.clone()) }
234 }
235
236 pub fn allocate(
238 self: &Arc<Self>,
239 name: impl Into<String>,
240 layout: Layout,
241 data: TypeDataKind,
242 ) -> Type {
243 let mut entries = self.types.lock();
244 let mut ty = self.allocate_inner(name, layout, data, &mut entries);
245 unsafe { ty.inner.as_mut() }.mark = Mark::Used;
246 ty
247 }
248
249 pub fn allocate_uninitialized(
251 self: &Arc<Self>,
252 name: impl Into<String>,
253 layout: Layout,
254 data: TypeDataKind,
255 ) -> Type {
256 let mut entries = self.types.lock();
257 self.allocate_inner(name, layout, data, &mut entries)
258 }
259}
260
261pub struct Type {
264 inner: NonNull<TypeData>,
265
266 store: Arc<TypeDataStore>,
275}
276
277impl Type {
278 unsafe fn new_unchecked(mut inner: NonNull<TypeData>, store: Arc<TypeDataStore>) -> Self {
285 inner
287 .as_mut()
288 .external_references
289 .fetch_add(1, Ordering::AcqRel);
290
291 Self { inner, store }
292 }
293}
294
295unsafe impl Send for Type {}
297unsafe impl Sync for Type {}
298
299impl Debug for Type {
300 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
301 std::fmt::Display::fmt(self, f)
302 }
303}
304
305impl Display for Type {
306 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
307 match self.kind() {
308 TypeKind::Primitive(_) => std::fmt::Display::fmt(self.name(), f),
309 TypeKind::Struct(s) => std::fmt::Display::fmt(&s, f),
310 TypeKind::Pointer(p) => std::fmt::Display::fmt(&p, f),
311 TypeKind::Array(a) => std::fmt::Display::fmt(&a, f),
312 }
313 }
314}
315
316impl Clone for Type {
317 fn clone(&self) -> Self {
318 self.inner()
319 .external_references
320 .fetch_add(1, Ordering::AcqRel);
321
322 Self {
323 store: self.store.clone(),
324 inner: self.inner,
325 }
326 }
327}
328
329impl Drop for Type {
330 fn drop(&mut self) {
331 self.inner()
332 .external_references
333 .fetch_sub(1, Ordering::Release);
334 }
335}
336
337impl PartialEq for Type {
338 fn eq(&self, other: &Self) -> bool {
339 self.inner() == other.inner()
340 }
341}
342
343impl Eq for Type {}
344impl Hash for Type {
345 fn hash<H: Hasher>(&self, state: &mut H) {
346 self.inner().hash(state)
347 }
348}
349
350pub struct TypeData {
352 name: String,
354
355 layout: Layout,
357
358 data: TypeDataKind,
360
361 external_references: AtomicUsize,
367
368 immutable_pointer_type: RwLock<Option<NonNull<TypeData>>>,
370
371 mutable_pointer_type: RwLock<Option<NonNull<TypeData>>>,
373
374 array_type: RwLock<Option<NonNull<TypeData>>>,
376
377 mark: Mark,
379}
380
381impl TypeData {
382 fn pointer_type(&self, mutable: bool, store: &Arc<TypeDataStore>) -> Type {
384 let cache_key = if mutable {
385 &self.mutable_pointer_type
386 } else {
387 &self.immutable_pointer_type
388 };
389
390 {
391 let read_lock = cache_key.read();
392
393 if let Some(ty) = read_lock.deref().as_ref() {
395 return Type {
396 inner: *ty,
397 store: store.clone(),
398 };
399 }
400 }
401
402 let mut ty = store.allocate_uninitialized(
404 format!("*{} {}", if mutable { "mut" } else { "const" }, self.name),
405 Layout::new::<*const std::ffi::c_void>(),
406 PointerData {
407 pointee: self.into(),
408 mutable,
409 }
410 .into(),
411 );
412
413 let mut write_lock = cache_key.write();
415
416 let inner = unsafe { ty.inner.as_mut() };
418
419 if let Some(element_ty) = write_lock.deref() {
421 inner.mark = Mark::Used;
422 return Type {
423 inner: *element_ty,
424 store: store.clone(),
425 };
426 }
427
428 *write_lock = Some(ty.inner);
432 inner.mark = Mark::Used;
433
434 ty
435 }
436
437 fn array_type(&self, store: &Arc<TypeDataStore>) -> Type {
439 let cache_key = &self.array_type;
440
441 {
442 let read_lock = cache_key.read();
443
444 if let Some(ty) = read_lock.deref().as_ref() {
446 return Type {
447 inner: *ty,
448 store: store.clone(),
449 };
450 }
451 }
452
453 let mut ty = store.allocate_uninitialized(
455 format!("[{}]", self.name),
456 Layout::new::<*const std::ffi::c_void>(),
457 ArrayData {
458 element_ty: self.into(),
459 }
460 .into(),
461 );
462
463 let mut write_lock = cache_key.write();
465
466 let inner = unsafe { ty.inner.as_mut() };
468
469 if let Some(element_ty) = write_lock.deref() {
471 inner.mark = Mark::Used;
472 return Type {
473 inner: *element_ty,
474 store: store.clone(),
475 };
476 }
477
478 *write_lock = Some(ty.inner);
482 inner.mark = Mark::Used;
483
484 ty
485 }
486}
487
488impl PartialEq for TypeData {
489 fn eq(&self, other: &Self) -> bool {
490 self.name == other.name && self.layout == other.layout && self.data == other.data
491 }
492}
493
494impl Eq for TypeData {}
495
496unsafe impl Send for TypeData {}
497unsafe impl Sync for TypeData {}
498
499#[derive(Clone, Debug, Eq, PartialEq, Hash)]
501enum TypeDataKind {
502 Primitive(abi::Guid),
504 Struct(StructData),
506 Pointer(PointerData),
508 Array(ArrayData),
510 Uninitialized,
513}
514
515#[derive(Copy, Clone)]
516pub enum TypeKind<'t> {
517 Primitive(&'t abi::Guid),
519 Struct(StructType<'t>),
521 Pointer(PointerType<'t>),
523 Array(ArrayType<'t>),
525}
526
527#[derive(Clone, Debug)]
529struct StructData {
530 pub guid: abi::Guid,
532 pub fields: Vec<FieldData>,
534 pub memory_kind: abi::StructMemoryKind,
536}
537
538#[repr(C)]
540#[derive(Copy, Clone)]
541pub struct StructType<'t> {
542 inner: &'t StructData,
543 store: &'t Arc<TypeDataStore>,
544}
545
546impl<'t> StructType<'t> {
547 pub fn guid<'s>(&'s self) -> &'t abi::Guid
549 where
550 't: 's,
551 {
552 &self.inner.guid
553 }
554
555 pub fn memory_kind(&self) -> abi::StructMemoryKind {
557 self.inner.memory_kind
558 }
559
560 pub fn is_value_struct(&self) -> bool {
563 self.memory_kind() == abi::StructMemoryKind::Value
564 }
565
566 pub fn is_gc_struct(&self) -> bool {
568 self.memory_kind() == abi::StructMemoryKind::Gc
569 }
570
571 pub fn fields(&self) -> Fields<'t> {
573 Fields {
574 inner: self.inner,
575 store: self.store,
576 }
577 }
578}
579
580impl<'t> Display for StructType<'t> {
581 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
582 f.write_fmt(format_args!(
583 "struct({}) {{",
584 if self.is_gc_struct() { "gc" } else { "value" },
585 ))?;
586 self.fields().iter().try_for_each(|field| {
587 f.write_fmt(format_args!("{}: {}, ", field.name(), field.ty()))
588 })?;
589 f.write_str("}")
590 }
591}
592
593#[derive(Copy, Clone)]
595pub struct Fields<'t> {
596 inner: &'t StructData,
597 store: &'t Arc<TypeDataStore>,
598}
599
600impl<'t> Fields<'t> {
601 pub fn len(&self) -> usize {
603 self.inner.fields.len()
604 }
605
606 pub fn get(&self, index: usize) -> Option<Field<'t>> {
608 self.inner.fields.get(index).map(|field| Field {
609 inner: field,
610 store: self.store,
611 })
612 }
613
614 pub fn find_by_name(&self, name: impl AsRef<str>) -> Option<Field<'t>> {
616 let field_name = name.as_ref();
617 self.iter().find(|field| field.name() == field_name)
618 }
619
620 pub fn iter(&self) -> FieldsIterator<'t> {
622 FieldsIterator {
623 iter: self.inner.fields.iter(),
624 store: self.store,
625 }
626 }
627}
628
629impl<'t> IntoIterator for Fields<'t> {
630 type Item = Field<'t>;
631 type IntoIter = FieldsIterator<'t>;
632
633 fn into_iter(self) -> Self::IntoIter {
634 FieldsIterator {
635 iter: self.inner.fields.iter(),
636 store: self.store,
637 }
638 }
639}
640
641pub struct FieldsIterator<'t> {
642 iter: std::slice::Iter<'t, FieldData>,
643 store: &'t Arc<TypeDataStore>,
644}
645
646impl<'t> Iterator for FieldsIterator<'t> {
647 type Item = Field<'t>;
648
649 fn next(&mut self) -> Option<Self::Item> {
650 self.iter.next().map(|field| Field {
651 inner: field,
652 store: self.store,
653 })
654 }
655}
656
657#[derive(Clone, Debug, Eq, PartialEq, Hash)]
659struct PointerData {
660 pub pointee: NonNull<TypeData>,
662 pub mutable: bool,
664}
665
666#[derive(Copy, Clone)]
668pub struct PointerType<'t> {
669 inner: &'t PointerData,
670 store: &'t Arc<TypeDataStore>,
671}
672
673impl<'t> PointerType<'t> {
674 pub fn pointee(&self) -> Type {
676 unsafe { Type::new_unchecked(self.inner.pointee, self.store.clone()) }
678 }
679
680 pub fn is_mutable(&self) -> bool {
682 self.inner.mutable
683 }
684
685 pub fn is_immutable(&self) -> bool {
687 !self.inner.mutable
688 }
689}
690
691impl<'t> Display for PointerType<'t> {
692 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
693 f.write_fmt(format_args!(
694 "*{} {}",
695 if self.is_mutable() { "mut" } else { "const" },
696 self.pointee()
697 ))
698 }
699}
700
701impl Hash for StructData {
702 fn hash<H: Hasher>(&self, state: &mut H) {
703 self.guid.hash(state)
704 }
705}
706
707impl PartialEq for StructData {
708 fn eq(&self, other: &Self) -> bool {
709 self.guid == other.guid
710 }
711}
712impl Eq for StructData {}
713
714#[derive(Clone, Debug, Eq, PartialEq, Hash)]
715struct ArrayData {
716 pub element_ty: NonNull<TypeData>,
717}
718
719#[repr(C)]
721#[derive(Copy, Clone)]
722pub struct ArrayType<'t> {
723 inner: &'t ArrayData,
724 store: &'t Arc<TypeDataStore>,
725}
726
727impl<'t> ArrayType<'t> {
728 pub fn element_type(&self) -> Type {
730 unsafe { Type::new_unchecked(self.inner.element_ty, self.store.clone()) }
732 }
733}
734
735impl<'t> Display for ArrayType<'t> {
736 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
737 f.write_str("[")?;
738 std::fmt::Display::fmt(&self.element_type(), f)?;
739 f.write_str("]")
740 }
741}
742
743impl From<StructData> for TypeDataKind {
744 fn from(s: StructData) -> Self {
745 TypeDataKind::Struct(s)
746 }
747}
748
749impl From<PointerData> for TypeDataKind {
750 fn from(p: PointerData) -> Self {
751 TypeDataKind::Pointer(p)
752 }
753}
754
755impl From<ArrayData> for TypeDataKind {
756 fn from(a: ArrayData) -> Self {
757 TypeDataKind::Array(a)
758 }
759}
760
761impl Hash for TypeData {
762 fn hash<H: Hasher>(&self, state: &mut H) {
763 Hash::hash(&self.data, state);
764 }
765}
766
767impl Type {
768 pub fn collect_unreferenced_type_data() -> TypeCollectionStats {
771 GLOBAL_TYPE_STORE.collect_garbage()
772 }
773
774 pub fn new_struct(
776 name: impl Into<String>,
777 layout: Layout,
778 guid: abi::Guid,
779 fields: impl IntoIterator<Item = (String, Type, u16)>,
780 memory_kind: abi::StructMemoryKind,
781 ) -> Type {
782 let fields = fields
783 .into_iter()
784 .map(|(name, ty, offset)| FieldData {
785 name,
786 type_info: ty.inner,
787 offset,
788 })
789 .collect::<Vec<_>>();
790 GLOBAL_TYPE_STORE.allocate(
791 name,
792 layout,
793 StructData {
794 guid,
795 fields,
796 memory_kind,
797 }
798 .into(),
799 )
800 }
801
802 fn inner(&self) -> &TypeData {
804 unsafe { self.inner.as_ref() }
807 }
808
809 pub fn name(&self) -> &str {
811 self.inner().name.as_str()
812 }
813
814 pub fn value_layout(&self) -> Layout {
817 self.inner().layout
818 }
819
820 pub fn reference_layout(&self) -> Layout {
822 if self.is_reference_type() {
823 Layout::new::<*const c_void>()
825 } else {
826 self.value_layout()
827 }
828 }
829
830 pub fn is_reference_type(&self) -> bool {
833 match self.kind() {
834 TypeKind::Primitive(_) | TypeKind::Pointer(_) => false,
835 TypeKind::Array(_) => true,
836 TypeKind::Struct(s) => s.is_gc_struct(),
837 }
838 }
839
840 pub fn is_value_type(&self) -> bool {
843 match self.kind() {
844 TypeKind::Primitive(_) | TypeKind::Pointer(_) => true,
845 TypeKind::Array(_) => false,
846 TypeKind::Struct(s) => s.is_value_struct(),
847 }
848 }
849
850 pub fn equals<T: HasStaticType>(&self) -> bool {
858 T::type_info() == self
859 }
860
861 pub fn is_primitive(&self) -> bool {
863 matches!(self.kind(), TypeKind::Primitive(_))
864 }
865
866 pub fn is_struct(&self) -> bool {
868 matches!(self.kind(), TypeKind::Struct(_))
869 }
870
871 pub fn is_pointer(&self) -> bool {
873 matches!(self.kind(), TypeKind::Pointer(_))
874 }
875
876 pub fn is_array(&self) -> bool {
878 matches!(self.kind(), TypeKind::Array(_))
879 }
880
881 pub fn kind(&self) -> TypeKind<'_> {
883 match &self.inner().data {
884 TypeDataKind::Primitive(guid) => TypeKind::Primitive(guid),
885 TypeDataKind::Struct(s) => TypeKind::Struct(StructType {
886 inner: s,
887 store: &self.store,
888 }),
889 TypeDataKind::Pointer(p) => TypeKind::Pointer(PointerType {
890 inner: p,
891 store: &self.store,
892 }),
893 TypeDataKind::Array(a) => TypeKind::Array(ArrayType {
894 inner: a,
895 store: &self.store,
896 }),
897 TypeDataKind::Uninitialized => {
898 unreachable!("should never be able to query the kind of an uninitialized type")
899 }
900 }
901 }
902
903 pub fn is_concrete(&self) -> bool {
906 match self.kind() {
907 TypeKind::Primitive(_) | TypeKind::Struct(_) => true,
908 TypeKind::Pointer(_) | TypeKind::Array(_) => false,
909 }
910 }
911
912 pub fn as_concrete(&self) -> Option<&abi::Guid> {
914 match self.kind() {
915 TypeKind::Primitive(g) => Some(g),
916 TypeKind::Struct(s) => Some(s.guid()),
917 TypeKind::Pointer(_) | TypeKind::Array(_) => None,
918 }
919 }
920
921 pub fn as_struct(&self) -> Option<StructType<'_>> {
923 if let TypeKind::Struct(s) = self.kind() {
924 Some(s)
925 } else {
926 None
927 }
928 }
929
930 pub fn as_pointer(&self) -> Option<PointerType<'_>> {
932 if let TypeKind::Pointer(p) = self.kind() {
933 Some(p)
934 } else {
935 None
936 }
937 }
938
939 pub fn as_array(&self) -> Option<ArrayType<'_>> {
941 if let TypeKind::Array(a) = self.kind() {
942 Some(a)
943 } else {
944 None
945 }
946 }
947
948 pub fn try_from_abi<'abi>(
951 type_info: impl IntoIterator<Item = &'abi abi::TypeDefinition<'abi>>,
952 type_table: TypeTable,
953 ) -> Result<(TypeTable, Vec<Type>), TryFromAbiError<'abi>> {
954 GLOBAL_TYPE_STORE.try_from_abi(type_info.into_iter(), type_table)
955 }
956
957 pub fn pointer_type(&self, mutable: bool) -> Type {
959 self.inner().pointer_type(mutable, &self.store)
960 }
961
962 pub fn array_type(&self) -> Type {
964 self.inner().array_type(&self.store)
965 }
966
967 pub fn into_raw(ty: Type) -> *const std::ffi::c_void {
973 ty.inner.as_ptr().cast()
974 }
975
976 pub unsafe fn from_raw(raw: *const std::ffi::c_void) -> Type {
993 Type {
994 inner: NonNull::new(raw as *mut _).expect("invalid raw pointer"),
995 store: GLOBAL_TYPE_STORE.clone(),
996 }
997 }
998}
999
1000impl StructData {
1001 fn try_from_abi<'abi>(
1003 struct_info: &'abi abi::StructDefinition<'abi>,
1004 type_table: &TypeTable,
1005 ) -> Result<StructData, TryFromAbiError<'abi>> {
1006 let fields: Result<Vec<FieldData>, TryFromAbiError> = izip!(
1007 struct_info.field_names(),
1008 struct_info.field_types(),
1009 struct_info.field_offsets()
1010 )
1011 .map(|(name, type_id, offset)| {
1012 type_table
1013 .find_type_info_by_id(type_id)
1014 .ok_or_else(|| TryFromAbiError::UnknownTypeId(type_id.clone()))
1015 .map(|type_info| FieldData {
1016 name: name.to_owned(),
1017 type_info: type_info.inner,
1018 offset: *offset,
1019 })
1020 })
1021 .collect();
1022
1023 fields.map(|fields| StructData {
1024 guid: struct_info.guid,
1025 fields,
1026 memory_kind: struct_info.memory_kind,
1027 })
1028 }
1029}
1030
1031#[derive(Clone, Debug, Eq, PartialEq)]
1033pub struct FieldData {
1034 pub name: String,
1036 pub type_info: NonNull<TypeData>,
1038 pub offset: u16,
1040 }
1043
1044#[derive(Copy, Clone)]
1045pub struct Field<'t> {
1046 inner: &'t FieldData,
1047 store: &'t Arc<TypeDataStore>,
1048}
1049
1050impl<'t> Field<'t> {
1051 pub fn name<'s>(&'s self) -> &'t str
1053 where
1054 't: 's,
1055 {
1056 self.inner.name.as_str()
1057 }
1058
1059 pub fn ty(&self) -> Type {
1061 unsafe { Type::new_unchecked(self.inner.type_info, self.store.clone()) }
1063 }
1064
1065 pub fn offset(&self) -> usize {
1067 self.inner.offset as _
1068 }
1069}
1070
1071pub struct StructTypeBuilder {
1073 name: String,
1075
1076 memory_kind: abi::StructMemoryKind,
1078
1079 fields: Vec<(String, Type, usize)>,
1081
1082 layout: Layout,
1084
1085 guid: Option<abi::Guid>,
1087}
1088
1089impl StructTypeBuilder {
1090 pub fn new(name: impl Into<String>) -> Self {
1091 Self {
1092 name: name.into(),
1093 memory_kind: abi::StructMemoryKind::Gc,
1094 fields: Vec::new(),
1095 layout: Layout::from_size_align(0, 1).expect("invalid default layout"),
1096 guid: None,
1097 }
1098 }
1099
1100 pub fn set_memory_kind(mut self, kind: abi::StructMemoryKind) -> Self {
1102 self.memory_kind = kind;
1103 self
1104 }
1105
1106 pub fn add_field(mut self, name: impl Into<String>, ty: Type) -> Self {
1108 let field_layout = if ty.is_value_type() {
1109 ty.value_layout()
1110 } else {
1111 Layout::new::<std::ffi::c_void>()
1112 };
1113
1114 let (new_layout, offset) = self
1115 .layout
1116 .extend(field_layout)
1117 .expect("cannot extend struct layout");
1118 self.fields.push((name.into(), ty, offset));
1119 self.layout = new_layout;
1120 self
1121 }
1122
1123 pub fn add_fields<N: Into<String>>(
1125 mut self,
1126 iter: impl IntoIterator<Item = (N, Type)>,
1127 ) -> Self {
1128 for (name, ty) in iter.into_iter() {
1129 self = self.add_field(name.into(), ty);
1130 }
1131 self
1132 }
1133
1134 pub fn finish(self) -> Type {
1136 let guid = if let Some(guid) = self.guid {
1137 guid
1138 } else {
1139 let guid_string = build_struct_guid_string(
1140 &self.name,
1141 self.fields
1142 .iter()
1143 .map(|(name, ty, offset)| (name, Cow::Borrowed(ty), *offset)),
1144 );
1145 abi::Guid::from_str(&guid_string)
1146 };
1147
1148 Type::new_struct(
1149 self.name,
1150 self.layout,
1151 guid,
1152 self.fields
1153 .into_iter()
1154 .map(|(name, ty, offset)| (name, ty, offset.try_into().expect("offset too large"))),
1155 self.memory_kind,
1156 )
1157 }
1158}
1159
1160fn build_struct_guid_string<'t, N: AsRef<str> + 't>(
1162 name: &str,
1163 fields: impl Iterator<Item = (N, Cow<'t, Type>, usize)>,
1164) -> String {
1165 let fields: Vec<String> = fields
1166 .map(|(name, ty, _offset)| {
1167 let ty_string = build_type_guid_string(ty.as_ref());
1168 format!("{}: {}", name.as_ref(), ty_string)
1169 })
1170 .collect();
1171
1172 format!(
1173 "struct {name}{{{fields}}}",
1174 name = name,
1175 fields = fields.join(",")
1176 )
1177}
1178
1179fn build_type_guid_string(ty: &Type) -> String {
1181 match ty.kind() {
1182 TypeKind::Struct(s) => {
1183 if s.is_gc_struct() {
1184 format!("struct {}", ty.name())
1185 } else {
1186 build_struct_guid_string(
1187 ty.name(),
1188 s.fields()
1189 .iter()
1190 .map(|f| (f.name(), Cow::Owned(f.ty()), f.offset())),
1191 )
1192 }
1193 }
1194 TypeKind::Array(_) | TypeKind::Primitive(_) | TypeKind::Pointer(_) => ty.name().to_owned(),
1195 }
1196}
1197
1198pub trait HasStaticType {
1200 fn type_info() -> &'static Type;
1201}
1202
1203macro_rules! impl_primitive_type {
1204 ($($ty:ty),+) => {
1205 $(
1206 impl HasStaticType for $ty {
1207 fn type_info() -> &'static Type {
1208 static TYPE_INFO: once_cell::sync::OnceCell<Type> = once_cell::sync::OnceCell::new();
1209 TYPE_INFO.get_or_init(|| {
1210 GLOBAL_TYPE_STORE.allocate(
1211 <$ty as abi::PrimitiveType>::name(),
1212 Layout::new::<$ty>(),
1213 TypeDataKind::Primitive(<$ty as abi::PrimitiveType>::guid().clone())
1214 )
1215 })
1216 }
1217 }
1218 )+
1219 }
1220}
1221
1222impl_primitive_type!(
1223 i8,
1224 i16,
1225 i32,
1226 i64,
1227 i128,
1228 isize,
1229 u8,
1230 u16,
1231 u32,
1232 u64,
1233 u128,
1234 usize,
1235 f32,
1236 f64,
1237 bool,
1238 (),
1239 std::ffi::c_void
1240);
1241
1242impl<T: HasStaticType + 'static> HasStaticType for *mut T {
1244 fn type_info() -> &'static Type {
1245 static mut VALUE: Option<StaticTypeMap<Type>> = None;
1246 static INIT: Once = Once::new();
1247
1248 let map = unsafe {
1249 INIT.call_once(|| {
1250 VALUE = Some(StaticTypeMap::default());
1251 });
1252 VALUE.as_ref().unwrap()
1253 };
1254
1255 map.call_once::<T, _>(|| T::type_info().pointer_type(true))
1256 }
1257}
1258
1259impl<T: HasStaticType + 'static> HasStaticType for *const T {
1261 fn type_info() -> &'static Type {
1262 static mut VALUE: Option<StaticTypeMap<Type>> = None;
1263 static INIT: Once = Once::new();
1264
1265 let map = unsafe {
1266 INIT.call_once(|| {
1267 VALUE = Some(StaticTypeMap::default());
1268 });
1269 VALUE.as_ref().unwrap()
1270 };
1271
1272 map.call_once::<T, _>(|| T::type_info().pointer_type(false))
1273 }
1274}