1use crate::types::{StructFieldQuery, Type, TypeHandle, TypeQuery};
10use intuicio_data::{Initialize, non_zero_alloc, non_zero_dealloc, type_hash::TypeHash};
11use std::collections::HashMap;
12
13pub struct RuntimeObject;
18
19impl Initialize for RuntimeObject {
20 fn initialize() -> Self {
21 Self
22 }
23}
24
25pub struct Object {
34 handle: TypeHandle,
35 memory: *mut u8,
36 drop: bool,
37}
38
39impl Drop for Object {
40 fn drop(&mut self) {
41 if self.drop {
42 unsafe {
43 if self.memory.is_null() {
44 return;
45 }
46 self.handle.finalize(self.memory.cast::<()>());
47 non_zero_dealloc(self.memory, *self.handle.layout());
48 self.memory = std::ptr::null_mut();
49 }
50 }
51 }
52}
53
54impl Object {
55 pub fn new(handle: TypeHandle) -> Self {
62 if !handle.can_initialize() {
63 panic!(
64 "Objects of type `{}::{}` cannot be initialized!",
65 handle.module_name().unwrap_or(""),
66 handle.name()
67 );
68 }
69 let memory = unsafe { non_zero_alloc(*handle.layout()) };
70 let mut result = Self {
71 memory,
72 handle,
73 drop: true,
74 };
75 unsafe { result.initialize() };
76 result
77 }
78
79 pub fn try_new(handle: TypeHandle) -> Option<Self> {
81 if handle.can_initialize() {
82 let memory = unsafe { non_zero_alloc(*handle.layout()) };
83 if memory.is_null() {
84 None
85 } else {
86 let mut result = Self {
87 memory,
88 handle,
89 drop: true,
90 };
91 unsafe { result.initialize() };
92 Some(result)
93 }
94 } else {
95 None
96 }
97 }
98
99 pub unsafe fn new_uninitialized(handle: TypeHandle) -> Option<Self> {
107 let memory = unsafe { non_zero_alloc(*handle.layout()) };
108 if memory.is_null() {
109 None
110 } else {
111 Some(Self {
112 memory,
113 handle,
114 drop: true,
115 })
116 }
117 }
118
119 pub unsafe fn new_raw(handle: TypeHandle, memory: *mut u8) -> Self {
126 Self {
127 memory,
128 handle,
129 drop: true,
130 }
131 }
132
133 pub unsafe fn from_bytes(handle: TypeHandle, bytes: &[u8]) -> Option<Self> {
142 if handle.layout().size() == bytes.len() {
143 let memory = unsafe { non_zero_alloc(*handle.layout()) };
144 if memory.is_null() {
145 None
146 } else {
147 unsafe { memory.copy_from(bytes.as_ptr(), bytes.len()) };
148 Some(Self {
149 memory,
150 handle,
151 drop: true,
152 })
153 }
154 } else {
155 None
156 }
157 }
158
159 pub fn with_value<T: 'static>(handle: TypeHandle, value: T) -> Option<Self> {
162 if handle.type_hash() == TypeHash::of::<T>() {
163 unsafe {
164 let mut result = Self::new_uninitialized(handle)?;
165 result.as_mut_ptr().cast::<T>().write(value);
166 Some(result)
167 }
168 } else {
169 None
170 }
171 }
172
173 pub unsafe fn initialize(&mut self) {
180 if self.handle.is_native() {
181 unsafe { self.handle.initialize(self.memory.cast::<()>()) };
182 } else {
183 match &*self.handle {
184 Type::Struct(type_) => {
185 for field in type_.fields() {
186 unsafe {
187 field
188 .type_handle()
189 .initialize(self.memory.add(field.address_offset()).cast::<()>())
190 };
191 }
192 }
193 Type::Enum(type_) => {
194 if let Some(variant) = type_.default_variant() {
195 unsafe { self.memory.write(variant.discriminant()) };
196 for field in &variant.fields {
197 unsafe {
198 field.type_handle().initialize(
199 self.memory.add(field.address_offset()).cast::<()>(),
200 )
201 };
202 }
203 }
204 }
205 }
206 }
207 }
208
209 pub fn consume<T: 'static>(mut self) -> Result<T, Self> {
212 if self.handle.type_hash() == TypeHash::of::<T>() {
213 self.drop = false;
214 unsafe { Ok(self.memory.cast::<T>().read()) }
215 } else {
216 Err(self)
217 }
218 }
219
220 pub unsafe fn into_inner(mut self) -> (TypeHandle, *mut u8) {
228 self.drop = false;
229 (self.handle.clone(), self.memory)
230 }
231
232 pub fn type_handle(&self) -> &TypeHandle {
234 &self.handle
235 }
236
237 pub unsafe fn memory(&self) -> &[u8] {
244 unsafe { std::slice::from_raw_parts(self.memory, self.type_handle().layout().size()) }
245 }
246
247 pub unsafe fn memory_mut(&mut self) -> &mut [u8] {
254 unsafe { std::slice::from_raw_parts_mut(self.memory, self.type_handle().layout().size()) }
255 }
256
257 pub unsafe fn field_memory<'a>(&'a self, query: StructFieldQuery<'a>) -> Option<&'a [u8]> {
266 match &*self.handle {
267 Type::Struct(type_) => {
268 let field = type_.find_field(query)?;
269 Some(unsafe {
270 std::slice::from_raw_parts(
271 self.memory.add(field.address_offset()),
272 field.type_handle().layout().size(),
273 )
274 })
275 }
276 Type::Enum(type_) => {
277 let discriminant = unsafe { self.memory.read() };
278 let variant = type_.find_variant_by_discriminant(discriminant)?;
279 let field = variant.find_field(query)?;
280 Some(unsafe {
281 std::slice::from_raw_parts(
282 self.memory.add(field.address_offset()),
283 field.type_handle().layout().size(),
284 )
285 })
286 }
287 }
288 }
289
290 pub unsafe fn field_memory_mut<'a>(
299 &'a mut self,
300 query: StructFieldQuery<'a>,
301 ) -> Option<&'a mut [u8]> {
302 match &*self.handle {
303 Type::Struct(type_) => {
304 let field = type_.find_field(query)?;
305 Some(unsafe {
306 std::slice::from_raw_parts_mut(
307 self.memory.add(field.address_offset()),
308 field.type_handle().layout().size(),
309 )
310 })
311 }
312 Type::Enum(type_) => {
313 let discriminant = unsafe { self.memory.read() };
314 let variant = type_.find_variant_by_discriminant(discriminant)?;
315 let field = variant.find_field(query)?;
316 Some(unsafe {
317 std::slice::from_raw_parts_mut(
318 self.memory.add(field.address_offset()),
319 field.type_handle().layout().size(),
320 )
321 })
322 }
323 }
324 }
325
326 pub fn read<T: 'static>(&self) -> Option<&T> {
328 if self.handle.type_hash() == TypeHash::of::<T>() {
329 unsafe { self.memory.cast::<T>().as_ref() }
330 } else {
331 None
332 }
333 }
334
335 pub fn write<T: 'static>(&mut self) -> Option<&mut T> {
338 if self.handle.type_hash() == TypeHash::of::<T>() {
339 unsafe { self.memory.cast::<T>().as_mut() }
340 } else {
341 None
342 }
343 }
344
345 pub fn read_field<'a, T: 'static>(&'a self, field: &str) -> Option<&'a T> {
351 let query = StructFieldQuery {
352 name: Some(field.into()),
353 type_query: Some(TypeQuery::of::<T>()),
354 ..Default::default()
355 };
356 let field = match &*self.handle {
357 Type::Struct(type_) => type_.find_field(query),
358 Type::Enum(type_) => {
359 let discriminant = unsafe { self.memory.read() };
360 let variant = type_.find_variant_by_discriminant(discriminant)?;
361 variant.find_field(query)
362 }
363 }?;
364 unsafe { self.memory.add(field.address_offset()).cast::<T>().as_ref() }
365 }
366
367 pub fn write_field<'a, T: 'static>(&'a mut self, field: &str) -> Option<&'a mut T> {
369 let query = StructFieldQuery {
370 name: Some(field.into()),
371 type_query: Some(TypeQuery::of::<T>()),
372 ..Default::default()
373 };
374 let field = match &*self.handle {
375 Type::Struct(type_) => type_.find_field(query),
376 Type::Enum(type_) => {
377 let discriminant = unsafe { self.memory.read() };
378 let variant = type_.find_variant_by_discriminant(discriminant)?;
379 variant.find_field(query)
380 }
381 }?;
382 unsafe { self.memory.add(field.address_offset()).cast::<T>().as_mut() }
383 }
384
385 pub unsafe fn as_ptr(&self) -> *const u8 {
391 self.memory
392 }
393
394 pub unsafe fn as_mut_ptr(&mut self) -> *mut u8 {
400 self.memory
401 }
402
403 pub unsafe fn prevent_drop(&mut self) {
409 self.drop = false;
410 }
411}
412
413impl std::fmt::Debug for Object {
414 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
415 unsafe {
416 f.debug_struct("Object")
417 .field("address", &(self.as_ptr() as usize))
418 .field(
419 "type",
420 &format!(
421 "{}::{}",
422 self.handle.module_name().unwrap_or_default(),
423 self.handle.name()
424 ),
425 )
426 .finish()
427 }
428 }
429}
430
431#[derive(Default)]
436pub struct DynamicObject {
437 properties: HashMap<String, Object>,
438}
439
440impl DynamicObject {
441 pub fn get(&self, name: &str) -> Option<&Object> {
443 self.properties.get(name)
444 }
445
446 pub fn get_mut(&mut self, name: &str) -> Option<&mut Object> {
448 self.properties.get_mut(name)
449 }
450
451 pub fn set(&mut self, name: impl ToString, value: Object) {
453 self.properties.insert(name.to_string(), value);
454 }
455
456 pub fn delete(&mut self, name: &str) -> Option<Object> {
458 self.properties.remove(name)
459 }
460
461 pub fn drain(&mut self) -> impl Iterator<Item = (String, Object)> + '_ {
463 self.properties.drain()
464 }
465
466 pub fn properties(&self) -> impl Iterator<Item = (&str, &Object)> + '_ {
468 self.properties
469 .iter()
470 .map(|(key, value)| (key.as_str(), value))
471 }
472
473 pub fn properties_mut(&mut self) -> impl Iterator<Item = (&str, &mut Object)> + '_ {
475 self.properties
476 .iter_mut()
477 .map(|(key, value)| (key.as_str(), value))
478 }
479
480 pub fn property_names(&self) -> impl Iterator<Item = &str> + '_ {
482 self.properties.keys().map(|key| key.as_str())
483 }
484
485 pub fn property_values(&self) -> impl Iterator<Item = &Object> + '_ {
487 self.properties.values()
488 }
489
490 pub fn property_values_mut(&mut self) -> impl Iterator<Item = &mut Object> + '_ {
492 self.properties.values_mut()
493 }
494}
495
496#[derive(Default)]
501pub struct TypedDynamicObject {
502 properties: HashMap<TypeHash, Object>,
503}
504
505impl TypedDynamicObject {
506 pub fn get<T: 'static>(&self) -> Option<&Object> {
508 self.properties.get(&TypeHash::of::<T>())
509 }
510
511 pub fn get_mut<T: 'static>(&mut self) -> Option<&mut Object> {
513 self.properties.get_mut(&TypeHash::of::<T>())
514 }
515
516 pub fn set<T: 'static>(&mut self, value: Object) {
518 self.properties.insert(TypeHash::of::<T>(), value);
519 }
520
521 pub fn delete<T: 'static>(&mut self) -> Option<Object> {
523 self.properties.remove(&TypeHash::of::<T>())
524 }
525
526 pub fn drain(&mut self) -> impl Iterator<Item = (TypeHash, Object)> + '_ {
528 self.properties.drain()
529 }
530
531 pub fn properties(&self) -> impl Iterator<Item = (&TypeHash, &Object)> + '_ {
533 self.properties.iter()
534 }
535
536 pub fn properties_mut(&mut self) -> impl Iterator<Item = (&TypeHash, &mut Object)> + '_ {
538 self.properties.iter_mut()
539 }
540
541 pub fn property_types(&self) -> impl Iterator<Item = &TypeHash> + '_ {
543 self.properties.keys()
544 }
545
546 pub fn property_values(&self) -> impl Iterator<Item = &Object> + '_ {
548 self.properties.values()
549 }
550
551 pub fn property_values_mut(&mut self) -> impl Iterator<Item = &mut Object> + '_ {
553 self.properties.values_mut()
554 }
555}
556
557#[cfg(test)]
558mod tests {
559 use crate::{
560 object::*,
561 registry::Registry,
562 types::struct_type::*,
563 utils::{object_pop_from_stack, object_push_to_stack},
564 };
565 use intuicio_data::{
566 data_stack::{DataStack, DataStackMode},
567 lifetime::{Lifetime, LifetimeRefMut},
568 };
569 use std::{
570 alloc::Layout,
571 rc::{Rc, Weak},
572 };
573
574 #[test]
575 fn test_object() {
576 struct Droppable(Option<Weak<()>>);
577
578 impl Default for Droppable {
579 fn default() -> Self {
580 println!("Wrapper created!");
581 Self(None)
582 }
583 }
584
585 impl Drop for Droppable {
586 fn drop(&mut self) {
587 println!("Wrapper dropped!");
588 }
589 }
590
591 struct Pass;
592
593 impl Default for Pass {
594 fn default() -> Self {
595 println!("Pass created!");
596 Self
597 }
598 }
599
600 impl Drop for Pass {
601 fn drop(&mut self) {
602 println!("Pass dropped!");
603 }
604 }
605
606 let bool_handle = NativeStructBuilder::new::<bool>()
607 .build()
608 .into_type()
609 .into_handle();
610 let f32_handle = NativeStructBuilder::new::<f32>()
611 .build()
612 .into_type()
613 .into_handle();
614 let usize_handle = NativeStructBuilder::new::<usize>()
615 .build()
616 .into_type()
617 .into_handle();
618 let pass_handle = NativeStructBuilder::new::<Pass>()
619 .build()
620 .into_type()
621 .into_handle();
622 let droppable_handle = NativeStructBuilder::new::<Droppable>()
623 .build()
624 .into_type()
625 .into_handle();
626 let handle = RuntimeStructBuilder::new("Foo")
627 .field(StructField::new("a", bool_handle))
628 .field(StructField::new("b", f32_handle))
629 .field(StructField::new("c", usize_handle))
630 .field(StructField::new("d", pass_handle))
631 .field(StructField::new("e", droppable_handle))
632 .build()
633 .into_type()
634 .into_handle();
635 assert_eq!(handle.layout().size(), 24);
636 assert_eq!(handle.layout().align(), 8);
637 assert_eq!(handle.as_struct().unwrap().fields().len(), 5);
638 assert_eq!(
639 handle.as_struct().unwrap().fields()[0]
640 .type_handle()
641 .layout()
642 .size(),
643 1
644 );
645 assert_eq!(
646 handle.as_struct().unwrap().fields()[0]
647 .type_handle()
648 .layout()
649 .align(),
650 1
651 );
652 assert_eq!(handle.as_struct().unwrap().fields()[0].address_offset(), 0);
653 assert_eq!(
654 handle.as_struct().unwrap().fields()[1]
655 .type_handle()
656 .layout()
657 .size(),
658 4
659 );
660 assert_eq!(
661 handle.as_struct().unwrap().fields()[1]
662 .type_handle()
663 .layout()
664 .align(),
665 4
666 );
667 assert_eq!(handle.as_struct().unwrap().fields()[1].address_offset(), 4);
668 assert_eq!(
669 handle.as_struct().unwrap().fields()[2]
670 .type_handle()
671 .layout()
672 .size(),
673 8
674 );
675 assert_eq!(
676 handle.as_struct().unwrap().fields()[2]
677 .type_handle()
678 .layout()
679 .align(),
680 8
681 );
682 assert_eq!(handle.as_struct().unwrap().fields()[2].address_offset(), 8);
683 assert_eq!(
684 handle.as_struct().unwrap().fields()[3]
685 .type_handle()
686 .layout()
687 .size(),
688 0
689 );
690 assert_eq!(
691 handle.as_struct().unwrap().fields()[3]
692 .type_handle()
693 .layout()
694 .align(),
695 1
696 );
697 assert_eq!(handle.as_struct().unwrap().fields()[3].address_offset(), 16);
698 assert_eq!(
699 handle.as_struct().unwrap().fields()[4]
700 .type_handle()
701 .layout()
702 .size(),
703 8
704 );
705 assert_eq!(
706 handle.as_struct().unwrap().fields()[4]
707 .type_handle()
708 .layout()
709 .align(),
710 8
711 );
712 assert_eq!(handle.as_struct().unwrap().fields()[4].address_offset(), 16);
713 let mut object = Object::new(handle);
714 *object.write_field::<bool>("a").unwrap() = true;
715 *object.write_field::<f32>("b").unwrap() = 4.2;
716 *object.write_field::<usize>("c").unwrap() = 42;
717 let dropped = Rc::new(());
718 let dropped_weak = Rc::downgrade(&dropped);
719 object.write_field::<Droppable>("e").unwrap().0 = Some(dropped_weak);
720 assert!(*object.read_field::<bool>("a").unwrap());
721 assert_eq!(*object.read_field::<f32>("b").unwrap(), 4.2);
722 assert_eq!(*object.read_field::<usize>("c").unwrap(), 42);
723 assert_eq!(Rc::weak_count(&dropped), 1);
724 assert!(object.read_field::<()>("e").is_none());
725 drop(object);
726 assert_eq!(Rc::weak_count(&dropped), 0);
727 }
728
729 #[test]
730 fn test_drop() {
731 type Wrapper = LifetimeRefMut;
732
733 let lifetime = Lifetime::default();
734 assert!(lifetime.state().can_write(0));
735 let handle = NativeStructBuilder::new_uninitialized::<Wrapper>()
736 .build()
737 .into_type()
738 .into_handle();
739 let object = Object::with_value(handle, lifetime.borrow_mut().unwrap()).unwrap();
740 assert!(!lifetime.state().can_write(0));
741 drop(object);
742 assert!(lifetime.state().can_write(0));
743 }
744
745 #[test]
746 fn test_inner() {
747 let mut stack = DataStack::new(10240, DataStackMode::Values);
748 assert_eq!(stack.position(), 0);
749 let registry = Registry::default().with_basic_types();
750 let handle = registry.find_type(TypeQuery::of::<usize>()).unwrap();
751 let mut object = Object::new(handle);
752 *object.write::<usize>().unwrap() = 42;
753 let (handle, data) = unsafe { object.into_inner() };
754 assert_eq!(handle.type_hash(), TypeHash::of::<usize>());
755 assert_eq!(*handle.layout(), Layout::new::<usize>().pad_to_align());
756 let object = unsafe { Object::new_raw(handle, data) };
757 assert!(object_push_to_stack(object, &mut stack));
758 assert_eq!(
759 stack.position(),
760 if cfg!(feature = "typehash_debug_name") {
761 32
762 } else {
763 16
764 }
765 );
766 let object = object_pop_from_stack(&mut stack, ®istry).unwrap();
767 assert_eq!(*object.read::<usize>().unwrap(), 42);
768 assert_eq!(stack.position(), 0);
769 }
770}