1use intuicio_core::{
2 define_native_struct,
3 function::{FunctionHandle, FunctionQuery},
4 object::Object,
5 registry::Registry,
6 types::{TypeHandle, TypeQuery, struct_type::NativeStructBuilder},
7};
8use intuicio_data::{shared::Shared, type_hash::TypeHash};
9use std::{
10 cell::{Ref, RefMut},
11 collections::HashMap,
12};
13
14pub type Boolean = bool;
15pub type Integer = i64;
16pub type Real = f64;
17pub type Text = String;
18pub type Array = Vec<Reference>;
19pub type Map = HashMap<Text, Reference>;
20
21thread_local! {
22 static TRANSFERRED_STRUCT_HANDLE: TypeHandle = NativeStructBuilder::new::<Transferred>().build().into_type().into_handle();
23}
24
25#[derive(Default, Clone)]
26pub struct Type {
27 data: Option<TypeHandle>,
28}
29
30impl Type {
31 pub fn by_name(name: &str, module_name: &str, registry: &Registry) -> Option<Self> {
32 Some(Self::new(registry.find_type(TypeQuery {
33 name: Some(name.into()),
34 module_name: Some(module_name.into()),
35 ..Default::default()
36 })?))
37 }
38
39 pub fn of<T: 'static>(registry: &Registry) -> Option<Self> {
40 Some(Self::new(registry.find_type(TypeQuery {
41 type_hash: Some(TypeHash::of::<T>()),
42 ..Default::default()
43 })?))
44 }
45
46 pub fn new(handle: TypeHandle) -> Self {
47 Self { data: Some(handle) }
48 }
49
50 pub fn handle(&self) -> Option<&TypeHandle> {
51 self.data.as_ref()
52 }
53
54 pub fn is<T: 'static>(&self) -> bool {
55 self.data
56 .as_ref()
57 .map(|data| data.type_hash() == TypeHash::of::<T>())
58 .unwrap_or(false)
59 }
60
61 pub fn is_same_as(&self, other: &Self) -> bool {
62 if let (Some(this), Some(other)) = (self.data.as_ref(), other.data.as_ref()) {
63 this == other
64 } else {
65 false
66 }
67 }
68
69 pub fn type_hash(&self) -> Option<TypeHash> {
70 Some(self.data.as_ref()?.type_hash())
71 }
72}
73
74#[derive(Default, Clone)]
75pub struct Function {
76 data: Option<FunctionHandle>,
77}
78
79impl Function {
80 pub fn by_name(name: &str, module_name: &str, registry: &Registry) -> Option<Self> {
81 Some(Self::new(registry.find_function(FunctionQuery {
82 name: Some(name.into()),
83 module_name: Some(module_name.into()),
84 ..Default::default()
85 })?))
86 }
87
88 pub fn new(handle: FunctionHandle) -> Self {
89 Self { data: Some(handle) }
90 }
91
92 pub fn handle(&self) -> Option<&FunctionHandle> {
93 self.data.as_ref()
94 }
95
96 pub fn is_same_as(&self, other: &Self) -> bool {
97 if let (Some(this), Some(other)) = (self.data.as_ref(), other.data.as_ref()) {
98 this.signature() == other.signature()
99 } else {
100 false
101 }
102 }
103}
104
105#[derive(Default, Clone)]
106pub struct Reference {
107 data: Option<Shared<Object>>,
108}
109
110impl Reference {
111 pub fn null() -> Self {
112 Self { data: None }
113 }
114
115 pub fn is_null(&self) -> bool {
116 self.data.is_none()
117 }
118
119 pub fn is_transferred(&self) -> bool {
120 self.data
121 .as_ref()
122 .and_then(|data| data.read())
123 .map(|data| data.read::<Transferred>().is_some())
124 .unwrap_or_default()
125 }
126
127 pub fn is_being_written(&mut self) -> bool {
128 self.data
129 .as_mut()
130 .map(|data| data.write().is_none())
131 .unwrap_or_default()
132 }
133
134 pub fn new_boolean(value: Boolean, registry: &Registry) -> Self {
135 Self::new(value, registry)
136 }
137
138 pub fn new_integer(value: Integer, registry: &Registry) -> Self {
139 Self::new(value, registry)
140 }
141
142 pub fn new_real(value: Real, registry: &Registry) -> Self {
143 Self::new(value, registry)
144 }
145
146 pub fn new_text(value: Text, registry: &Registry) -> Self {
147 Self::new(value, registry)
148 }
149
150 pub fn new_array(value: Array, registry: &Registry) -> Self {
151 Self::new(value, registry)
152 }
153
154 pub fn new_map(value: Map, registry: &Registry) -> Self {
155 Self::new(value, registry)
156 }
157
158 pub fn new_type(value: Type, registry: &Registry) -> Self {
159 Self::new(value, registry)
160 }
161
162 pub fn new_function(value: Function, registry: &Registry) -> Self {
163 Self::new(value, registry)
164 }
165
166 pub fn new<T: 'static>(data: T, registry: &Registry) -> Self {
167 let type_ = registry.find_type(TypeQuery::of::<T>()).unwrap_or_else(|| {
168 panic!(
169 "Could not make a reference of type: {}",
170 std::any::type_name::<T>()
171 )
172 });
173 let mut value = unsafe { Object::new_uninitialized(type_).unwrap() };
174 unsafe { value.as_mut_ptr().cast::<T>().write(data) };
175 Self::new_raw(value)
176 }
177
178 pub fn new_custom<T: 'static>(data: T, ty: &Type) -> Self {
179 let mut value =
180 unsafe { Object::new_uninitialized(ty.data.as_ref().unwrap().clone()).unwrap() };
181 unsafe { value.as_mut_ptr().cast::<T>().write(data) };
182 Self::new_raw(value)
183 }
184
185 pub fn new_raw(data: Object) -> Self {
186 Self {
187 data: Some(Shared::new(data)),
188 }
189 }
190
191 pub fn new_shared(data: Shared<Object>) -> Self {
192 Self { data: Some(data) }
193 }
194
195 pub fn initialized(ty: &Type) -> Self {
196 Self::new_raw(Object::new(ty.data.as_ref().unwrap().clone()))
197 }
198
199 pub unsafe fn uninitialized(ty: &Type) -> Self {
201 Self::new_raw(unsafe {
202 Object::new_uninitialized(ty.data.as_ref().unwrap().clone()).unwrap()
203 })
204 }
205
206 pub fn type_of(&self) -> Option<Type> {
207 Some(Type::new(self.data.as_ref()?.read()?.type_handle().clone()))
208 }
209
210 pub fn read<T: 'static>(&'_ self) -> Option<Ref<'_, T>> {
211 let result = self.data.as_ref()?.read()?;
212 if result.type_handle().type_hash() == TypeHash::of::<T>() {
213 Some(Ref::map(result, |data| data.read::<T>().unwrap()))
214 } else {
215 None
216 }
217 }
218
219 pub fn write<T: 'static>(&'_ mut self) -> Option<RefMut<'_, T>> {
220 let result = self.data.as_mut()?.write()?;
221 if result.type_handle().type_hash() == TypeHash::of::<T>() {
222 Some(RefMut::map(result, |data| data.write::<T>().unwrap()))
223 } else {
224 None
225 }
226 }
227
228 pub fn read_object(&'_ self) -> Option<Ref<'_, Object>> {
229 self.data.as_ref()?.read()
230 }
231
232 pub fn write_object(&'_ mut self) -> Option<RefMut<'_, Object>> {
233 self.data.as_mut()?.write()
234 }
235
236 pub fn swap<T: 'static>(&mut self, data: T) -> Option<T> {
237 Some(std::mem::replace(
238 self.data.as_mut()?.write()?.write::<T>()?,
239 data,
240 ))
241 }
242
243 pub fn try_consume(self) -> Result<Object, Self> {
244 match self.data {
245 Some(data) => match data.try_consume() {
246 Ok(data) => Ok(data),
247 Err(data) => Err(Self { data: Some(data) }),
248 },
249 None => Err(Self::null()),
250 }
251 }
252
253 pub fn references_count(&self) -> usize {
254 self.data
255 .as_ref()
256 .map(|data| data.references_count())
257 .unwrap_or(0)
258 }
259
260 pub fn does_share_reference(&self, other: &Self, consider_null: bool) -> bool {
261 match (self.data.as_ref(), other.data.as_ref()) {
262 (Some(this), Some(other)) => this.does_share_reference(other),
263 (None, None) => consider_null,
264 _ => false,
265 }
266 }
267
268 pub unsafe fn transfer(&self) -> Option<Result<Object, usize>> {
270 let mut data = self.data.as_ref()?.write()?;
271 if let Some(data) = data.read::<Transferred>() {
272 return Some(Err(data.0));
273 }
274 if !data.type_handle().is_send() {
275 return None;
276 }
277 let mut object = unsafe {
278 Object::new_uninitialized(TRANSFERRED_STRUCT_HANDLE.with(|handle| handle.clone()))
279 .unwrap()
280 };
281 unsafe {
282 object
283 .as_mut_ptr()
284 .cast::<Transferred>()
285 .write(Transferred(data.as_ptr() as usize))
286 };
287 Some(Ok(std::mem::replace(&mut *data, object)))
288 }
289}
290
291impl std::fmt::Debug for Reference {
292 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293 match self.data.as_ref() {
294 Some(object) => {
295 if let Some(object) = object.read() {
296 f.debug_struct("Reference").field("data", &*object).finish()
297 } else {
298 f.debug_struct("Reference").field("data", &()).finish()
299 }
300 }
301 None => f.debug_struct("Reference").finish(),
302 }
303 }
304}
305
306impl From<Transferable> for Reference {
307 fn from(value: Transferable) -> Self {
308 value.reproduce()
309 }
310}
311
312#[derive(Debug)]
313enum TransferableObject {
314 Array {
315 object: Object,
316 items: Vec<Option<usize>>,
317 },
318 Map {
319 object: Object,
320 pairs: HashMap<String, Option<usize>>,
321 },
322 Object {
323 object: Object,
324 fields: HashMap<String, Option<usize>>,
325 },
326}
327
328#[derive(Debug)]
329enum TransferableReference {
330 Array {
331 reference: Reference,
332 items: Vec<Option<usize>>,
333 },
334 Map {
335 reference: Reference,
336 pairs: HashMap<String, Option<usize>>,
337 },
338 Object {
339 reference: Reference,
340 fields: HashMap<String, Option<usize>>,
341 },
342}
343
344impl From<TransferableObject> for TransferableReference {
345 fn from(value: TransferableObject) -> Self {
346 match value {
347 TransferableObject::Array { object, items } => TransferableReference::Array {
348 reference: Reference::new_raw(object),
349 items,
350 },
351 TransferableObject::Map { object, pairs } => TransferableReference::Map {
352 reference: Reference::new_raw(object),
353 pairs,
354 },
355 TransferableObject::Object { object, fields } => TransferableReference::Object {
356 reference: Reference::new_raw(object),
357 fields,
358 },
359 }
360 }
361}
362
363impl TransferableReference {
364 fn reference(&self) -> Reference {
365 match self {
366 TransferableReference::Array { reference, .. }
367 | TransferableReference::Map { reference, .. }
368 | TransferableReference::Object { reference, .. } => reference.clone(),
369 }
370 }
371}
372
373#[derive(Debug)]
380pub struct Transferable {
381 objects: HashMap<usize, TransferableObject>,
383 root: Option<usize>,
384}
385
386unsafe impl Send for Transferable {}
387unsafe impl Sync for Transferable {}
388
389impl Transferable {
390 fn produce(
391 value: Reference,
392 objects: &mut HashMap<usize, TransferableObject>,
393 ) -> Option<usize> {
394 let mut object = match unsafe { value.transfer() } {
395 Some(object) => match object {
396 Ok(object) => object,
397 Err(address) => return Some(address),
398 },
399 None => return None,
400 };
401 let address = unsafe { object.as_ptr() as usize };
402 if objects.iter().any(|object| *object.0 == address) {
403 return Some(address);
404 }
405 if let Some(array) = object.write::<Array>() {
406 let items = array
407 .iter_mut()
408 .map(|value| Self::produce(std::mem::replace(value, Reference::null()), objects))
409 .collect();
410 objects.insert(address, TransferableObject::Array { object, items });
411 } else if let Some(map) = object.write::<Map>() {
412 let pairs = map
413 .iter_mut()
414 .map(|(key, value)| {
415 (
416 key.to_owned(),
417 Self::produce(std::mem::replace(value, Reference::null()), objects),
418 )
419 })
420 .collect();
421 objects.insert(address, TransferableObject::Map { object, pairs });
422 } else {
423 match &*object.type_handle().clone() {
424 intuicio_core::types::Type::Struct(type_) => {
425 let fields = type_
426 .fields()
427 .iter()
428 .filter_map(|field| {
429 let value = object.write_field::<Reference>(&field.name)?;
430 Some((
431 field.name.to_owned(),
432 Self::produce(std::mem::replace(value, Reference::null()), objects),
433 ))
434 })
435 .collect();
436 objects.insert(address, TransferableObject::Object { object, fields });
437 }
438 intuicio_core::types::Type::Enum(type_) => {
439 let discriminant = unsafe { object.as_ptr().read() };
440 if let Some(variant) = type_.find_variant_by_discriminant(discriminant) {
441 let fields = variant
442 .fields
443 .iter()
444 .filter_map(|field| {
445 let value = object.write_field::<Reference>(&field.name)?;
446 Some((
447 field.name.to_owned(),
448 Self::produce(
449 std::mem::replace(value, Reference::null()),
450 objects,
451 ),
452 ))
453 })
454 .collect();
455 objects.insert(address, TransferableObject::Object { object, fields });
456 }
457 }
458 }
459 }
460 Some(address)
461 }
462
463 fn reproduce(self) -> Reference {
464 let Some(root) = self.root else {
465 return Reference::null();
466 };
467 let mut results = self
468 .objects
469 .into_iter()
470 .map(|(address, object)| (address, TransferableReference::from(object)))
471 .collect::<HashMap<_, _>>();
472 let references = results
473 .iter()
474 .map(|(address, reference)| (*address, reference.reference()))
475 .collect::<HashMap<_, _>>();
476 for reference in results.values_mut() {
477 match reference {
478 TransferableReference::Array { reference, items } => {
479 if let Some(mut array) = reference.write::<Array>() {
480 for (index, value) in array.iter_mut().enumerate() {
481 if let Some(address) = items.get(index) {
482 *value = address
483 .and_then(|address| references.get(&address).cloned())
484 .unwrap_or_default();
485 } else {
486 *value = Reference::null();
487 }
488 }
489 }
490 }
491 TransferableReference::Map { reference, pairs } => {
492 if let Some(mut map) = reference.write::<Map>() {
493 for (key, value) in map.iter_mut() {
494 if let Some(address) = pairs.get(key) {
495 *value = address
496 .and_then(|address| references.get(&address).cloned())
497 .unwrap_or_default();
498 } else {
499 *value = Reference::null();
500 }
501 }
502 }
503 }
504 TransferableReference::Object { reference, fields } => {
505 if let Some(mut object) = reference.write_object() {
506 match &**object.type_handle() {
507 intuicio_core::types::Type::Struct(type_) => {
508 let names = type_
509 .fields()
510 .iter()
511 .map(|field| field.name.to_owned())
512 .collect::<Vec<_>>();
513 for name in names {
514 if let Some(value) = object.write_field::<Reference>(&name) {
515 if let Some(address) = fields.get(&name) {
516 *value = address
517 .and_then(|address| {
518 references.get(&address).cloned()
519 })
520 .unwrap_or_default();
521 } else {
522 *value = Reference::null();
523 }
524 }
525 }
526 }
527 intuicio_core::types::Type::Enum(type_) => {
528 let discriminant = unsafe { object.as_ptr().read() };
529 if let Some(variant) =
530 type_.find_variant_by_discriminant(discriminant)
531 {
532 let names = variant
533 .fields
534 .iter()
535 .map(|field| field.name.to_owned())
536 .collect::<Vec<_>>();
537 for name in names {
538 if let Some(value) = object.write_field::<Reference>(&name)
539 {
540 if let Some(address) = fields.get(&name) {
541 *value = address
542 .and_then(|address| {
543 references.get(&address).cloned()
544 })
545 .unwrap_or_default();
546 } else {
547 *value = Reference::null();
548 }
549 }
550 }
551 }
552 }
553 }
554 }
555 }
556 }
557 }
558 references.get(&root).cloned().unwrap_or_default()
559 }
560}
561
562impl From<Reference> for Transferable {
563 fn from(value: Reference) -> Self {
564 let mut objects = Default::default();
565 let root = Transferable::produce(value, &mut objects);
566 Self { objects, root }
567 }
568}
569
570#[derive(Debug, Default)]
571pub struct Transferred(usize);
572
573pub fn install(registry: &mut Registry) {
574 registry.add_type(define_native_struct! {
575 registry => mod reflect struct Reference (Reference) {}
576 [override_send = true]
577 });
578 registry.add_type(define_native_struct! {
579 registry => mod reflect struct Type (Type) {}
580 });
581 registry.add_type(define_native_struct! {
582 registry => mod reflect struct Function (Function) {}
583 });
584 registry.add_type(define_native_struct! {
585 registry => mod math struct Boolean (Boolean) {}
586 });
587 registry.add_type(define_native_struct! {
588 registry => mod math struct Integer (Integer) {}
589 });
590 registry.add_type(define_native_struct! {
591 registry => mod math struct Real (Real) {}
592 });
593 registry.add_type(define_native_struct! {
594 registry => mod math struct Text (Text) {}
595 });
596 registry.add_type(define_native_struct! {
597 registry => mod math struct Array (Array) {}
598 });
599 registry.add_type(define_native_struct! {
600 registry => mod math struct Map (Map) {}
601 });
602}
603
604#[cfg(test)]
605mod tests {
606 use crate::{Integer, Reference, Transferable};
607 use intuicio_core::{IntuicioEnum, IntuicioStruct, registry::Registry};
608 use intuicio_derive::*;
609 use std::thread::spawn;
610
611 #[test]
612 fn test_threading() {
613 #[derive(IntuicioStruct, Default)]
614 #[intuicio(name = "Foo", module_name = "test", override_send = true)]
615 struct Foo {
616 pub v: Reference,
617 pub me: Reference,
618 }
619
620 #[derive(IntuicioEnum, Default)]
621 #[intuicio(name = "Bar", module_name = "test", override_send = true)]
622 #[repr(u8)]
623 enum Bar {
624 #[default]
625 A,
626 B(Reference),
627 }
628
629 let mut registry = Registry::default();
630 crate::install(&mut registry);
631 let foo_type = registry.add_type(Foo::define_struct(®istry));
632 assert!(foo_type.is_send());
633 let bar_type = registry.add_type(Bar::define_enum(®istry));
634 assert!(bar_type.is_send());
635
636 let mut value = Reference::new(
637 Foo {
638 v: Reference::new(Bar::B(Reference::new(0 as Integer, ®istry)), ®istry),
639 me: Default::default(),
640 },
641 ®istry,
642 );
643 let me = value.clone();
644 value.write::<Foo>().unwrap().me = me;
645 let transferable = Transferable::from(value.clone());
646 assert!(value.is_transferred());
647
648 let handle = spawn(|| {
649 let mut registry = Registry::default();
650 crate::install(&mut registry);
651 let object = Reference::from(transferable);
652
653 {
656 let mut value = object.clone();
657 let mut value = value.write::<Foo>().unwrap();
658 let mut value = value.v.write::<Bar>().unwrap();
659 if let Bar::B(value) = &mut *value {
660 let mut value = value.write::<Integer>().unwrap();
661 while *value < 42 {
662 *value += 1;
663 }
664 }
665 }
666
667 Transferable::from(object)
668 });
669
670 let object = Reference::from(handle.join().unwrap());
671 assert!(!object.is_null());
672 assert!(object.type_of().unwrap().is::<Foo>());
673 let value = object.read::<Foo>().unwrap();
674 assert!(!value.v.is_null());
675 assert!(value.v.type_of().unwrap().is::<Bar>());
676 if let Bar::B(value) = &*value.v.read::<Bar>().unwrap() {
677 assert!(value.type_of().unwrap().is::<Integer>());
678 assert_eq!(*value.read::<Integer>().unwrap(), 42);
679 }
680 assert!(!value.me.is_null());
681 assert!(value.me.type_of().unwrap().is::<Foo>());
682 assert!(value.me.does_share_reference(&object, true));
683 }
684}