mun_memory/type/
mod.rs

1//! Type information in Mun is stored globally. This allows type information to be stored easily.
2//!
3//! A type is referred to with [`Type`]. A `Type` holds a reference to the underlying data which is
4//! managed by the runtime. `Type`s can be freely created through a [`StructTypeBuilder`], via
5//! [`HasStaticType`] or by querying other types ([`Type::pointer_type`] for instance). Cloning a
6//! [`Type`] is a cheap operation.
7//!
8//! Type information is stored globally on the heap and is freed when no longer referenced by a
9//! `Type`. However, since `Type`s can reference each other a garbage collection algorithm is used
10//! to clean up unreferenced type information. See [`Type::collect_unreferenced_types()`].
11
12pub 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/// A type store holds a list of interconnected [`TypeData`]s. Type information can contain cycles
38/// so the `TypeData`s refer to each other via pointers. The `TypeDataStore` owns the heap allocated
39/// `TypeData` instances.
40///
41/// By calling [`TypeDataStore::collect_garbage`] types that are no longer referenced by [`Type`]s
42/// are removed.
43#[derive(Default)]
44struct TypeDataStore {
45    types: Mutex<VecDeque<Box<TypeData>>>,
46}
47
48/// Result information after a call to [`TypeDataStore::collect_garbage`].
49#[derive(Clone, Debug)]
50pub struct TypeCollectionStats {
51    pub collected_types: usize,
52    pub remaining_types: usize,
53}
54
55/// A status stored with every [`TypeData`] which stores the current usage of the `TypeData`.
56/// Initially, types are marked as `Initializing` which indicates that they should not 'yet'
57/// participate in garbage-collection.
58#[derive(Eq, PartialEq)]
59enum Mark {
60    Used,
61    Unused,
62    Initializing,
63}
64
65impl TypeDataStore {
66    /// Called to collect types that are no longer externally referenced.
67    pub fn collect_garbage(&self) -> TypeCollectionStats {
68        let mut lock = self.types.lock();
69
70        // Reset all mark flags.
71        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        // Trace all types
86        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            // Iterate over the indirections. This is an interesting case safety wise, because at
119            // this very moment another thread might be accessing this as well. However this is safe
120            // because we use `allocate_into` to allocate the values.
121            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        // Iterate over all objects and remove the ones that are no longer referenced
138        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    /// Tries to convert multiple [`abi::TypeDefinition`] to internal type representations. If
157    /// the conversion succeeds an updated [`TypeTable`] is returned
158    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        // Acquire a lock in the type entries
164        let mut entries = self.types.lock();
165
166        // Create uninitialized types for all the definitions
167        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        // Next, initialize the types.
185        for (type_def, mut ty) in definition_and_type {
186            // Safety: we are modifying the inner data of the type here. At this point this is safe
187            // because the type cannot be used by anything else yet.
188            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            // Mark the entry as used. This should be safe because the `type_table` also still holds
197            // a strong reference to the type. After that type is potentially dropped (after this
198            // function returns) all values has already been initialized.
199            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        // Safety: get a TypeInner with a 'static lifetime. This is safe because of the nature of
224        // `Type`. The `Type` struct ensures that the pointed to value is never destructed as long
225        // as it lives.
226        let entry = unsafe {
227            NonNull::new_unchecked(
228                entries.back().expect("didnt insert").deref() as *const TypeData as *mut _,
229            )
230        };
231
232        // Safety: this operation is safe, because we currently own the instance and the lock.
233        unsafe { Type::new_unchecked(entry, self.clone()) }
234    }
235
236    /// Allocates a new type instance
237    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    /// Allocates a new type instance but keeps it in an uninitialized state.
250    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
261/// A reference to internally stored type information. A `Type` can be used to query information,
262/// construct other types, or store type information for later use.
263pub struct Type {
264    inner: NonNull<TypeData>,
265
266    /// A [`Type`] holds a strong reference to its data store. This ensure that the data is never
267    /// deleted before this instance is destroyed.
268    ///
269    /// This has to be here because we store [`Type`] instances globally both in Rust and
270    /// potentially als over FFI. Since the static destruction order is not completely guarenteed
271    /// the store might be deallocated before the last type is deallocated. Keeping a reference to
272    /// the store in this instance ensures that the data is kept alive until the last `Type` is
273    /// dropped.
274    store: Arc<TypeDataStore>,
275}
276
277impl Type {
278    /// Constructs a new instance from a pointer and the store it belongs to.
279    ///
280    /// # Safety
281    ///
282    /// The pointer pointed to by `inner` might be invalid, in which case this method will cause
283    /// undefined behavior.
284    unsafe fn new_unchecked(mut inner: NonNull<TypeData>, store: Arc<TypeDataStore>) -> Self {
285        // Increment the external reference count
286        inner
287            .as_mut()
288            .external_references
289            .fetch_add(1, Ordering::AcqRel);
290
291        Self { inner, store }
292    }
293}
294
295// Types can safely be used across multiple threads.
296unsafe 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
350/// Stores type information for a particular type as well as references to related types.
351pub struct TypeData {
352    /// Type name
353    name: String,
354
355    /// The memory layout of the type
356    layout: Layout,
357
358    /// Type group
359    data: TypeDataKind,
360
361    /// Holds the number of external (non-cyclic) references. Basically the number of [`Type`]
362    /// instances pointing to this instance.
363    ///
364    /// Note that if this ever reaches zero is doesn't mean it's no longer used because it can still
365    /// be referenced by other types.
366    external_references: AtomicUsize,
367
368    /// The type of an immutable pointer to this type
369    immutable_pointer_type: RwLock<Option<NonNull<TypeData>>>,
370
371    /// The type of a mutable pointer to this type
372    mutable_pointer_type: RwLock<Option<NonNull<TypeData>>>,
373
374    /// The type of an array of this type
375    array_type: RwLock<Option<NonNull<TypeData>>>,
376
377    /// The state of instance with regards to its usage.
378    mark: Mark,
379}
380
381impl TypeData {
382    /// Returns the type that represents a pointer to this type
383    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            // Fast path, the type already exists, return it immediately.
394            if let Some(ty) = read_lock.deref().as_ref() {
395                return Type {
396                    inner: *ty,
397                    store: store.clone(),
398                };
399            }
400        }
401
402        // No type is currently stored, allocate a new one.
403        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        // Acquire the write lock
414        let mut write_lock = cache_key.write();
415
416        // Get the reference to the inner data, we need this to mark it properly.
417        let inner = unsafe { ty.inner.as_mut() };
418
419        // Recheck if another thread acquired the write lock in the mean time
420        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        // We store the reference to the array type in the current type. After which we mark the
429        // type as used. This ensures that the garbage collector never removes the type from under
430        // our noses.
431        *write_lock = Some(ty.inner);
432        inner.mark = Mark::Used;
433
434        ty
435    }
436
437    /// Returns the type that represents a pointer to this type
438    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            // Fast path, the type already exists, return it immediately.
445            if let Some(ty) = read_lock.deref().as_ref() {
446                return Type {
447                    inner: *ty,
448                    store: store.clone(),
449                };
450            }
451        }
452
453        // No type is currently stored, allocate a new one.
454        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        // Acquire the write lock
464        let mut write_lock = cache_key.write();
465
466        // Get the reference to the inner data, we need this to mark it properly.
467        let inner = unsafe { ty.inner.as_mut() };
468
469        // Recheck if another thread acquired the write lock in the mean time
470        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        // We store the reference to the array type in the current type. After which we mark the
479        // type as used. This ensures that the garbage collector never removes the type from under
480        // our noses.
481        *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/// A linked version of [`mun_abi::TypeInfoData`] that has resolved all occurrences of `TypeId` with `TypeInfo`.
500#[derive(Clone, Debug, Eq, PartialEq, Hash)]
501enum TypeDataKind {
502    /// Primitive types (i.e. `()`, `bool`, `float`, `int`, etc.)
503    Primitive(abi::Guid),
504    /// Struct types (i.e. record, tuple, or unit structs)
505    Struct(StructData),
506    /// A pointer to another type
507    Pointer(PointerData),
508    /// An array
509    Array(ArrayData),
510    /// Indicates that the type has been allocated but it has not yet been initialized,
511    /// this indicates that it still needs to be properly initialized.
512    Uninitialized,
513}
514
515#[derive(Copy, Clone)]
516pub enum TypeKind<'t> {
517    /// Primitive types (i.e. `()`, `bool`, `float`, `int`, etc.)
518    Primitive(&'t abi::Guid),
519    /// Struct types (i.e. record, tuple, or unit structs)
520    Struct(StructType<'t>),
521    /// A pointer to another type
522    Pointer(PointerType<'t>),
523    /// An array of values
524    Array(ArrayType<'t>),
525}
526
527/// A linked version of [`mun_abi::StructInfo`] that has resolved all occurrences of `TypeId` with `TypeInfo`.
528#[derive(Clone, Debug)]
529struct StructData {
530    /// The unique identifier of this struct
531    pub guid: abi::Guid,
532    /// Struct fields
533    pub fields: Vec<FieldData>,
534    /// Struct memory kind
535    pub memory_kind: abi::StructMemoryKind,
536}
537
538/// Reference information of a struct
539#[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    /// Returns the unique identifier of this struct
548    pub fn guid<'s>(&'s self) -> &'t abi::Guid
549    where
550        't: 's,
551    {
552        &self.inner.guid
553    }
554
555    /// Returns the memory type of this struct
556    pub fn memory_kind(&self) -> abi::StructMemoryKind {
557        self.inner.memory_kind
558    }
559
560    /// Returns true if this struct is a value struct. Value structs are passed by value and are not
561    /// allocated by the garbage collector.
562    pub fn is_value_struct(&self) -> bool {
563        self.memory_kind() == abi::StructMemoryKind::Value
564    }
565
566    /// Returns true if this struct is a garbage collected struct.
567    pub fn is_gc_struct(&self) -> bool {
568        self.memory_kind() == abi::StructMemoryKind::Gc
569    }
570
571    /// Returns an iterator over all fields
572    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/// A collection of fields of a struct
594#[derive(Copy, Clone)]
595pub struct Fields<'t> {
596    inner: &'t StructData,
597    store: &'t Arc<TypeDataStore>,
598}
599
600impl<'t> Fields<'t> {
601    /// Returns the number of fields in the struct
602    pub fn len(&self) -> usize {
603        self.inner.fields.len()
604    }
605
606    /// Returns the field at the given index, or `None` if `index` exceeds the number of fields.
607    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    /// Returns the field with the given name, or `None` if no such field exists.
615    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    /// Returns an iterator over all fields
621    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/// A linked version of [`mun_abi::PointerInfo`] that has resolved all occurrences of `TypeId` with `TypeInfo`.
658#[derive(Clone, Debug, Eq, PartialEq, Hash)]
659struct PointerData {
660    /// The type to which is pointed
661    pub pointee: NonNull<TypeData>,
662    /// Whether or not the pointer is mutable
663    pub mutable: bool,
664}
665
666/// Reference information of a pointer
667#[derive(Copy, Clone)]
668pub struct PointerType<'t> {
669    inner: &'t PointerData,
670    store: &'t Arc<TypeDataStore>,
671}
672
673impl<'t> PointerType<'t> {
674    /// Returns the type to which this pointer points
675    pub fn pointee(&self) -> Type {
676        // Safety: this operation is safe due to the lifetime constraints on this type
677        unsafe { Type::new_unchecked(self.inner.pointee, self.store.clone()) }
678    }
679
680    /// Returns true if this is a mutable pointer type
681    pub fn is_mutable(&self) -> bool {
682        self.inner.mutable
683    }
684
685    /// Returns true if this is a immutable pointer type
686    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/// Reference information of an array
720#[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    /// Returns the type of elements this array stores
729    pub fn element_type(&self) -> Type {
730        // Safety: this operation is safe due to the lifetime constraints on this type
731        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    /// Collects all data related to types that are no longer referenced by a [`Type`]. Returns
769    /// the number of types that were removed.
770    pub fn collect_unreferenced_type_data() -> TypeCollectionStats {
771        GLOBAL_TYPE_STORE.collect_garbage()
772    }
773
774    /// Constructs a new struct type
775    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    /// Returns a reference to the [`TypeInner`]
803    fn inner(&self) -> &TypeData {
804        // Safety: taking the reference is always ok because the garbage collector ensures that as
805        // long as self (Type) exists the inner stays alive.
806        unsafe { self.inner.as_ref() }
807    }
808
809    /// Returns the name of the type
810    pub fn name(&self) -> &str {
811        self.inner().name.as_str()
812    }
813
814    /// Returns the memory layout of the data of the type. This is the layout of the memory when
815    /// stored on the stack or in the heap.
816    pub fn value_layout(&self) -> Layout {
817        self.inner().layout
818    }
819
820    /// Returns the layout of the type when being referenced.
821    pub fn reference_layout(&self) -> Layout {
822        if self.is_reference_type() {
823            // Reference types are always stored as pointers to an GC object
824            Layout::new::<*const c_void>()
825        } else {
826            self.value_layout()
827        }
828    }
829
830    /// Returns true if the type is a reference type. Variables of reference types store references
831    /// to their data (objects), while variables of value types directly contain their data.
832    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    /// Returns true if the type is a value type. Variables of reference types store references to
841    /// their data (objects), while variables of value types directly contain their data.
842    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    /// Returns true if this instance represents the TypeInfo of the given type.
851    ///
852    /// ```rust
853    /// # use mun_memory::HasStaticType;
854    /// assert!(i64::type_info().equals::<i64>());
855    /// assert!(!i64::type_info().equals::<f64>())
856    /// ```
857    pub fn equals<T: HasStaticType>(&self) -> bool {
858        T::type_info() == self
859    }
860
861    /// Returns whether this is a fundamental type.
862    pub fn is_primitive(&self) -> bool {
863        matches!(self.kind(), TypeKind::Primitive(_))
864    }
865
866    /// Returns whether this is a struct type.
867    pub fn is_struct(&self) -> bool {
868        matches!(self.kind(), TypeKind::Struct(_))
869    }
870
871    /// Returns whether this is a pointer type.
872    pub fn is_pointer(&self) -> bool {
873        matches!(self.kind(), TypeKind::Pointer(_))
874    }
875
876    /// Returns whether this is an array type.
877    pub fn is_array(&self) -> bool {
878        matches!(self.kind(), TypeKind::Array(_))
879    }
880
881    /// Returns the kind of the type
882    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    /// Returns true if this type is a concrete type. This is the case for any type that doesn't
904    /// refer to another type like a pointer.
905    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    /// Returns the GUID associated with this instance if this instance represents a concrete type.
913    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    /// Retrieves the type's struct information, if available.
922    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    /// Retrieves the type's pointer information, if available.
931    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    /// Retrieves the type's array information, if available.
940    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    /// Tries to convert multiple [`abi::TypeDefinition`] to internal type representations. If
949    /// the conversion succeeds an updated [`TypeTable`] is returned
950    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    /// Returns the type that represents a pointer to this type
958    pub fn pointer_type(&self, mutable: bool) -> Type {
959        self.inner().pointer_type(mutable, &self.store)
960    }
961
962    /// Returns the type that represents an array to this type
963    pub fn array_type(&self) -> Type {
964        self.inner().array_type(&self.store)
965    }
966
967    /// Consumes the `Type`, returning a wrapped raw pointer.
968    ///
969    /// After calling this function, the caller is responsible for the memory previously managed by
970    /// the `Type`. The easiest way to do this is to convert the raw pointer back into a `Type` with
971    /// the [`Type::from_raw`] function, allowing the `Type` destructor to perform the cleanup.
972    pub fn into_raw(ty: Type) -> *const std::ffi::c_void {
973        ty.inner.as_ptr().cast()
974    }
975
976    /// Constructs a box from a raw pointer.
977    ///
978    /// After calling this function, the raw pointer is owned by the resulting `Type`. Specifically,
979    /// the `Type` destructor will ensure the memory previously retained by the `raw` will be
980    /// properly cleaned up. For this to be safe, the passed in `raw` pointer must have been
981    /// previously returned by [`Type::into_raw`].
982    ///
983    /// This function must also not be called as part of static deinitialization as that may cause
984    /// undefined behavior in the underlying implementation. Therefor passing the raw pointer over
985    /// FFI might not be safe. Instead, wrap the `Type` in an `Arc` or a `Box` and use that on the
986    /// FFI boundary.
987    ///
988    /// # Safety
989    ///
990    /// This function is unsafe because improper use may lead to memory problems. For example, a
991    /// double-free may occur if the function is called twice on the same raw pointer.
992    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    /// Tries to convert from an `abi::StructInfo`.
1002    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/// A linked version of a struct field.
1032#[derive(Clone, Debug, Eq, PartialEq)]
1033pub struct FieldData {
1034    /// The field's name
1035    pub name: String,
1036    /// The field's type
1037    pub type_info: NonNull<TypeData>,
1038    /// The field's offset
1039    pub offset: u16,
1040    // TODO: Field accessibility levels
1041    // const MunPrivacy_t *field_privacies,
1042}
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    /// Returns the name of the field
1052    pub fn name<'s>(&'s self) -> &'t str
1053    where
1054        't: 's,
1055    {
1056        self.inner.name.as_str()
1057    }
1058
1059    /// Returns the type of the field
1060    pub fn ty(&self) -> Type {
1061        // Safety: this operation is safe due to the lifetime constraints on this type
1062        unsafe { Type::new_unchecked(self.inner.type_info, self.store.clone()) }
1063    }
1064
1065    /// Returns the offset of the field from the start of the parent struct
1066    pub fn offset(&self) -> usize {
1067        self.inner.offset as _
1068    }
1069}
1070
1071/// A helper struct to create a struct type.
1072pub struct StructTypeBuilder {
1073    /// The name of the struct type
1074    name: String,
1075
1076    /// The type of memory management for this struct
1077    memory_kind: abi::StructMemoryKind,
1078
1079    /// The fields of the struct
1080    fields: Vec<(String, Type, usize)>,
1081
1082    /// Layout of the struct.
1083    layout: Layout,
1084
1085    /// Optional explicit type of the struct
1086    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    /// Sets the memory kind of the struct
1101    pub fn set_memory_kind(mut self, kind: abi::StructMemoryKind) -> Self {
1102        self.memory_kind = kind;
1103        self
1104    }
1105
1106    /// Adds a field to the struct
1107    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    /// Adds a collection of fields to the struct
1124    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    /// Finishes building the struct returning the corresponding [`Type`].
1135    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
1160/// Constructs a string that unique identifies a struct with the given name and fields.
1161fn 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
1179/// Constructs a string that unique identifies the specified type.
1180fn 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
1198/// A trait that defines static type information for types that can provide it.
1199pub 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
1242/// Every type that has at least a type name also has a valid pointer type name
1243impl<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
1259/// Every type that has at least a type name also has a valid pointer type name
1260impl<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}