intuicio_core/
object.rs

1use crate::types::{StructFieldQuery, Type, TypeHandle, TypeQuery};
2use intuicio_data::{type_hash::TypeHash, Initialize};
3use std::{
4    alloc::{alloc, dealloc},
5    collections::HashMap,
6};
7
8pub struct RuntimeObject;
9
10impl Initialize for RuntimeObject {
11    fn initialize() -> Self {
12        Self
13    }
14}
15
16pub struct Object {
17    handle: TypeHandle,
18    memory: *mut u8,
19    drop: bool,
20}
21
22impl Drop for Object {
23    fn drop(&mut self) {
24        if self.drop {
25            unsafe {
26                if self.handle.is_native() {
27                    self.handle.finalize(self.memory.cast::<()>());
28                } else {
29                    match &*self.handle {
30                        Type::Struct(type_) => {
31                            for field in type_.fields() {
32                                field
33                                    .type_handle()
34                                    .finalize(self.memory.add(field.address_offset()).cast::<()>());
35                            }
36                        }
37                        Type::Enum(type_) => {
38                            let discriminant = self.memory.read();
39                            if let Some(variant) = type_.find_variant_by_discriminant(discriminant)
40                            {
41                                for field in &variant.fields {
42                                    field.type_handle().finalize(
43                                        self.memory.add(field.address_offset()).cast::<()>(),
44                                    );
45                                }
46                            }
47                        }
48                    }
49                }
50                dealloc(self.memory, *self.handle.layout());
51            }
52        }
53    }
54}
55
56impl Object {
57    pub fn new(handle: TypeHandle) -> Self {
58        if !handle.can_initialize() {
59            panic!(
60                "Objects of type `{}::{}` cannot be initialized!",
61                handle.module_name().unwrap_or(""),
62                handle.name()
63            );
64        }
65        let memory = unsafe { alloc(*handle.layout()) };
66        let mut result = Self {
67            memory,
68            handle,
69            drop: true,
70        };
71        unsafe { result.initialize() };
72        result
73    }
74
75    pub fn try_new(handle: TypeHandle) -> Option<Self> {
76        if handle.can_initialize() {
77            let memory = unsafe { alloc(*handle.layout()) };
78            if memory.is_null() {
79                None
80            } else {
81                let mut result = Self {
82                    memory,
83                    handle,
84                    drop: true,
85                };
86                unsafe { result.initialize() };
87                Some(result)
88            }
89        } else {
90            None
91        }
92    }
93
94    /// # Safety
95    pub unsafe fn new_uninitialized(handle: TypeHandle) -> Option<Self> {
96        let memory = alloc(*handle.layout());
97        if memory.is_null() {
98            None
99        } else {
100            Some(Self {
101                memory,
102                handle,
103                drop: true,
104            })
105        }
106    }
107
108    /// # Safety
109    pub unsafe fn new_raw(handle: TypeHandle, memory: *mut u8) -> Self {
110        Self {
111            memory,
112            handle,
113            drop: true,
114        }
115    }
116
117    /// # Safety
118    pub unsafe fn from_bytes(handle: TypeHandle, bytes: &[u8]) -> Option<Self> {
119        if handle.layout().size() == bytes.len() {
120            let memory = alloc(*handle.layout());
121            if memory.is_null() {
122                None
123            } else {
124                memory.copy_from(bytes.as_ptr(), bytes.len());
125                Some(Self {
126                    memory,
127                    handle,
128                    drop: true,
129                })
130            }
131        } else {
132            None
133        }
134    }
135
136    pub fn with_value<T: 'static>(handle: TypeHandle, value: T) -> Option<Self> {
137        if handle.type_hash() == TypeHash::of::<T>() {
138            unsafe {
139                let mut result = Self::new_uninitialized(handle)?;
140                result.as_mut_ptr().cast::<T>().write(value);
141                Some(result)
142            }
143        } else {
144            None
145        }
146    }
147
148    /// # Safety
149    pub unsafe fn initialize(&mut self) {
150        if self.handle.is_native() {
151            self.handle.initialize(self.memory.cast::<()>());
152        } else {
153            match &*self.handle {
154                Type::Struct(type_) => {
155                    for field in type_.fields() {
156                        field
157                            .type_handle()
158                            .initialize(self.memory.add(field.address_offset()).cast::<()>());
159                    }
160                }
161                Type::Enum(type_) => {
162                    if let Some(variant) = type_.default_variant() {
163                        self.memory.write(variant.discriminant());
164                        for field in &variant.fields {
165                            field
166                                .type_handle()
167                                .initialize(self.memory.add(field.address_offset()).cast::<()>());
168                        }
169                    }
170                }
171            }
172        }
173    }
174
175    pub fn consume<T: 'static>(mut self) -> Result<T, Self> {
176        if self.handle.type_hash() == TypeHash::of::<T>() {
177            self.drop = false;
178            unsafe { Ok(self.memory.cast::<T>().read()) }
179        } else {
180            Err(self)
181        }
182    }
183
184    /// # Safety
185    pub unsafe fn into_inner(mut self) -> (TypeHandle, *mut u8) {
186        self.drop = false;
187        (self.handle.clone(), self.memory)
188    }
189
190    pub fn type_handle(&self) -> &TypeHandle {
191        &self.handle
192    }
193
194    /// # Safety
195    pub unsafe fn memory(&self) -> &[u8] {
196        std::slice::from_raw_parts(self.memory, self.type_handle().layout().size())
197    }
198
199    /// # Safety
200    pub unsafe fn memory_mut(&mut self) -> &mut [u8] {
201        std::slice::from_raw_parts_mut(self.memory, self.type_handle().layout().size())
202    }
203
204    /// # Safety
205    pub unsafe fn field_memory<'a>(&'a self, query: StructFieldQuery<'a>) -> Option<&'a [u8]> {
206        match &*self.handle {
207            Type::Struct(type_) => {
208                let field = type_.find_field(query)?;
209                Some(std::slice::from_raw_parts(
210                    self.memory.add(field.address_offset()),
211                    field.type_handle().layout().size(),
212                ))
213            }
214            Type::Enum(type_) => {
215                let discriminant = self.memory.read();
216                let variant = type_.find_variant_by_discriminant(discriminant)?;
217                let field = variant.find_field(query)?;
218                Some(std::slice::from_raw_parts(
219                    self.memory.add(field.address_offset()),
220                    field.type_handle().layout().size(),
221                ))
222            }
223        }
224    }
225
226    /// # Safety
227    pub unsafe fn field_memory_mut<'a>(
228        &'a mut self,
229        query: StructFieldQuery<'a>,
230    ) -> Option<&'a mut [u8]> {
231        match &*self.handle {
232            Type::Struct(type_) => {
233                let field = type_.find_field(query)?;
234                Some(std::slice::from_raw_parts_mut(
235                    self.memory.add(field.address_offset()),
236                    field.type_handle().layout().size(),
237                ))
238            }
239            Type::Enum(type_) => {
240                let discriminant = self.memory.read();
241                let variant = type_.find_variant_by_discriminant(discriminant)?;
242                let field = variant.find_field(query)?;
243                Some(std::slice::from_raw_parts_mut(
244                    self.memory.add(field.address_offset()),
245                    field.type_handle().layout().size(),
246                ))
247            }
248        }
249    }
250
251    pub fn read<T: 'static>(&self) -> Option<&T> {
252        if self.handle.type_hash() == TypeHash::of::<T>() {
253            unsafe { self.memory.cast::<T>().as_ref() }
254        } else {
255            None
256        }
257    }
258
259    pub fn write<T: 'static>(&mut self) -> Option<&mut T> {
260        if self.handle.type_hash() == TypeHash::of::<T>() {
261            unsafe { self.memory.cast::<T>().as_mut() }
262        } else {
263            None
264        }
265    }
266
267    pub fn read_field<'a, T: 'static>(&'a self, field: &str) -> Option<&'a T> {
268        let query = StructFieldQuery {
269            name: Some(field.into()),
270            type_query: Some(TypeQuery::of::<T>()),
271            ..Default::default()
272        };
273        let field = match &*self.handle {
274            Type::Struct(type_) => type_.find_field(query),
275            Type::Enum(type_) => {
276                let discriminant = unsafe { self.memory.read() };
277                let variant = type_.find_variant_by_discriminant(discriminant)?;
278                variant.find_field(query)
279            }
280        }?;
281        unsafe { self.memory.add(field.address_offset()).cast::<T>().as_ref() }
282    }
283
284    pub fn write_field<'a, T: 'static>(&'a mut self, field: &str) -> Option<&'a mut T> {
285        let query = StructFieldQuery {
286            name: Some(field.into()),
287            type_query: Some(TypeQuery::of::<T>()),
288            ..Default::default()
289        };
290        let field = match &*self.handle {
291            Type::Struct(type_) => type_.find_field(query),
292            Type::Enum(type_) => {
293                let discriminant = unsafe { self.memory.read() };
294                let variant = type_.find_variant_by_discriminant(discriminant)?;
295                variant.find_field(query)
296            }
297        }?;
298        unsafe { self.memory.add(field.address_offset()).cast::<T>().as_mut() }
299    }
300
301    /// # Safety
302    pub unsafe fn as_ptr(&self) -> *const u8 {
303        self.memory
304    }
305
306    /// # Safety
307    pub unsafe fn as_mut_ptr(&mut self) -> *mut u8 {
308        self.memory
309    }
310
311    /// # Safety
312    pub unsafe fn prevent_drop(&mut self) {
313        self.drop = false;
314    }
315}
316
317impl std::fmt::Debug for Object {
318    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319        unsafe {
320            f.debug_struct("Object")
321                .field("address", &(self.as_ptr() as usize))
322                .field(
323                    "type",
324                    &format!(
325                        "{}::{}",
326                        self.handle.module_name().unwrap_or_default(),
327                        self.handle.name()
328                    ),
329                )
330                .finish()
331        }
332    }
333}
334
335#[derive(Default)]
336pub struct DynamicObject {
337    properties: HashMap<String, Object>,
338}
339
340impl DynamicObject {
341    pub fn get(&self, name: &str) -> Option<&Object> {
342        self.properties.get(name)
343    }
344
345    pub fn get_mut(&mut self, name: &str) -> Option<&mut Object> {
346        self.properties.get_mut(name)
347    }
348
349    pub fn set(&mut self, name: impl ToString, value: Object) {
350        self.properties.insert(name.to_string(), value);
351    }
352
353    pub fn delete(&mut self, name: &str) -> Option<Object> {
354        self.properties.remove(name)
355    }
356
357    pub fn drain(&mut self) -> impl Iterator<Item = (String, Object)> + '_ {
358        self.properties.drain()
359    }
360
361    pub fn properties(&self) -> impl Iterator<Item = (&str, &Object)> + '_ {
362        self.properties
363            .iter()
364            .map(|(key, value)| (key.as_str(), value))
365    }
366
367    pub fn properties_mut(&mut self) -> impl Iterator<Item = (&str, &mut Object)> + '_ {
368        self.properties
369            .iter_mut()
370            .map(|(key, value)| (key.as_str(), value))
371    }
372
373    pub fn property_names(&self) -> impl Iterator<Item = &str> + '_ {
374        self.properties.keys().map(|key| key.as_str())
375    }
376
377    pub fn property_values(&self) -> impl Iterator<Item = &Object> + '_ {
378        self.properties.values()
379    }
380
381    pub fn property_values_mut(&mut self) -> impl Iterator<Item = &mut Object> + '_ {
382        self.properties.values_mut()
383    }
384}
385
386#[derive(Default)]
387pub struct TypedDynamicObject {
388    properties: HashMap<TypeHash, Object>,
389}
390
391impl TypedDynamicObject {
392    pub fn get<T: 'static>(&self) -> Option<&Object> {
393        self.properties.get(&TypeHash::of::<T>())
394    }
395
396    pub fn get_mut<T: 'static>(&mut self) -> Option<&mut Object> {
397        self.properties.get_mut(&TypeHash::of::<T>())
398    }
399
400    pub fn set<T: 'static>(&mut self, value: Object) {
401        self.properties.insert(TypeHash::of::<T>(), value);
402    }
403
404    pub fn delete<T: 'static>(&mut self) -> Option<Object> {
405        self.properties.remove(&TypeHash::of::<T>())
406    }
407
408    pub fn drain(&mut self) -> impl Iterator<Item = (TypeHash, Object)> + '_ {
409        self.properties.drain()
410    }
411
412    pub fn properties(&self) -> impl Iterator<Item = (&TypeHash, &Object)> + '_ {
413        self.properties.iter()
414    }
415
416    pub fn properties_mut(&mut self) -> impl Iterator<Item = (&TypeHash, &mut Object)> + '_ {
417        self.properties.iter_mut()
418    }
419
420    pub fn property_types(&self) -> impl Iterator<Item = &TypeHash> + '_ {
421        self.properties.keys()
422    }
423
424    pub fn property_values(&self) -> impl Iterator<Item = &Object> + '_ {
425        self.properties.values()
426    }
427
428    pub fn property_values_mut(&mut self) -> impl Iterator<Item = &mut Object> + '_ {
429        self.properties.values_mut()
430    }
431}
432
433#[cfg(test)]
434mod tests {
435    use crate::{
436        object::*,
437        registry::Registry,
438        types::struct_type::*,
439        utils::{object_pop_from_stack, object_push_to_stack},
440    };
441    use intuicio_data::prelude::*;
442    use std::{
443        alloc::Layout,
444        rc::{Rc, Weak},
445    };
446
447    #[test]
448    fn test_object() {
449        struct Droppable(Option<Weak<()>>);
450
451        impl Default for Droppable {
452            fn default() -> Self {
453                println!("Wrapper created!");
454                Self(None)
455            }
456        }
457
458        impl Drop for Droppable {
459            fn drop(&mut self) {
460                println!("Wrapper dropped!");
461            }
462        }
463
464        struct Pass;
465
466        impl Default for Pass {
467            fn default() -> Self {
468                println!("Pass created!");
469                Self
470            }
471        }
472
473        impl Drop for Pass {
474            fn drop(&mut self) {
475                println!("Pass dropped!");
476            }
477        }
478
479        let bool_handle = NativeStructBuilder::new::<bool>()
480            .build()
481            .into_type()
482            .into_handle();
483        let f32_handle = NativeStructBuilder::new::<f32>()
484            .build()
485            .into_type()
486            .into_handle();
487        let usize_handle = NativeStructBuilder::new::<usize>()
488            .build()
489            .into_type()
490            .into_handle();
491        let pass_handle = NativeStructBuilder::new::<Pass>()
492            .build()
493            .into_type()
494            .into_handle();
495        let droppable_handle = NativeStructBuilder::new::<Droppable>()
496            .build()
497            .into_type()
498            .into_handle();
499        let handle = RuntimeStructBuilder::new("Foo")
500            .field(StructField::new("a", bool_handle))
501            .field(StructField::new("b", f32_handle))
502            .field(StructField::new("c", usize_handle))
503            .field(StructField::new("d", pass_handle))
504            .field(StructField::new("e", droppable_handle))
505            .build()
506            .into_type()
507            .into_handle();
508        assert_eq!(handle.layout().size(), 24);
509        assert_eq!(handle.layout().align(), 8);
510        assert_eq!(handle.as_struct().unwrap().fields().len(), 5);
511        assert_eq!(
512            handle.as_struct().unwrap().fields()[0]
513                .type_handle()
514                .layout()
515                .size(),
516            1
517        );
518        assert_eq!(
519            handle.as_struct().unwrap().fields()[0]
520                .type_handle()
521                .layout()
522                .align(),
523            1
524        );
525        assert_eq!(handle.as_struct().unwrap().fields()[0].address_offset(), 0);
526        assert_eq!(
527            handle.as_struct().unwrap().fields()[1]
528                .type_handle()
529                .layout()
530                .size(),
531            4
532        );
533        assert_eq!(
534            handle.as_struct().unwrap().fields()[1]
535                .type_handle()
536                .layout()
537                .align(),
538            4
539        );
540        assert_eq!(handle.as_struct().unwrap().fields()[1].address_offset(), 4);
541        assert_eq!(
542            handle.as_struct().unwrap().fields()[2]
543                .type_handle()
544                .layout()
545                .size(),
546            8
547        );
548        assert_eq!(
549            handle.as_struct().unwrap().fields()[2]
550                .type_handle()
551                .layout()
552                .align(),
553            8
554        );
555        assert_eq!(handle.as_struct().unwrap().fields()[2].address_offset(), 8);
556        assert_eq!(
557            handle.as_struct().unwrap().fields()[3]
558                .type_handle()
559                .layout()
560                .size(),
561            0
562        );
563        assert_eq!(
564            handle.as_struct().unwrap().fields()[3]
565                .type_handle()
566                .layout()
567                .align(),
568            1
569        );
570        assert_eq!(handle.as_struct().unwrap().fields()[3].address_offset(), 16);
571        assert_eq!(
572            handle.as_struct().unwrap().fields()[4]
573                .type_handle()
574                .layout()
575                .size(),
576            8
577        );
578        assert_eq!(
579            handle.as_struct().unwrap().fields()[4]
580                .type_handle()
581                .layout()
582                .align(),
583            8
584        );
585        assert_eq!(handle.as_struct().unwrap().fields()[4].address_offset(), 16);
586        let mut object = Object::new(handle);
587        *object.write_field::<bool>("a").unwrap() = true;
588        *object.write_field::<f32>("b").unwrap() = 4.2;
589        *object.write_field::<usize>("c").unwrap() = 42;
590        let dropped = Rc::new(());
591        let dropped_weak = Rc::downgrade(&dropped);
592        object.write_field::<Droppable>("e").unwrap().0 = Some(dropped_weak);
593        assert!(*object.read_field::<bool>("a").unwrap());
594        assert_eq!(*object.read_field::<f32>("b").unwrap(), 4.2);
595        assert_eq!(*object.read_field::<usize>("c").unwrap(), 42);
596        assert_eq!(Rc::weak_count(&dropped), 1);
597        assert!(object.read_field::<()>("e").is_none());
598        drop(object);
599        assert_eq!(Rc::weak_count(&dropped), 0);
600    }
601
602    #[test]
603    fn test_drop() {
604        type Wrapper = LifetimeRefMut;
605
606        let lifetime = Lifetime::default();
607        assert!(lifetime.state().can_write(0));
608        let handle = NativeStructBuilder::new_uninitialized::<Wrapper>()
609            .build()
610            .into_type()
611            .into_handle();
612        let object = Object::with_value(handle, lifetime.borrow_mut().unwrap()).unwrap();
613        assert!(!lifetime.state().can_write(0));
614        drop(object);
615        assert!(lifetime.state().can_write(0));
616    }
617
618    #[test]
619    fn test_inner() {
620        let mut stack = DataStack::new(10240, DataStackMode::Values);
621        assert_eq!(stack.position(), 0);
622        let registry = Registry::default().with_basic_types();
623        let handle = registry.find_type(TypeQuery::of::<usize>()).unwrap();
624        let mut object = Object::new(handle);
625        *object.write::<usize>().unwrap() = 42;
626        let (handle, data) = unsafe { object.into_inner() };
627        assert_eq!(handle.type_hash(), TypeHash::of::<usize>());
628        assert_eq!(*handle.layout(), Layout::new::<usize>().pad_to_align());
629        let object = unsafe { Object::new_raw(handle, data) };
630        assert!(object_push_to_stack(object, &mut stack));
631        assert_eq!(stack.position(), 16);
632        let object = object_pop_from_stack(&mut stack, &registry).unwrap();
633        assert_eq!(*object.read::<usize>().unwrap(), 42);
634        assert_eq!(stack.position(), 0);
635    }
636}