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