intuicio_framework_dynamic/
lib.rs

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    /// # Safety
200    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    /// # Safety
269    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/// Normally references are single-threaded, but they can be sent between threads
374/// only by means of transfer mechanism. Transfer mechanism works like this:
375/// For transferred reference, we construct graph of connected unpacked objects,
376/// replacing their original content objects with special Transferred type, so they
377/// cannot be accessed later in original thread. We send that graph and on the other
378/// thread we reconstruct objects and references from that graph and return main one.
379#[derive(Debug)]
380pub struct Transferable {
381    /// { reference's object address as its unique ID: object behind reference}
382    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(&registry));
632        assert!(foo_type.is_send());
633        let bar_type = registry.add_type(Bar::define_enum(&registry));
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, &registry)), &registry),
639                me: Default::default(),
640            },
641            &registry,
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            // we need to keep it in scope, because references being
654            // actively written are not able to be transferred.
655            {
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}