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