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 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 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 = 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 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 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 pub unsafe fn memory(&self) -> &[u8] {
196 std::slice::from_raw_parts(self.memory, self.type_handle().layout().size())
197 }
198
199 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 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 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 pub unsafe fn as_ptr(&self) -> *const u8 {
303 self.memory
304 }
305
306 pub unsafe fn as_mut_ptr(&mut self) -> *mut u8 {
308 self.memory
309 }
310
311 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, ®istry).unwrap();
633 assert_eq!(*object.read::<usize>().unwrap(), 42);
634 assert_eq!(stack.position(), 0);
635 }
636}