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