intuicio_data/
managed_gc.rs

1use crate::{
2    Finalize,
3    lifetime::{Lifetime, LifetimeLazy, ValueReadAccess, ValueWriteAccess},
4    managed::{
5        DynamicManagedLazy, DynamicManagedRef, DynamicManagedRefMut, ManagedLazy, ManagedRef,
6        ManagedRefMut,
7    },
8    non_zero_alloc, non_zero_dealloc,
9    type_hash::TypeHash,
10};
11use std::{
12    alloc::{Layout, handle_alloc_error},
13    marker::PhantomData,
14    mem::MaybeUninit,
15};
16
17enum Kind {
18    Owned {
19        lifetime: Box<Lifetime>,
20        data: *mut u8,
21    },
22    Referenced {
23        lifetime: LifetimeLazy,
24        data: *mut u8,
25    },
26}
27
28pub enum ManagedGcLifetime<'a> {
29    Owned(&'a Lifetime),
30    Referenced(&'a LifetimeLazy),
31}
32
33pub struct ManagedGc<T> {
34    dynamic: DynamicManagedGc,
35    _phantom: PhantomData<fn() -> T>,
36}
37
38unsafe impl<T> Send for ManagedGc<T> {}
39unsafe impl<T> Sync for ManagedGc<T> {}
40
41impl<T: Default> Default for ManagedGc<T> {
42    fn default() -> Self {
43        Self::new(T::default())
44    }
45}
46
47impl<T> ManagedGc<T> {
48    pub fn new(data: T) -> Self {
49        Self {
50            dynamic: DynamicManagedGc::new(data),
51            _phantom: PhantomData,
52        }
53    }
54
55    /// # Safety
56    pub unsafe fn new_cyclic(f: impl FnOnce(Self) -> T) -> Self {
57        Self {
58            dynamic: unsafe { DynamicManagedGc::new_cyclic(|dynamic| f(dynamic.into_typed())) },
59            _phantom: PhantomData,
60        }
61    }
62
63    pub fn reference(&self) -> Self {
64        Self {
65            dynamic: self.dynamic.reference(),
66            _phantom: PhantomData,
67        }
68    }
69
70    pub fn consume(self) -> Result<T, Self> {
71        self.dynamic.consume().map_err(|value| Self {
72            dynamic: value,
73            _phantom: PhantomData,
74        })
75    }
76
77    pub fn into_dynamic(self) -> DynamicManagedGc {
78        self.dynamic
79    }
80
81    pub fn renew(&mut self) {
82        self.dynamic.renew();
83    }
84
85    pub fn type_hash(&self) -> TypeHash {
86        self.dynamic.type_hash()
87    }
88
89    pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
90        self.dynamic.lifetime()
91    }
92
93    pub fn exists(&self) -> bool {
94        self.dynamic.exists()
95    }
96
97    pub fn is_owning(&self) -> bool {
98        self.dynamic.is_owning()
99    }
100
101    pub fn is_referencing(&self) -> bool {
102        self.dynamic.is_referencing()
103    }
104
105    pub fn is_owned_by(&self, other: &Self) -> bool {
106        self.dynamic.is_owned_by(&other.dynamic)
107    }
108
109    pub fn try_read(&'_ self) -> Option<ValueReadAccess<'_, T>> {
110        self.dynamic.try_read::<T>()
111    }
112
113    pub fn try_write(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
114        self.dynamic.try_write::<T>()
115    }
116
117    pub fn read<const LOCKING: bool>(&'_ self) -> ValueReadAccess<'_, T> {
118        self.dynamic.read::<LOCKING, T>()
119    }
120
121    pub fn write<const LOCKING: bool>(&'_ mut self) -> ValueWriteAccess<'_, T> {
122        self.dynamic.write::<LOCKING, T>()
123    }
124
125    pub fn borrow<const LOCKING: bool>(&self) -> ManagedRef<T> {
126        self.dynamic
127            .borrow::<LOCKING>()
128            .into_typed()
129            .ok()
130            .expect("ManagedGc cannot be immutably borrowed")
131    }
132
133    pub fn borrow_mut<const LOCKING: bool>(&mut self) -> ManagedRefMut<T> {
134        self.dynamic
135            .borrow_mut::<LOCKING>()
136            .into_typed()
137            .ok()
138            .expect("ManagedGc cannot be mutably borrowed")
139    }
140
141    pub fn lazy(&self) -> ManagedLazy<T> {
142        self.dynamic
143            .lazy()
144            .into_typed()
145            .ok()
146            .expect("ManagedGc cannot be lazily borrowed")
147    }
148
149    /// # Safety
150    pub unsafe fn as_ptr(&self) -> *const T {
151        unsafe { self.dynamic.as_ptr_raw().cast::<T>() }
152    }
153
154    /// # Safety
155    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
156        unsafe { self.dynamic.as_mut_ptr_raw().cast::<T>() }
157    }
158}
159
160pub struct DynamicManagedGc {
161    type_hash: TypeHash,
162    kind: Kind,
163    layout: Layout,
164    finalizer: unsafe fn(*mut ()),
165    drop: bool,
166}
167
168unsafe impl Send for DynamicManagedGc {}
169unsafe impl Sync for DynamicManagedGc {}
170
171impl Drop for DynamicManagedGc {
172    fn drop(&mut self) {
173        if let Kind::Owned { lifetime, data } = &mut self.kind
174            && self.drop
175        {
176            while lifetime.state().is_in_use() {
177                std::hint::spin_loop();
178            }
179            lifetime.invalidate();
180            unsafe {
181                if data.is_null() {
182                    return;
183                }
184                (self.finalizer)(data.cast::<()>());
185                non_zero_dealloc(*data, self.layout);
186            }
187        }
188    }
189}
190
191impl DynamicManagedGc {
192    pub fn new<T: Finalize>(data: T) -> Self {
193        let layout = Layout::new::<T>().pad_to_align();
194        unsafe {
195            let memory = non_zero_alloc(layout) as *mut T;
196            if memory.is_null() {
197                handle_alloc_error(layout);
198            }
199            memory.cast::<T>().write(data);
200            Self {
201                type_hash: TypeHash::of::<T>(),
202                kind: Kind::Owned {
203                    lifetime: Default::default(),
204                    data: memory.cast::<u8>(),
205                },
206                layout,
207                finalizer: T::finalize_raw,
208                drop: true,
209            }
210        }
211    }
212
213    /// # Safety
214    pub unsafe fn new_cyclic<T: Finalize>(f: impl FnOnce(Self) -> T) -> Self {
215        let layout = Layout::new::<T>().pad_to_align();
216        unsafe {
217            let memory = non_zero_alloc(layout) as *mut T;
218            if memory.is_null() {
219                handle_alloc_error(layout);
220            }
221            let result = Self {
222                type_hash: TypeHash::of::<T>(),
223                kind: Kind::Owned {
224                    lifetime: Default::default(),
225                    data: memory.cast::<u8>(),
226                },
227                layout,
228                finalizer: T::finalize_raw,
229                drop: true,
230            };
231            let data = f(result.reference());
232            memory.cast::<T>().write(data);
233            result
234        }
235    }
236
237    pub fn new_raw(
238        type_hash: TypeHash,
239        lifetime: Lifetime,
240        memory: *mut u8,
241        layout: Layout,
242        finalizer: unsafe fn(*mut ()),
243    ) -> Self {
244        if memory.is_null() {
245            handle_alloc_error(layout);
246        }
247        Self {
248            type_hash,
249            kind: Kind::Owned {
250                lifetime: Box::new(lifetime),
251                data: memory,
252            },
253            layout,
254            finalizer,
255            drop: true,
256        }
257    }
258
259    pub fn new_uninitialized(
260        type_hash: TypeHash,
261        layout: Layout,
262        finalizer: unsafe fn(*mut ()),
263    ) -> Self {
264        let memory = unsafe { non_zero_alloc(layout) };
265        if memory.is_null() {
266            handle_alloc_error(layout);
267        }
268        Self {
269            type_hash,
270            kind: Kind::Owned {
271                lifetime: Default::default(),
272                data: memory,
273            },
274            layout,
275            finalizer,
276            drop: true,
277        }
278    }
279
280    pub fn reference(&self) -> Self {
281        match &self.kind {
282            Kind::Owned { lifetime, data } => Self {
283                type_hash: self.type_hash,
284                kind: Kind::Referenced {
285                    lifetime: lifetime.lazy(),
286                    data: *data,
287                },
288                layout: self.layout,
289                finalizer: self.finalizer,
290                drop: true,
291            },
292            Kind::Referenced { lifetime, data } => Self {
293                type_hash: self.type_hash,
294                kind: Kind::Referenced {
295                    lifetime: lifetime.clone(),
296                    data: *data,
297                },
298                layout: self.layout,
299                finalizer: self.finalizer,
300                drop: true,
301            },
302        }
303    }
304
305    pub fn consume<T>(mut self) -> Result<T, Self> {
306        if let Kind::Owned { lifetime, data } = &mut self.kind {
307            if self.type_hash == TypeHash::of::<T>() && !lifetime.state().is_in_use() {
308                if data.is_null() {
309                    return Err(self);
310                }
311                self.drop = false;
312                let mut result = MaybeUninit::<T>::uninit();
313                unsafe {
314                    result.as_mut_ptr().copy_from(data.cast::<T>(), 1);
315                    non_zero_dealloc(*data, self.layout);
316                    Ok(result.assume_init())
317                }
318            } else {
319                Err(self)
320            }
321        } else {
322            Err(self)
323        }
324    }
325
326    pub fn into_typed<T>(self) -> ManagedGc<T> {
327        ManagedGc {
328            dynamic: self,
329            _phantom: PhantomData,
330        }
331    }
332
333    pub fn renew(&mut self) {
334        if let Kind::Owned { lifetime, .. } = &mut self.kind {
335            **lifetime = Default::default();
336        }
337    }
338
339    pub fn type_hash(&self) -> TypeHash {
340        self.type_hash
341    }
342
343    pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
344        match &self.kind {
345            Kind::Owned { lifetime, .. } => ManagedGcLifetime::Owned(lifetime),
346            Kind::Referenced { lifetime, .. } => ManagedGcLifetime::Referenced(lifetime),
347        }
348    }
349
350    pub fn layout(&self) -> &Layout {
351        &self.layout
352    }
353
354    pub fn finalizer(&self) -> unsafe fn(*mut ()) {
355        self.finalizer
356    }
357
358    /// # Safety
359    pub unsafe fn memory(&self) -> &[u8] {
360        let memory = match &self.kind {
361            Kind::Owned { data, .. } => *data,
362            Kind::Referenced { data, .. } => *data,
363        };
364        unsafe { std::slice::from_raw_parts(memory, self.layout.size()) }
365    }
366
367    /// # Safety
368    pub unsafe fn memory_mut(&mut self) -> &mut [u8] {
369        let memory = match &mut self.kind {
370            Kind::Owned { data, .. } => *data,
371            Kind::Referenced { data, .. } => *data,
372        };
373        unsafe { std::slice::from_raw_parts_mut(memory, self.layout.size()) }
374    }
375
376    pub fn exists(&self) -> bool {
377        match &self.kind {
378            Kind::Owned { .. } => true,
379            Kind::Referenced { lifetime, .. } => lifetime.exists(),
380        }
381    }
382
383    pub fn is_owning(&self) -> bool {
384        matches!(self.kind, Kind::Owned { .. })
385    }
386
387    pub fn is_referencing(&self) -> bool {
388        matches!(self.kind, Kind::Referenced { .. })
389    }
390
391    pub fn is_owned_by(&self, other: &Self) -> bool {
392        if let (Kind::Referenced { lifetime: l1, .. }, Kind::Owned { lifetime: l2, .. }) =
393            (&self.kind, &other.kind)
394        {
395            l1.state().is_owned_by(l2.state())
396        } else {
397            false
398        }
399    }
400
401    pub fn is<T>(&self) -> bool {
402        self.type_hash == TypeHash::of::<T>()
403    }
404
405    pub fn try_read<T>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
406        if !self.is::<T>() {
407            panic!(
408                "DynamicManagedGc is not of the requested type: {}",
409                std::any::type_name::<T>()
410            );
411        }
412        unsafe {
413            match &self.kind {
414                Kind::Owned { lifetime, data } => {
415                    let data = data.cast::<T>().as_ref()?;
416                    lifetime.read(data)
417                }
418                Kind::Referenced { lifetime, data } => {
419                    if lifetime.exists() {
420                        let data = data.cast::<T>().as_ref()?;
421                        lifetime.read(data)
422                    } else {
423                        None
424                    }
425                }
426            }
427        }
428    }
429
430    pub fn try_write<T>(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
431        if !self.is::<T>() {
432            panic!(
433                "DynamicManagedGc is not of the requested type: {}",
434                std::any::type_name::<T>()
435            );
436        }
437        unsafe {
438            match &self.kind {
439                Kind::Owned { lifetime, data } => {
440                    let data = data.cast::<T>().as_mut()?;
441                    lifetime.write(data)
442                }
443                Kind::Referenced { lifetime, data } => {
444                    if lifetime.exists() {
445                        let data = data.cast::<T>().as_mut()?;
446                        lifetime.write(data)
447                    } else {
448                        None
449                    }
450                }
451            }
452        }
453    }
454
455    pub fn read<const LOCKING: bool, T>(&'_ self) -> ValueReadAccess<'_, T> {
456        if !self.is::<T>() {
457            panic!(
458                "DynamicManagedGc is not of the requested type: {}",
459                std::any::type_name::<T>()
460            );
461        }
462        unsafe {
463            if LOCKING {
464                match &self.kind {
465                    Kind::Owned { lifetime, data } => loop {
466                        let data = data
467                            .cast::<T>()
468                            .as_ref()
469                            .expect("DynamicManagedGc data pointer is null");
470                        if let Some(access) = lifetime.read(data) {
471                            return access;
472                        }
473                        std::hint::spin_loop();
474                    },
475                    Kind::Referenced { lifetime, data } => loop {
476                        if !lifetime.exists() {
477                            panic!("DynamicManagedGc owner is dead");
478                        }
479                        let data = data
480                            .cast::<T>()
481                            .as_ref()
482                            .expect("DynamicManagedGc data pointer is null");
483                        if let Some(access) = lifetime.read(data) {
484                            return access;
485                        }
486                        std::hint::spin_loop();
487                    },
488                }
489            } else {
490                match &self.kind {
491                    Kind::Owned { lifetime, data } => {
492                        let data = data
493                            .cast::<T>()
494                            .as_ref()
495                            .expect("DynamicManagedGc data pointer is null");
496                        lifetime
497                            .read(data)
498                            .expect("DynamicManagedGc is inaccessible for reading")
499                    }
500                    Kind::Referenced { lifetime, data } => {
501                        let data = data
502                            .cast::<T>()
503                            .as_ref()
504                            .expect("DynamicManagedGc data pointer is null");
505                        lifetime
506                            .read(data)
507                            .expect("DynamicManagedGc is inaccessible for reading")
508                    }
509                }
510            }
511        }
512    }
513
514    pub fn write<const LOCKING: bool, T>(&'_ mut self) -> ValueWriteAccess<'_, T> {
515        if !self.is::<T>() {
516            panic!(
517                "DynamicManagedGc is not of the requested type: {}",
518                std::any::type_name::<T>()
519            );
520        }
521        unsafe {
522            if LOCKING {
523                match &self.kind {
524                    Kind::Owned { lifetime, data } => loop {
525                        let data = data
526                            .cast::<T>()
527                            .as_mut()
528                            .expect("DynamicManagedGc data pointer is null");
529                        if let Some(access) = lifetime.write(data) {
530                            return access;
531                        }
532                        std::hint::spin_loop();
533                    },
534                    Kind::Referenced { lifetime, data } => loop {
535                        if !lifetime.exists() {
536                            panic!("DynamicManagedGc owner is dead");
537                        }
538                        let data = data
539                            .cast::<T>()
540                            .as_mut()
541                            .expect("DynamicManagedGc data pointer is null");
542                        if let Some(access) = lifetime.write(data) {
543                            return access;
544                        }
545                        std::hint::spin_loop();
546                    },
547                }
548            } else {
549                match &self.kind {
550                    Kind::Owned { lifetime, data } => {
551                        let data = data
552                            .cast::<T>()
553                            .as_mut()
554                            .expect("DynamicManagedGc data pointer is null");
555                        lifetime
556                            .write(data)
557                            .expect("DynamicManagedGc is inaccessible for writing")
558                    }
559                    Kind::Referenced { lifetime, data } => {
560                        let data = data
561                            .cast::<T>()
562                            .as_mut()
563                            .expect("DynamicManagedGc data pointer is null");
564                        lifetime
565                            .write(data)
566                            .expect("DynamicManagedGc is inaccessible for writing")
567                    }
568                }
569            }
570        }
571    }
572
573    pub fn borrow<const LOCKING: bool>(&self) -> DynamicManagedRef {
574        unsafe {
575            if LOCKING {
576                match &self.kind {
577                    Kind::Owned { lifetime, data } => loop {
578                        if let Some(lifetime) = lifetime.borrow() {
579                            return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
580                                .expect("DynamicManagedGc cannot be immutably borrowed");
581                        }
582                        std::hint::spin_loop();
583                    },
584                    Kind::Referenced { lifetime, data } => loop {
585                        if !lifetime.exists() {
586                            panic!("DynamicManagedGc owner is dead");
587                        }
588                        if let Some(lifetime) = lifetime.borrow() {
589                            return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
590                                .expect("DynamicManagedGc cannot be immutably borrowed");
591                        }
592                        std::hint::spin_loop();
593                    },
594                }
595            } else {
596                match &self.kind {
597                    Kind::Owned { lifetime, data } => DynamicManagedRef::new_raw(
598                        self.type_hash,
599                        lifetime
600                            .borrow()
601                            .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
602                        *data,
603                    )
604                    .expect("DynamicManagedGc cannot be immutably borrowed"),
605                    Kind::Referenced { lifetime, data } => DynamicManagedRef::new_raw(
606                        self.type_hash,
607                        lifetime
608                            .borrow()
609                            .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
610                        *data,
611                    )
612                    .expect("DynamicManagedGc cannot be immutably borrowed"),
613                }
614            }
615        }
616    }
617
618    pub fn borrow_mut<const LOCKING: bool>(&mut self) -> DynamicManagedRefMut {
619        unsafe {
620            if LOCKING {
621                match &self.kind {
622                    Kind::Owned { lifetime, data } => loop {
623                        if let Some(lifetime) = lifetime.borrow_mut() {
624                            return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
625                                .expect("DynamicManagedGc cannot be mutably borrowed");
626                        }
627                        std::hint::spin_loop();
628                    },
629                    Kind::Referenced { lifetime, data } => loop {
630                        if !lifetime.exists() {
631                            panic!("DynamicManagedGc owner is dead");
632                        }
633                        if let Some(lifetime) = lifetime.borrow_mut() {
634                            return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
635                                .expect("DynamicManagedGc cannot be mutably borrowed");
636                        }
637                        std::hint::spin_loop();
638                    },
639                }
640            } else {
641                match &self.kind {
642                    Kind::Owned { lifetime, data } => DynamicManagedRefMut::new_raw(
643                        self.type_hash,
644                        lifetime
645                            .borrow_mut()
646                            .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
647                        *data,
648                    )
649                    .expect("DynamicManagedGc cannot be mutably borrowed"),
650                    Kind::Referenced { lifetime, data } => DynamicManagedRefMut::new_raw(
651                        self.type_hash,
652                        lifetime
653                            .borrow_mut()
654                            .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
655                        *data,
656                    )
657                    .expect("DynamicManagedGc cannot be mutably borrowed"),
658                }
659            }
660        }
661    }
662
663    pub fn lazy(&self) -> DynamicManagedLazy {
664        unsafe {
665            match &self.kind {
666                Kind::Owned { lifetime, data } => {
667                    DynamicManagedLazy::new_raw(self.type_hash, lifetime.lazy(), *data)
668                        .expect("DynamicManagedGc cannot be lazily borrowed")
669                }
670                Kind::Referenced { lifetime, data } => {
671                    DynamicManagedLazy::new_raw(self.type_hash, lifetime.clone(), *data)
672                        .expect("DynamicManagedGc cannot be lazily borrowed")
673                }
674            }
675        }
676    }
677
678    /// # Safety
679    pub unsafe fn as_ptr_raw(&self) -> *const u8 {
680        match &self.kind {
681            Kind::Owned { data, .. } => *data as *const u8,
682            Kind::Referenced { data, .. } => *data as *const u8,
683        }
684    }
685
686    /// # Safety
687    pub unsafe fn as_mut_ptr_raw(&mut self) -> *mut u8 {
688        match &self.kind {
689            Kind::Owned { data, .. } => *data,
690            Kind::Referenced { data, .. } => *data,
691        }
692    }
693}
694
695#[cfg(test)]
696mod tests {
697    use super::*;
698
699    #[test]
700    fn test_is_async() {
701        fn is_async<T: Send + Sync>() {}
702
703        is_async::<ManagedGc<()>>();
704        is_async::<DynamicManagedGc>();
705    }
706
707    #[test]
708    fn test_managed_gc() {
709        let mut managed = ManagedGc::new(42);
710        {
711            let read_access = managed.read::<true>();
712            assert_eq!(*read_access, 42);
713        }
714        {
715            let mut write_access = managed.write::<true>();
716            *write_access = 100;
717        }
718        {
719            let read_access = managed.read::<true>();
720            assert_eq!(*read_access, 100);
721        }
722    }
723
724    #[test]
725    #[allow(unused)]
726    fn test_managed_gc_lifetimes() {
727        struct Car {
728            gear: i32,
729            engine: Option<ManagedGc<Engine>>,
730        }
731
732        struct Engine {
733            owning_car: Option<ManagedGc<Car>>,
734            horsepower: i32,
735        }
736
737        let mut car = ManagedGc::new(Car {
738            gear: 1,
739            engine: None,
740        });
741        let engine = ManagedGc::new(Engine {
742            owning_car: Some(car.reference()),
743            horsepower: 200,
744        });
745        let engine2 = engine.reference();
746        car.write::<true>().engine = Some(engine);
747
748        assert!(car.exists());
749        assert!(car.is_owning());
750        assert!(engine2.exists());
751        assert!(engine2.is_referencing());
752        assert!(engine2.is_owned_by(car.read::<true>().engine.as_ref().unwrap()));
753
754        let car2 = car.reference();
755        assert!(car2.exists());
756        assert!(car2.is_referencing());
757
758        drop(car);
759        assert!(!car2.exists());
760        assert!(car2.try_read().is_none());
761        assert!(!engine2.exists());
762        assert!(engine2.try_read().is_none());
763    }
764
765    #[test]
766    fn test_managed_gc_cycles() {
767        #[derive(Default)]
768        struct Foo {
769            other: Option<ManagedGc<Self>>,
770        }
771
772        {
773            let mut a = ManagedGc::<Foo>::default();
774            let mut b = ManagedGc::<Foo>::default();
775            a.write::<true>().other = Some(b.reference());
776            b.write::<true>().other = Some(a.reference());
777
778            assert!(a.exists());
779            assert!(a.is_owning());
780            assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
781            assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&b));
782
783            assert!(b.exists());
784            assert!(b.is_owning());
785            assert!(b.read::<true>().other.as_ref().unwrap().is_referencing());
786            assert!(b.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
787
788            drop(b);
789            assert!(!a.read::<true>().other.as_ref().unwrap().exists());
790        }
791
792        {
793            let mut a = ManagedGc::<Foo>::default();
794            a.write::<true>().other = Some(a.reference());
795
796            assert!(a.exists());
797            assert!(a.is_owning());
798            assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
799            assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
800        }
801    }
802
803    #[test]
804    fn test_dynamic_managed_gc() {
805        let mut managed = DynamicManagedGc::new(42);
806        {
807            let read_access = managed.read::<true, i32>();
808            assert_eq!(*read_access, 42);
809        }
810        {
811            let mut write_access = managed.write::<true, i32>();
812            *write_access = 100;
813        }
814        {
815            let read_access = managed.read::<true, i32>();
816            assert_eq!(*read_access, 100);
817        }
818    }
819
820    #[test]
821    fn test_dynamic_managed_gc_cycles() {
822        #[derive(Default)]
823        struct Foo {
824            other: Option<DynamicManagedGc>,
825        }
826
827        {
828            let mut a = DynamicManagedGc::new(Foo::default());
829            let mut b = DynamicManagedGc::new(Foo::default());
830            a.write::<true, Foo>().other = Some(b.reference());
831            b.write::<true, Foo>().other = Some(a.reference());
832
833            assert!(a.exists());
834            assert!(a.is_owning());
835            assert!(
836                a.read::<true, Foo>()
837                    .other
838                    .as_ref()
839                    .unwrap()
840                    .is_referencing()
841            );
842            assert!(
843                a.read::<true, Foo>()
844                    .other
845                    .as_ref()
846                    .unwrap()
847                    .is_owned_by(&b)
848            );
849
850            assert!(b.exists());
851            assert!(b.is_owning());
852            assert!(
853                b.read::<true, Foo>()
854                    .other
855                    .as_ref()
856                    .unwrap()
857                    .is_referencing()
858            );
859            assert!(
860                b.read::<true, Foo>()
861                    .other
862                    .as_ref()
863                    .unwrap()
864                    .is_owned_by(&a)
865            );
866
867            drop(b);
868            assert!(!a.read::<true, Foo>().other.as_ref().unwrap().exists());
869        }
870
871        {
872            let mut a = DynamicManagedGc::new(Foo::default());
873            a.write::<true, Foo>().other = Some(a.reference());
874
875            assert!(a.exists());
876            assert!(a.is_owning());
877            assert!(
878                a.read::<true, Foo>()
879                    .other
880                    .as_ref()
881                    .unwrap()
882                    .is_referencing()
883            );
884            assert!(
885                a.read::<true, Foo>()
886                    .other
887                    .as_ref()
888                    .unwrap()
889                    .is_owned_by(&a)
890            );
891        }
892    }
893
894    #[test]
895    fn test_managed_gc_conversions() {
896        let managed = ManagedGc::new(42);
897        assert_eq!(*managed.read::<true>(), 42);
898
899        let mut dynamic = managed.into_dynamic();
900        *dynamic.write::<true, i32>() = 100;
901
902        let managed = dynamic.into_typed::<i32>();
903        assert_eq!(*managed.read::<true>(), 100);
904    }
905
906    #[test]
907    fn test_managed_gc_dead_owner() {
908        let a = ManagedGc::new(42);
909        let mut b = a.reference();
910
911        assert!(a.exists());
912        assert!(b.exists());
913        assert_eq!(*b.read::<true>(), 42);
914
915        drop(a);
916        assert!(!b.exists());
917        assert!(b.try_write().is_none());
918    }
919
920    #[test]
921    #[should_panic]
922    fn test_managed_gc_dead_owner_panic() {
923        let a = ManagedGc::new(42);
924        let mut b = a.reference();
925
926        assert!(a.exists());
927        assert!(b.exists());
928        assert_eq!(*b.read::<true>(), 42);
929
930        drop(a);
931        assert!(!b.exists());
932        assert_eq!(*b.write::<true>(), 42);
933    }
934
935    #[test]
936    fn test_managed_gc_cyclic() {
937        struct SelfReferencial {
938            value: i32,
939            this: ManagedGc<SelfReferencial>,
940        }
941
942        let v = unsafe { ManagedGc::new_cyclic(|this| SelfReferencial { value: 42, this }) };
943        assert_eq!(v.read::<true>().value, 42);
944        let this = v.read::<true>().this.reference();
945        assert_eq!(this.read::<true>().value, 42);
946    }
947}