1use crate::{
2 garbage_collector::GcRootPtr,
3 marshal::Marshal,
4 reflection::{ArgumentReflection, ReturnTypeReflection},
5 GarbageCollector, Runtime,
6};
7use mun_memory::{
8 gc::{GcPtr, GcRuntime, HasIndirectionPtr},
9 Type,
10};
11use std::{
12 ptr::{self, NonNull},
13 sync::Arc,
14};
15
16#[repr(transparent)]
18#[derive(Clone)]
19pub struct RawStruct(GcPtr);
20
21impl RawStruct {
22 pub unsafe fn get_ptr(&self) -> *const u8 {
24 self.0.deref()
25 }
26}
27
28#[derive(Clone)]
31pub struct StructRef<'s> {
32 raw: RawStruct,
33 runtime: &'s Runtime,
34}
35
36impl<'s> StructRef<'s> {
37 fn new<'r>(raw: RawStruct, runtime: &'r Runtime) -> Self
39 where
40 'r: 's,
41 {
42 Self { raw, runtime }
43 }
44
45 pub fn into_raw(self) -> RawStruct {
47 self.raw
48 }
49
50 pub fn root(self) -> RootedStruct {
52 RootedStruct::new(&self.runtime.gc, self.raw)
53 }
54
55 pub fn type_info(&self) -> Type {
57 self.runtime.gc.ptr_type(self.raw.0)
58 }
59
60 unsafe fn get_field_ptr_unchecked<T>(&self, offset: usize) -> NonNull<T> {
66 let ptr = self.raw.get_ptr();
68
69 NonNull::new_unchecked(ptr.add(offset).cast::<T>() as *mut T)
70 }
71
72 pub fn get<T: ReturnTypeReflection + Marshal<'s>>(&self, field_name: &str) -> Result<T, String>
74 where
75 T: 's,
76 {
77 let type_info = self.type_info();
78
79 let struct_info = type_info.as_struct().unwrap();
81
82 let field_info = struct_info
83 .fields()
84 .find_by_name(field_name)
85 .ok_or_else(|| {
86 format!(
87 "Struct `{}` does not contain field `{}`.",
88 type_info.name(),
89 field_name
90 )
91 })?;
92
93 if !T::accepts_type(&field_info.ty()) {
94 return Err(format!(
95 "Mismatched types for `{}::{}`. Expected: `{}`. Found: `{}`.",
96 type_info.name(),
97 field_name,
98 T::type_hint(),
99 field_info.ty().name(),
100 ));
101 };
102
103 let field_ptr = unsafe { self.get_field_ptr_unchecked::<T::MunType>(field_info.offset()) };
105 Ok(Marshal::marshal_from_ptr(
106 field_ptr,
107 self.runtime,
108 &field_info.ty(),
109 ))
110 }
111
112 pub fn replace<T: ArgumentReflection + Marshal<'s>>(
115 &mut self,
116 field_name: &str,
117 value: T,
118 ) -> Result<T, String>
119 where
120 T: 's,
121 {
122 let type_info = self.type_info();
123
124 let struct_info = type_info.as_struct().unwrap();
126
127 let field_info = struct_info
128 .fields()
129 .find_by_name(field_name)
130 .ok_or_else(|| {
131 format!(
132 "Struct `{}` does not contain field `{}`.",
133 type_info.name(),
134 field_name
135 )
136 })?;
137
138 let value_type = value.type_info(self.runtime);
139 if field_info.ty() != value_type {
140 return Err(format!(
141 "Mismatched types for `{}::{}`. Expected: `{}`. Found: `{}`.",
142 type_info.name(),
143 field_name,
144 value_type.name(),
145 field_info.ty()
146 ));
147 }
148
149 let field_ptr = unsafe { self.get_field_ptr_unchecked::<T::MunType>(field_info.offset()) };
151 let old = Marshal::marshal_from_ptr(field_ptr, self.runtime, &field_info.ty());
152 Marshal::marshal_to_ptr(value, field_ptr, &field_info.ty());
153 Ok(old)
154 }
155
156 pub fn set<T: ArgumentReflection + Marshal<'s>>(
158 &mut self,
159 field_name: &str,
160 value: T,
161 ) -> Result<(), String> {
162 let type_info = self.type_info();
163
164 let struct_info = type_info.as_struct().unwrap();
166
167 let field_info = struct_info
168 .fields()
169 .find_by_name(field_name)
170 .ok_or_else(|| {
171 format!(
172 "Struct `{}` does not contain field `{}`.",
173 type_info.name(),
174 field_name
175 )
176 })?;
177
178 let value_type = value.type_info(self.runtime);
179 if field_info.ty() != value_type {
180 return Err(format!(
181 "Mismatched types for `{}::{}`. Expected: `{}`. Found: `{}`.",
182 type_info.name(),
183 field_name,
184 value_type.name(),
185 field_info.ty()
186 ));
187 }
188
189 let field_ptr = unsafe { self.get_field_ptr_unchecked::<T::MunType>(field_info.offset()) };
191 Marshal::marshal_to_ptr(value, field_ptr, &field_info.ty());
192 Ok(())
193 }
194}
195
196impl<'r> ArgumentReflection for StructRef<'r> {
197 fn type_info(&self, _runtime: &Runtime) -> Type {
198 self.type_info()
199 }
200}
201
202impl<'s> Marshal<'s> for StructRef<'s> {
203 type MunType = RawStruct;
204
205 fn marshal_from<'r>(value: Self::MunType, runtime: &'r Runtime) -> Self
206 where
207 'r: 's,
208 {
209 StructRef::new(value, runtime)
210 }
211
212 fn marshal_into<'r>(self) -> Self::MunType {
213 self.into_raw()
214 }
215
216 fn marshal_from_ptr<'r>(
217 ptr: NonNull<Self::MunType>,
218 runtime: &'r Runtime,
219 type_info: &Type,
220 ) -> StructRef<'s>
221 where
222 Self: 's,
223 'r: 's,
224 {
225 let struct_info = type_info.as_struct().unwrap();
226
227 let gc_handle = if struct_info.is_value_struct() {
229 let mut gc_handle = runtime.gc().alloc(type_info);
233
234 let src = ptr.cast::<u8>().as_ptr() as *const _;
236 let dest = unsafe { gc_handle.deref_mut::<u8>() };
237 unsafe { ptr::copy_nonoverlapping(src, dest, type_info.value_layout().size()) };
238
239 gc_handle
240 } else {
241 unsafe { *ptr.cast::<GcPtr>().as_ptr() }
243 };
244
245 StructRef::new(RawStruct(gc_handle), runtime)
246 }
247
248 fn marshal_to_ptr(value: Self, mut ptr: NonNull<Self::MunType>, type_info: &Type) {
249 let struct_info = type_info.as_struct().unwrap();
250 if struct_info.is_value_struct() {
251 let dest = ptr.cast::<u8>().as_ptr();
252 unsafe {
253 ptr::copy_nonoverlapping(
254 value.into_raw().get_ptr(),
255 dest,
256 type_info.value_layout().size(),
257 )
258 };
259 } else {
260 unsafe { *ptr.as_mut() = value.into_raw() };
261 }
262 }
263}
264
265impl<'r> ReturnTypeReflection for StructRef<'r> {
266 fn accepts_type(ty: &Type) -> bool {
268 ty.is_struct()
269 }
270
271 fn type_hint() -> &'static str {
272 "struct"
273 }
274}
275
276#[derive(Clone)]
279pub struct RootedStruct {
280 handle: GcRootPtr,
281}
282
283impl RootedStruct {
284 fn new(gc: &Arc<GarbageCollector>, raw: RawStruct) -> Self {
286 assert!(gc.ptr_type(raw.0).is_struct());
287 Self {
288 handle: GcRootPtr::new(gc, raw.0),
289 }
290 }
291
292 pub fn as_ref<'r>(&self, runtime: &'r Runtime) -> StructRef<'r> {
295 assert_eq!(Arc::as_ptr(&runtime.gc), self.handle.runtime().as_ptr());
296 StructRef::new(RawStruct(self.handle.handle()), runtime)
297 }
298}