mun_runtime/
array.rs

1use crate::{
2    garbage_collector::GcRootPtr, ArgumentReflection, GarbageCollector, Marshal,
3    ReturnTypeReflection, Runtime,
4};
5use mun_memory::{
6    gc::{Array, GcPtr, GcRuntime, HasIndirectionPtr},
7    Type,
8};
9use std::marker::PhantomData;
10use std::ptr::NonNull;
11use std::sync::Arc;
12
13/// Represents a Mun array pointer.
14#[repr(transparent)]
15#[derive(Clone)]
16pub struct RawArray(pub(crate) GcPtr);
17
18impl RawArray {
19    /// Returns a pointer to the array memory.
20    ///
21    /// # Safety
22    ///
23    /// Dereferencing might cause undefined behavior
24    pub unsafe fn get_ptr(&self) -> *const u8 {
25        self.0.deref()
26    }
27}
28
29/// Type-agnostic wrapper for interoperability with a Mun array. This is merely a reference to the
30/// Mun array, that will be garbage collected unless it is rooted.
31#[derive(Clone)]
32pub struct ArrayRef<'a, T> {
33    raw: RawArray,
34    runtime: &'a Runtime,
35    _phantom: PhantomData<T>,
36}
37
38impl<'array, T: Marshal<'array> + 'array> ArrayRef<'array, T> {
39    /// Creates a `ArrayRef` that wraps a raw Mun struct.
40    pub(crate) fn new<'runtime>(raw: RawArray, runtime: &'runtime Runtime) -> Self
41    where
42        'runtime: 'array,
43    {
44        Self {
45            raw,
46            runtime,
47            _phantom: Default::default(),
48        }
49    }
50
51    /// Consumes the `ArrayRef`, returning a raw Mun array.
52    pub fn into_raw(self) -> RawArray {
53        self.raw
54    }
55
56    /// Roots the `ArrayRef`.
57    pub fn root(self) -> RootedArray<T> {
58        RootedArray::new(&self.runtime.gc, self.raw)
59    }
60
61    /// Returns the type information of the array.
62    pub fn type_info(&self) -> Type {
63        self.runtime.gc.ptr_type(self.raw.0)
64    }
65
66    /// Returns the number of elements stored in the array
67    pub fn len(&self) -> usize {
68        self.runtime
69            .gc
70            .as_ref()
71            .array(self.raw.0)
72            .expect("the internal handle does not refer to an array")
73            .length()
74    }
75
76    /// Returns true if this array does not contain a single element.
77    pub fn is_empty(&self) -> bool {
78        self.len() == 0
79    }
80
81    /// Returns the length of the array
82    pub fn capacity(&self) -> usize {
83        self.runtime
84            .gc
85            .as_ref()
86            .array(self.raw.0)
87            .expect("the internal handle does not refer to an array")
88            .capacity()
89    }
90
91    /// Returns an iterator to iterate over the elements of the array.
92    pub fn iter(&self) -> impl Iterator<Item = T> + 'array
93    where
94        T: 'array,
95    {
96        let handle = self
97            .runtime
98            .gc
99            .as_ref()
100            .array(self.raw.0)
101            .expect("type of the array value must be an array");
102        let element_ty = handle.element_type();
103        let runtime = self.runtime;
104        handle
105            .elements()
106            .map(move |element_ptr| T::marshal_from_ptr(element_ptr.cast(), runtime, &element_ty))
107    }
108}
109
110impl<'a, T: Marshal<'a> + ReturnTypeReflection> ReturnTypeReflection for ArrayRef<'a, T> {
111    fn accepts_type(ty: &Type) -> bool {
112        if let Some(arr) = ty.as_array() {
113            T::accepts_type(&arr.element_type())
114        } else {
115            false
116        }
117    }
118
119    fn type_hint() -> &'static str {
120        // TODO: Improve this
121        "array"
122    }
123}
124
125impl<'a, T: Marshal<'a> + ArgumentReflection + 'a> ArgumentReflection for ArrayRef<'a, T> {
126    fn type_info(&self, _runtime: &Runtime) -> Type {
127        self.type_info()
128    }
129}
130
131impl<'a, T: Marshal<'a> + 'a> Marshal<'a> for ArrayRef<'a, T> {
132    type MunType = RawArray;
133
134    fn marshal_from<'runtime>(value: Self::MunType, runtime: &'runtime Runtime) -> Self
135    where
136        Self: 'a,
137        'runtime: 'a,
138    {
139        ArrayRef::new(value, runtime)
140    }
141
142    fn marshal_into(self) -> Self::MunType {
143        self.raw
144    }
145
146    fn marshal_from_ptr<'runtime>(
147        ptr: NonNull<Self::MunType>,
148        runtime: &'runtime Runtime,
149        _type_info: &Type,
150    ) -> Self
151    where
152        Self: 'a,
153        'runtime: 'a,
154    {
155        let handle = unsafe { *ptr.cast::<GcPtr>().as_ptr() };
156        ArrayRef::new(RawArray(handle), runtime)
157    }
158
159    fn marshal_to_ptr(value: Self, mut ptr: NonNull<Self::MunType>, _type_info: &Type) {
160        unsafe { *ptr.as_mut() = value.into_raw() };
161    }
162}
163
164/// Type-agnostic wrapper for interoperability with a Mun struct, that has been rooted. To marshal,
165/// obtain a `ArrayRef` for the `RootedArray`.
166#[derive(Clone)]
167pub struct RootedArray<T> {
168    handle: GcRootPtr,
169    _data: PhantomData<T>,
170}
171
172impl<T> RootedArray<T> {
173    /// Creates a `RootedArray` that wraps a raw Mun struct.
174    fn new(gc: &Arc<GarbageCollector>, raw: RawArray) -> Self {
175        assert!(gc.ptr_type(raw.0).is_array());
176        Self {
177            handle: GcRootPtr::new(gc, raw.0),
178            _data: Default::default(),
179        }
180    }
181
182    /// Converts the `RootedArray` into an `ArrayRef<T>`, using an external shared reference to a
183    /// `Runtime`.
184    pub fn as_ref<'r>(&self, runtime: &'r Runtime) -> ArrayRef<'r, T>
185    where
186        T: Marshal<'r> + 'r,
187    {
188        assert_eq!(Arc::as_ptr(&runtime.gc), self.handle.runtime().as_ptr());
189        ArrayRef::new(RawArray(self.handle.handle()), runtime)
190    }
191}