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::prelude::*;
455 use std::{
456 alloc::Layout,
457 rc::{Rc, Weak},
458 };
459
460 #[test]
461 fn test_object() {
462 struct Droppable(Option<Weak<()>>);
463
464 impl Default for Droppable {
465 fn default() -> Self {
466 println!("Wrapper created!");
467 Self(None)
468 }
469 }
470
471 impl Drop for Droppable {
472 fn drop(&mut self) {
473 println!("Wrapper dropped!");
474 }
475 }
476
477 struct Pass;
478
479 impl Default for Pass {
480 fn default() -> Self {
481 println!("Pass created!");
482 Self
483 }
484 }
485
486 impl Drop for Pass {
487 fn drop(&mut self) {
488 println!("Pass dropped!");
489 }
490 }
491
492 let bool_handle = NativeStructBuilder::new::<bool>()
493 .build()
494 .into_type()
495 .into_handle();
496 let f32_handle = NativeStructBuilder::new::<f32>()
497 .build()
498 .into_type()
499 .into_handle();
500 let usize_handle = NativeStructBuilder::new::<usize>()
501 .build()
502 .into_type()
503 .into_handle();
504 let pass_handle = NativeStructBuilder::new::<Pass>()
505 .build()
506 .into_type()
507 .into_handle();
508 let droppable_handle = NativeStructBuilder::new::<Droppable>()
509 .build()
510 .into_type()
511 .into_handle();
512 let handle = RuntimeStructBuilder::new("Foo")
513 .field(StructField::new("a", bool_handle))
514 .field(StructField::new("b", f32_handle))
515 .field(StructField::new("c", usize_handle))
516 .field(StructField::new("d", pass_handle))
517 .field(StructField::new("e", droppable_handle))
518 .build()
519 .into_type()
520 .into_handle();
521 assert_eq!(handle.layout().size(), 24);
522 assert_eq!(handle.layout().align(), 8);
523 assert_eq!(handle.as_struct().unwrap().fields().len(), 5);
524 assert_eq!(
525 handle.as_struct().unwrap().fields()[0]
526 .type_handle()
527 .layout()
528 .size(),
529 1
530 );
531 assert_eq!(
532 handle.as_struct().unwrap().fields()[0]
533 .type_handle()
534 .layout()
535 .align(),
536 1
537 );
538 assert_eq!(handle.as_struct().unwrap().fields()[0].address_offset(), 0);
539 assert_eq!(
540 handle.as_struct().unwrap().fields()[1]
541 .type_handle()
542 .layout()
543 .size(),
544 4
545 );
546 assert_eq!(
547 handle.as_struct().unwrap().fields()[1]
548 .type_handle()
549 .layout()
550 .align(),
551 4
552 );
553 assert_eq!(handle.as_struct().unwrap().fields()[1].address_offset(), 4);
554 assert_eq!(
555 handle.as_struct().unwrap().fields()[2]
556 .type_handle()
557 .layout()
558 .size(),
559 8
560 );
561 assert_eq!(
562 handle.as_struct().unwrap().fields()[2]
563 .type_handle()
564 .layout()
565 .align(),
566 8
567 );
568 assert_eq!(handle.as_struct().unwrap().fields()[2].address_offset(), 8);
569 assert_eq!(
570 handle.as_struct().unwrap().fields()[3]
571 .type_handle()
572 .layout()
573 .size(),
574 0
575 );
576 assert_eq!(
577 handle.as_struct().unwrap().fields()[3]
578 .type_handle()
579 .layout()
580 .align(),
581 1
582 );
583 assert_eq!(handle.as_struct().unwrap().fields()[3].address_offset(), 16);
584 assert_eq!(
585 handle.as_struct().unwrap().fields()[4]
586 .type_handle()
587 .layout()
588 .size(),
589 8
590 );
591 assert_eq!(
592 handle.as_struct().unwrap().fields()[4]
593 .type_handle()
594 .layout()
595 .align(),
596 8
597 );
598 assert_eq!(handle.as_struct().unwrap().fields()[4].address_offset(), 16);
599 let mut object = Object::new(handle);
600 *object.write_field::<bool>("a").unwrap() = true;
601 *object.write_field::<f32>("b").unwrap() = 4.2;
602 *object.write_field::<usize>("c").unwrap() = 42;
603 let dropped = Rc::new(());
604 let dropped_weak = Rc::downgrade(&dropped);
605 object.write_field::<Droppable>("e").unwrap().0 = Some(dropped_weak);
606 assert!(*object.read_field::<bool>("a").unwrap());
607 assert_eq!(*object.read_field::<f32>("b").unwrap(), 4.2);
608 assert_eq!(*object.read_field::<usize>("c").unwrap(), 42);
609 assert_eq!(Rc::weak_count(&dropped), 1);
610 assert!(object.read_field::<()>("e").is_none());
611 drop(object);
612 assert_eq!(Rc::weak_count(&dropped), 0);
613 }
614
615 #[test]
616 fn test_drop() {
617 type Wrapper = LifetimeRefMut;
618
619 let lifetime = Lifetime::default();
620 assert!(lifetime.state().can_write(0));
621 let handle = NativeStructBuilder::new_uninitialized::<Wrapper>()
622 .build()
623 .into_type()
624 .into_handle();
625 let object = Object::with_value(handle, lifetime.borrow_mut().unwrap()).unwrap();
626 assert!(!lifetime.state().can_write(0));
627 drop(object);
628 assert!(lifetime.state().can_write(0));
629 }
630
631 #[test]
632 fn test_inner() {
633 let mut stack = DataStack::new(10240, DataStackMode::Values);
634 assert_eq!(stack.position(), 0);
635 let registry = Registry::default().with_basic_types();
636 let handle = registry.find_type(TypeQuery::of::<usize>()).unwrap();
637 let mut object = Object::new(handle);
638 *object.write::<usize>().unwrap() = 42;
639 let (handle, data) = unsafe { object.into_inner() };
640 assert_eq!(handle.type_hash(), TypeHash::of::<usize>());
641 assert_eq!(*handle.layout(), Layout::new::<usize>().pad_to_align());
642 let object = unsafe { Object::new_raw(handle, data) };
643 assert!(object_push_to_stack(object, &mut stack));
644 assert_eq!(stack.position(), 16);
645 let object = object_pop_from_stack(&mut stack, ®istry).unwrap();
646 assert_eq!(*object.read::<usize>().unwrap(), 42);
647 assert_eq!(stack.position(), 0);
648 }
649}