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