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#[repr(transparent)]
15#[derive(Clone)]
16pub struct RawArray(pub(crate) GcPtr);
17
18impl RawArray {
19 pub unsafe fn get_ptr(&self) -> *const u8 {
25 self.0.deref()
26 }
27}
28
29#[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 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 pub fn into_raw(self) -> RawArray {
53 self.raw
54 }
55
56 pub fn root(self) -> RootedArray<T> {
58 RootedArray::new(&self.runtime.gc, self.raw)
59 }
60
61 pub fn type_info(&self) -> Type {
63 self.runtime.gc.ptr_type(self.raw.0)
64 }
65
66 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 pub fn is_empty(&self) -> bool {
78 self.len() == 0
79 }
80
81 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 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 "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#[derive(Clone)]
167pub struct RootedArray<T> {
168 handle: GcRootPtr,
169 _data: PhantomData<T>,
170}
171
172impl<T> RootedArray<T> {
173 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 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}