Skip to main content

intuicio_data/managed/
gc.rs

1//! Value boxes that tolerate reference cycles.
2//!
3//! Reference counting leaks when two values point at each other. These boxes
4//! avoid that by not counting at all: exactly one handle **owns** the
5//! allocation and every other handle only **references** it. A cycle is then
6//! just a reference pointing back, and nothing keeps the value alive on its
7//! own.
8//!
9//! When the owner is dropped the value is destroyed, and every reference to
10//! it reports that through [`DynamicManagedGc::exists`] rather than dangling.
11//! Ownership can also be handed to a reference with
12//! [`DynamicManagedGc::transfer_ownership`], which is how a value outlives the
13//! handle it started in.
14//!
15//! [`ManagedGc`] is the typed box, [`DynamicManagedGc`] the type-erased one it
16//! is built on.
17//!
18//! # Blocking and non-blocking access
19//!
20//! The `try_` methods return [`None`] when the value is busy. The plain ones
21//! take a `LOCKING` constant: `true` spins until the value is free, `false`
22//! panics right away. Pick `false` on a single thread, where a busy value
23//! means a bug rather than a race.
24//!
25//! ```
26//! # use intuicio_data::managed::gc::ManagedGc;
27//! let mut owner = ManagedGc::new(42);
28//! let handle = owner.reference();
29//! assert!(handle.exists());
30//! drop(owner);
31//! // the owner is gone, so the reference knows the value is gone too
32//! assert!(!handle.exists());
33//! ```
34use crate::{
35    Finalize, Finalizer,
36    lifetime::{Lifetime, LifetimeLazy, ValueReadAccess, ValueWriteAccess},
37    managed::{
38        DynamicManagedLazy, DynamicManagedRef, DynamicManagedRefMut, ManagedLazy, ManagedRef,
39        ManagedRefMut,
40        value::{DynamicManagedValue, ManagedValue},
41    },
42    non_zero_alloc, non_zero_dealloc,
43    type_hash::TypeHash,
44};
45use std::{
46    alloc::{Layout, handle_alloc_error},
47    marker::PhantomData,
48    mem::MaybeUninit,
49};
50
51/// Whether this handle owns the allocation or only points at it.
52enum Kind {
53    Owned {
54        lifetime: Box<Lifetime>,
55        data: *mut u8,
56    },
57    Referenced {
58        lifetime: LifetimeLazy,
59        data: *mut u8,
60    },
61}
62
63/// Borrow state of a garbage collected box, as seen from a handle.
64///
65/// Which variant comes back tells whether the handle owns the value.
66pub enum ManagedGcLifetime<'a> {
67    /// This handle owns the value.
68    Owned(&'a Lifetime),
69    /// This handle only references the value.
70    Referenced(&'a LifetimeLazy),
71}
72
73/// Typed garbage collected box.
74///
75/// See the [module docs](self) for the ownership model.
76pub struct ManagedGc<T> {
77    dynamic: DynamicManagedGc,
78    _phantom: PhantomData<fn() -> T>,
79}
80
81unsafe impl<T> Send for ManagedGc<T> {}
82unsafe impl<T> Sync for ManagedGc<T> {}
83
84impl<T: Default> Default for ManagedGc<T> {
85    fn default() -> Self {
86        Self::new(T::default())
87    }
88}
89
90impl<T> ManagedGc<T> {
91    /// Allocates a value and owns it.
92    pub fn new(data: T) -> Self {
93        Self {
94            dynamic: DynamicManagedGc::new(data),
95            _phantom: PhantomData,
96        }
97    }
98
99    /// Allocates a value that can point back at itself.
100    ///
101    /// `f` is handed a reference to the box before the value exists, so it can
102    /// store it inside the value it returns.
103    ///
104    /// # Safety
105    ///
106    /// The handle passed to `f` points at memory that is not written yet.
107    /// Storing it is fine, but reading or writing through it before `f`
108    /// returns is undefined.
109    pub unsafe fn new_cyclic(f: impl FnOnce(Self) -> T) -> Self {
110        Self {
111            dynamic: unsafe { DynamicManagedGc::new_cyclic(|dynamic| f(dynamic.into_typed())) },
112            _phantom: PhantomData,
113        }
114    }
115
116    /// Takes another handle that references the same value without owning it.
117    pub fn reference(&self) -> Self {
118        Self {
119            dynamic: self.dynamic.reference(),
120            _phantom: PhantomData,
121        }
122    }
123
124    /// Takes the value out and frees the allocation.
125    ///
126    /// Gives the box back when it does not own the value or something is
127    /// accessing it.
128    pub fn consume(self) -> Result<T, Self> {
129        self.dynamic.consume().map_err(|value| Self {
130            dynamic: value,
131            _phantom: PhantomData,
132        })
133    }
134
135    /// Erases the type.
136    pub fn into_dynamic(self) -> DynamicManagedGc {
137        self.dynamic
138    }
139
140    /// Replaces the lifetime, killing every reference taken so far. Does
141    /// nothing on a referencing handle.
142    pub fn renew(&mut self) {
143        self.dynamic.renew();
144    }
145
146    /// Returns the type of the value.
147    pub fn type_hash(&self) -> TypeHash {
148        self.dynamic.type_hash()
149    }
150
151    /// Returns the borrow state, and with it whether this handle owns the
152    /// value.
153    pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
154        self.dynamic.lifetime()
155    }
156
157    /// Returns `true` while the value is alive.
158    ///
159    /// Always `true` for the owner.
160    pub fn exists(&self) -> bool {
161        self.dynamic.exists()
162    }
163
164    /// Returns `true` when this handle owns the value.
165    pub fn is_owning(&self) -> bool {
166        self.dynamic.is_owning()
167    }
168
169    /// Returns `true` when this handle only references the value.
170    pub fn is_referencing(&self) -> bool {
171        self.dynamic.is_referencing()
172    }
173
174    /// Returns `true` when this handle references the value that `other` owns.
175    pub fn is_owned_by(&self, other: &Self) -> bool {
176        self.dynamic.is_owned_by(&other.dynamic)
177    }
178
179    /// Hands ownership over to a handle that references this value.
180    ///
181    /// Returns `false` unless this handle owns the value and `new_owner`
182    /// references it.
183    pub fn transfer_ownership(&mut self, new_owner: &mut Self) -> bool {
184        self.dynamic.transfer_ownership(&mut new_owner.dynamic)
185    }
186
187    /// Guards the value for reading, or returns [`None`] when it is busy or
188    /// gone.
189    pub fn try_read(&'_ self) -> Option<ValueReadAccess<'_, T>> {
190        self.dynamic.try_read::<T>()
191    }
192
193    /// Guards the value for writing, or returns [`None`] when it is busy or
194    /// gone.
195    pub fn try_write(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
196        self.dynamic.try_write::<T>()
197    }
198
199    /// Guards the value for reading, spinning until it is free when `LOCKING`.
200    ///
201    /// # Panics
202    ///
203    /// Panics when the value is gone, or when it is busy and `LOCKING` is
204    /// `false`.
205    pub fn read<const LOCKING: bool>(&'_ self) -> ValueReadAccess<'_, T> {
206        self.dynamic.read::<LOCKING, T>()
207    }
208
209    /// Guards the value for writing, spinning until it is free when `LOCKING`.
210    ///
211    /// # Panics
212    ///
213    /// Panics when the value is gone, or when it is busy and `LOCKING` is
214    /// `false`.
215    pub fn write<const LOCKING: bool>(&'_ mut self) -> ValueWriteAccess<'_, T> {
216        self.dynamic.write::<LOCKING, T>()
217    }
218
219    /// Takes a shared handle, or returns [`None`] when the value is busy or
220    /// gone.
221    pub fn try_borrow(&self) -> Option<ManagedRef<T>> {
222        self.dynamic.try_borrow()?.into_typed().ok()
223    }
224
225    /// Takes an exclusive handle, or returns [`None`] when the value is busy or
226    /// gone.
227    pub fn try_borrow_mut(&self) -> Option<ManagedRefMut<T>> {
228        self.dynamic.try_borrow_mut()?.into_typed().ok()
229    }
230
231    /// Takes a shared handle, spinning until it is free when `LOCKING`.
232    ///
233    /// # Panics
234    ///
235    /// Panics when the value is gone, or when it is busy and `LOCKING` is
236    /// `false`.
237    pub fn borrow<const LOCKING: bool>(&self) -> ManagedRef<T> {
238        self.dynamic
239            .borrow::<LOCKING>()
240            .into_typed()
241            .ok()
242            .expect("ManagedGc cannot be immutably borrowed")
243    }
244
245    /// Takes an exclusive handle, spinning until it is free when `LOCKING`.
246    ///
247    /// # Panics
248    ///
249    /// Panics when the value is gone, or when it is busy and `LOCKING` is
250    /// `false`.
251    pub fn borrow_mut<const LOCKING: bool>(&mut self) -> ManagedRefMut<T> {
252        self.dynamic
253            .borrow_mut::<LOCKING>()
254            .into_typed()
255            .ok()
256            .expect("ManagedGc cannot be mutably borrowed")
257    }
258
259    /// Takes an unclaimed handle, which claims nothing and never blocks.
260    ///
261    /// # Panics
262    ///
263    /// Panics when the value is gone.
264    pub fn lazy(&self) -> ManagedLazy<T> {
265        self.dynamic
266            .lazy()
267            .into_typed()
268            .ok()
269            .expect("ManagedGc cannot be lazily borrowed")
270    }
271
272    /// Returns a pointer to the value, checking nothing.
273    ///
274    /// # Safety
275    ///
276    /// Neither the borrow state nor whether the value is still alive is
277    /// checked.
278    pub unsafe fn as_ptr(&self) -> *const T {
279        unsafe { self.dynamic.as_ptr_raw().cast::<T>() }
280    }
281
282    /// Returns a mutable pointer to the value, checking nothing.
283    ///
284    /// # Safety
285    ///
286    /// Neither the borrow state nor whether the value is still alive is
287    /// checked.
288    pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
289        unsafe { self.dynamic.as_mut_ptr_raw().cast::<T>() }
290    }
291}
292
293impl<T> TryFrom<ManagedValue<T>> for ManagedGc<T> {
294    type Error = ();
295
296    fn try_from(value: ManagedValue<T>) -> Result<Self, Self::Error> {
297        match value {
298            ManagedValue::Gc(value) => Ok(value),
299            _ => Err(()),
300        }
301    }
302}
303
304/// Type-erased garbage collected box.
305///
306/// The [`ManagedGc`] counterpart for script values. See the
307/// [module docs](self) for the ownership model.
308pub struct DynamicManagedGc {
309    type_hash: TypeHash,
310    kind: Kind,
311    layout: Layout,
312    finalizer: Finalizer,
313    drop: bool,
314}
315
316unsafe impl Send for DynamicManagedGc {}
317unsafe impl Sync for DynamicManagedGc {}
318
319impl Drop for DynamicManagedGc {
320    fn drop(&mut self) {
321        if let Kind::Owned { lifetime, data } = &mut self.kind
322            && self.drop
323        {
324            while lifetime.state().is_in_use() {
325                std::hint::spin_loop();
326            }
327            lifetime.invalidate();
328            unsafe {
329                if data.is_null() {
330                    return;
331                }
332                self.finalizer.finalize(data.cast::<()>());
333                non_zero_dealloc(*data, self.layout);
334            }
335        }
336    }
337}
338
339impl DynamicManagedGc {
340    /// Allocates a value and owns it.
341    pub fn new<T: Finalize>(data: T) -> Self {
342        let layout = Layout::new::<T>().pad_to_align();
343        unsafe {
344            let memory = non_zero_alloc(layout) as *mut T;
345            if memory.is_null() {
346                handle_alloc_error(layout);
347            }
348            memory.cast::<T>().write(data);
349            Self {
350                type_hash: TypeHash::of::<T>(),
351                kind: Kind::Owned {
352                    lifetime: Default::default(),
353                    data: memory.cast::<u8>(),
354                },
355                layout,
356                finalizer: Finalizer::of::<T>(),
357                drop: true,
358            }
359        }
360    }
361
362    /// Allocates a value that can point back at itself.
363    ///
364    /// `f` is handed a reference to the box before the value exists, so it can
365    /// store it inside the value it returns.
366    ///
367    /// # Safety
368    ///
369    /// The handle passed to `f` points at memory that is not written yet.
370    /// Storing it is fine, but reading or writing through it before `f`
371    /// returns is undefined.
372    pub unsafe fn new_cyclic<T: Finalize>(f: impl FnOnce(Self) -> T) -> Self {
373        let layout = Layout::new::<T>().pad_to_align();
374        unsafe {
375            let memory = non_zero_alloc(layout) as *mut T;
376            if memory.is_null() {
377                handle_alloc_error(layout);
378            }
379            let result = Self {
380                type_hash: TypeHash::of::<T>(),
381                kind: Kind::Owned {
382                    lifetime: Default::default(),
383                    data: memory.cast::<u8>(),
384                },
385                layout,
386                finalizer: Finalizer::of::<T>(),
387                drop: true,
388            };
389            let data = f(result.reference());
390            memory.cast::<T>().write(data);
391            result
392        }
393    }
394
395    /// Takes ownership of an existing allocation.
396    ///
397    /// The box will free `memory` and run `finalizer` when it is dropped.
398    ///
399    /// # Panics
400    ///
401    /// Panics when `memory` is null.
402    pub fn new_raw(
403        type_hash: TypeHash,
404        lifetime: Lifetime,
405        memory: *mut u8,
406        layout: Layout,
407        finalizer: impl Into<Finalizer>,
408    ) -> Self {
409        if memory.is_null() {
410            handle_alloc_error(layout);
411        }
412        Self {
413            type_hash,
414            kind: Kind::Owned {
415                lifetime: Box::new(lifetime),
416                data: memory,
417            },
418            layout,
419            finalizer: finalizer.into(),
420            drop: true,
421        }
422    }
423
424    /// Allocates room for a value without writing one into it.
425    ///
426    /// The finalizer still runs on drop, so the caller must fill the memory
427    /// before the box is dropped or read.
428    pub fn new_uninitialized(
429        type_hash: TypeHash,
430        layout: Layout,
431        finalizer: impl Into<Finalizer>,
432    ) -> Self {
433        let memory = unsafe { non_zero_alloc(layout) };
434        if memory.is_null() {
435            handle_alloc_error(layout);
436        }
437        Self {
438            type_hash,
439            kind: Kind::Owned {
440                lifetime: Default::default(),
441                data: memory,
442            },
443            layout,
444            finalizer: finalizer.into(),
445            drop: true,
446        }
447    }
448
449    /// Takes another handle that references the same value without owning it.
450    pub fn reference(&self) -> Self {
451        match &self.kind {
452            Kind::Owned { lifetime, data } => Self {
453                type_hash: self.type_hash,
454                kind: Kind::Referenced {
455                    lifetime: lifetime.lazy(),
456                    data: *data,
457                },
458                layout: self.layout,
459                finalizer: self.finalizer.clone(),
460                drop: true,
461            },
462            Kind::Referenced { lifetime, data } => Self {
463                type_hash: self.type_hash,
464                kind: Kind::Referenced {
465                    lifetime: lifetime.clone(),
466                    data: *data,
467                },
468                layout: self.layout,
469                finalizer: self.finalizer.clone(),
470                drop: true,
471            },
472        }
473    }
474
475    /// Takes the value out and frees the allocation.
476    ///
477    /// Gives the box back when it does not own the value, the type does not
478    /// match, or something is accessing it.
479    pub fn consume<T>(mut self) -> Result<T, Self> {
480        if let Kind::Owned { lifetime, data } = &mut self.kind {
481            if self.type_hash == TypeHash::of::<T>() && !lifetime.state().is_in_use() {
482                if data.is_null() {
483                    return Err(self);
484                }
485                self.drop = false;
486                let mut result = MaybeUninit::<T>::uninit();
487                unsafe {
488                    result.as_mut_ptr().copy_from(data.cast::<T>(), 1);
489                    non_zero_dealloc(*data, self.layout);
490                    Ok(result.assume_init())
491                }
492            } else {
493                Err(self)
494            }
495        } else {
496            Err(self)
497        }
498    }
499
500    /// Puts a type back on the box.
501    pub fn into_typed<T>(self) -> ManagedGc<T> {
502        ManagedGc {
503            dynamic: self,
504            _phantom: PhantomData,
505        }
506    }
507
508    /// Replaces the lifetime, killing every reference taken so far. Does
509    /// nothing on a referencing handle.
510    pub fn renew(&mut self) {
511        if let Kind::Owned { lifetime, .. } = &mut self.kind {
512            **lifetime = Default::default();
513        }
514    }
515
516    /// Returns the type of the value.
517    pub fn type_hash(&self) -> TypeHash {
518        self.type_hash
519    }
520
521    /// Returns the borrow state, and with it whether this handle owns the
522    /// value.
523    pub fn lifetime(&self) -> ManagedGcLifetime<'_> {
524        match &self.kind {
525            Kind::Owned { lifetime, .. } => ManagedGcLifetime::Owned(lifetime),
526            Kind::Referenced { lifetime, .. } => ManagedGcLifetime::Referenced(lifetime),
527        }
528    }
529
530    /// Returns the layout of the allocation.
531    pub fn layout(&self) -> &Layout {
532        &self.layout
533    }
534
535    /// Returns the drop function of the stored type.
536    pub fn finalizer(&self) -> &Finalizer {
537        &self.finalizer
538    }
539
540    /// Returns the value as raw bytes.
541    ///
542    /// # Safety
543    ///
544    /// Bypasses the borrow state, and does not check that the value is still
545    /// alive.
546    pub unsafe fn memory(&self) -> &[u8] {
547        let memory = match &self.kind {
548            Kind::Owned { data, .. } => *data,
549            Kind::Referenced { data, .. } => *data,
550        };
551        unsafe { std::slice::from_raw_parts(memory, self.layout.size()) }
552    }
553
554    /// Returns the value as mutable raw bytes.
555    ///
556    /// # Safety
557    ///
558    /// Bypasses the borrow state, does not check that the value is still
559    /// alive, and writing bytes that are not a valid value of the stored type
560    /// makes every later access undefined.
561    pub unsafe fn memory_mut(&mut self) -> &mut [u8] {
562        let memory = match &mut self.kind {
563            Kind::Owned { data, .. } => *data,
564            Kind::Referenced { data, .. } => *data,
565        };
566        unsafe { std::slice::from_raw_parts_mut(memory, self.layout.size()) }
567    }
568
569    /// Returns `true` while the value is alive.
570    ///
571    /// Always `true` for the owner.
572    pub fn exists(&self) -> bool {
573        match &self.kind {
574            Kind::Owned { .. } => true,
575            Kind::Referenced { lifetime, .. } => lifetime.exists(),
576        }
577    }
578
579    /// Returns `true` when this handle owns the value.
580    pub fn is_owning(&self) -> bool {
581        matches!(self.kind, Kind::Owned { .. })
582    }
583
584    /// Returns `true` when this handle only references the value.
585    pub fn is_referencing(&self) -> bool {
586        matches!(self.kind, Kind::Referenced { .. })
587    }
588
589    /// Returns `true` when this handle references the value that `other` owns.
590    pub fn is_owned_by(&self, other: &Self) -> bool {
591        if let (
592            Kind::Referenced {
593                lifetime: l1,
594                data: d1,
595            },
596            Kind::Owned {
597                lifetime: l2,
598                data: d2,
599            },
600        ) = (&self.kind, &other.kind)
601        {
602            *d1 == *d2 && l1.state().is_owned_by(l2.state())
603        } else {
604            false
605        }
606    }
607
608    /// Hands ownership over to a handle that references this value.
609    ///
610    /// Returns `false` unless this handle owns the value and `new_owner`
611    /// references it.
612    pub fn transfer_ownership(&mut self, new_owner: &mut Self) -> bool {
613        if let (
614            Kind::Owned {
615                lifetime: l1,
616                data: d1,
617            },
618            Kind::Referenced {
619                lifetime: l2,
620                data: d2,
621            },
622        ) = (&mut self.kind, &new_owner.kind)
623            && *d1 == *d2
624            && l2.state().is_owned_by(l1.state())
625        {
626            std::mem::swap(&mut self.kind, &mut new_owner.kind);
627            true
628        } else {
629            false
630        }
631    }
632
633    /// Returns `true` when the value is a `T`.
634    pub fn is<T>(&self) -> bool {
635        self.type_hash == TypeHash::of::<T>()
636    }
637
638    /// Guards the value for reading, or returns [`None`] when it is busy or
639    /// gone.
640    ///
641    /// # Panics
642    ///
643    /// Panics when the value is not a `T`.
644    pub fn try_read<T>(&'_ self) -> Option<ValueReadAccess<'_, T>> {
645        if !self.is::<T>() {
646            panic!(
647                "DynamicManagedGc is not of the requested type: {}",
648                std::any::type_name::<T>()
649            );
650        }
651        unsafe {
652            match &self.kind {
653                Kind::Owned { lifetime, data } => {
654                    let data = data.cast::<T>().as_ref()?;
655                    lifetime.read(data)
656                }
657                Kind::Referenced { lifetime, data } => {
658                    if lifetime.exists() {
659                        let data = data.cast::<T>().as_ref()?;
660                        lifetime.read(data)
661                    } else {
662                        None
663                    }
664                }
665            }
666        }
667    }
668
669    /// Guards the value for writing, or returns [`None`] when it is busy or
670    /// gone.
671    ///
672    /// # Panics
673    ///
674    /// Panics when the value is not a `T`.
675    pub fn try_write<T>(&'_ mut self) -> Option<ValueWriteAccess<'_, T>> {
676        if !self.is::<T>() {
677            panic!(
678                "DynamicManagedGc is not of the requested type: {}",
679                std::any::type_name::<T>()
680            );
681        }
682        unsafe {
683            match &self.kind {
684                Kind::Owned { lifetime, data } => {
685                    let data = data.cast::<T>().as_mut()?;
686                    lifetime.write(data)
687                }
688                Kind::Referenced { lifetime, data } => {
689                    if lifetime.exists() {
690                        let data = data.cast::<T>().as_mut()?;
691                        lifetime.write(data)
692                    } else {
693                        None
694                    }
695                }
696            }
697        }
698    }
699
700    /// Guards the value for reading, spinning until it is free when `LOCKING`.
701    ///
702    /// # Panics
703    ///
704    /// Panics when the value is not a `T`, is gone, or is busy and `LOCKING`
705    /// is `false`.
706    pub fn read<const LOCKING: bool, T>(&'_ self) -> ValueReadAccess<'_, T> {
707        if !self.is::<T>() {
708            panic!(
709                "DynamicManagedGc is not of the requested type: {}",
710                std::any::type_name::<T>()
711            );
712        }
713        unsafe {
714            if LOCKING {
715                match &self.kind {
716                    Kind::Owned { lifetime, data } => loop {
717                        let data = data
718                            .cast::<T>()
719                            .as_ref()
720                            .expect("DynamicManagedGc data pointer is null");
721                        if let Some(access) = lifetime.read(data) {
722                            return access;
723                        }
724                        std::hint::spin_loop();
725                    },
726                    Kind::Referenced { lifetime, data } => loop {
727                        if !lifetime.exists() {
728                            panic!("DynamicManagedGc owner is dead");
729                        }
730                        let data = data
731                            .cast::<T>()
732                            .as_ref()
733                            .expect("DynamicManagedGc data pointer is null");
734                        if let Some(access) = lifetime.read(data) {
735                            return access;
736                        }
737                        std::hint::spin_loop();
738                    },
739                }
740            } else {
741                match &self.kind {
742                    Kind::Owned { lifetime, data } => {
743                        let data = data
744                            .cast::<T>()
745                            .as_ref()
746                            .expect("DynamicManagedGc data pointer is null");
747                        lifetime
748                            .read(data)
749                            .expect("DynamicManagedGc is inaccessible for reading")
750                    }
751                    Kind::Referenced { lifetime, data } => {
752                        let data = data
753                            .cast::<T>()
754                            .as_ref()
755                            .expect("DynamicManagedGc data pointer is null");
756                        lifetime
757                            .read(data)
758                            .expect("DynamicManagedGc is inaccessible for reading")
759                    }
760                }
761            }
762        }
763    }
764
765    /// Guards the value for writing, spinning until it is free when `LOCKING`.
766    ///
767    /// # Panics
768    ///
769    /// Panics when the value is not a `T`, is gone, or is busy and `LOCKING`
770    /// is `false`.
771    pub fn write<const LOCKING: bool, T>(&'_ mut self) -> ValueWriteAccess<'_, T> {
772        if !self.is::<T>() {
773            panic!(
774                "DynamicManagedGc is not of the requested type: {}",
775                std::any::type_name::<T>()
776            );
777        }
778        unsafe {
779            if LOCKING {
780                match &self.kind {
781                    Kind::Owned { lifetime, data } => loop {
782                        let data = data
783                            .cast::<T>()
784                            .as_mut()
785                            .expect("DynamicManagedGc data pointer is null");
786                        if let Some(access) = lifetime.write(data) {
787                            return access;
788                        }
789                        std::hint::spin_loop();
790                    },
791                    Kind::Referenced { lifetime, data } => loop {
792                        if !lifetime.exists() {
793                            panic!("DynamicManagedGc owner is dead");
794                        }
795                        let data = data
796                            .cast::<T>()
797                            .as_mut()
798                            .expect("DynamicManagedGc data pointer is null");
799                        if let Some(access) = lifetime.write(data) {
800                            return access;
801                        }
802                        std::hint::spin_loop();
803                    },
804                }
805            } else {
806                match &self.kind {
807                    Kind::Owned { lifetime, data } => {
808                        let data = data
809                            .cast::<T>()
810                            .as_mut()
811                            .expect("DynamicManagedGc data pointer is null");
812                        lifetime
813                            .write(data)
814                            .expect("DynamicManagedGc is inaccessible for writing")
815                    }
816                    Kind::Referenced { lifetime, data } => {
817                        let data = data
818                            .cast::<T>()
819                            .as_mut()
820                            .expect("DynamicManagedGc data pointer is null");
821                        lifetime
822                            .write(data)
823                            .expect("DynamicManagedGc is inaccessible for writing")
824                    }
825                }
826            }
827        }
828    }
829
830    /// Takes a shared handle, or returns [`None`] when the value is busy or
831    /// gone.
832    pub fn try_borrow(&self) -> Option<DynamicManagedRef> {
833        unsafe {
834            match &self.kind {
835                Kind::Owned { lifetime, data } => {
836                    DynamicManagedRef::new_raw(self.type_hash, lifetime.borrow()?, *data)
837                }
838                Kind::Referenced { lifetime, data } => {
839                    DynamicManagedRef::new_raw(self.type_hash, lifetime.borrow()?, *data)
840                }
841            }
842        }
843    }
844
845    /// Takes an exclusive handle, or returns [`None`] when the value is busy or
846    /// gone.
847    pub fn try_borrow_mut(&self) -> Option<DynamicManagedRefMut> {
848        unsafe {
849            match &self.kind {
850                Kind::Owned { lifetime, data } => {
851                    DynamicManagedRefMut::new_raw(self.type_hash, lifetime.borrow_mut()?, *data)
852                }
853                Kind::Referenced { lifetime, data } => {
854                    DynamicManagedRefMut::new_raw(self.type_hash, lifetime.borrow_mut()?, *data)
855                }
856            }
857        }
858    }
859
860    /// Takes a shared handle, spinning until it is free when `LOCKING`.
861    ///
862    /// # Panics
863    ///
864    /// Panics when the value is gone, or when it is busy and `LOCKING` is
865    /// `false`.
866    pub fn borrow<const LOCKING: bool>(&self) -> DynamicManagedRef {
867        unsafe {
868            if LOCKING {
869                match &self.kind {
870                    Kind::Owned { lifetime, data } => loop {
871                        if let Some(lifetime) = lifetime.borrow() {
872                            return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
873                                .expect("DynamicManagedGc cannot be immutably borrowed");
874                        }
875                        std::hint::spin_loop();
876                    },
877                    Kind::Referenced { lifetime, data } => loop {
878                        if !lifetime.exists() {
879                            panic!("DynamicManagedGc owner is dead");
880                        }
881                        if let Some(lifetime) = lifetime.borrow() {
882                            return DynamicManagedRef::new_raw(self.type_hash, lifetime, *data)
883                                .expect("DynamicManagedGc cannot be immutably borrowed");
884                        }
885                        std::hint::spin_loop();
886                    },
887                }
888            } else {
889                match &self.kind {
890                    Kind::Owned { lifetime, data } => DynamicManagedRef::new_raw(
891                        self.type_hash,
892                        lifetime
893                            .borrow()
894                            .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
895                        *data,
896                    )
897                    .expect("DynamicManagedGc cannot be immutably borrowed"),
898                    Kind::Referenced { lifetime, data } => DynamicManagedRef::new_raw(
899                        self.type_hash,
900                        lifetime
901                            .borrow()
902                            .expect("DynamicManagedGc is inaccessible for immutable borrowing"),
903                        *data,
904                    )
905                    .expect("DynamicManagedGc cannot be immutably borrowed"),
906                }
907            }
908        }
909    }
910
911    /// Takes an exclusive handle, spinning until it is free when `LOCKING`.
912    ///
913    /// # Panics
914    ///
915    /// Panics when the value is gone, or when it is busy and `LOCKING` is
916    /// `false`.
917    pub fn borrow_mut<const LOCKING: bool>(&mut self) -> DynamicManagedRefMut {
918        unsafe {
919            if LOCKING {
920                match &self.kind {
921                    Kind::Owned { lifetime, data } => loop {
922                        if let Some(lifetime) = lifetime.borrow_mut() {
923                            return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
924                                .expect("DynamicManagedGc cannot be mutably borrowed");
925                        }
926                        std::hint::spin_loop();
927                    },
928                    Kind::Referenced { lifetime, data } => loop {
929                        if !lifetime.exists() {
930                            panic!("DynamicManagedGc owner is dead");
931                        }
932                        if let Some(lifetime) = lifetime.borrow_mut() {
933                            return DynamicManagedRefMut::new_raw(self.type_hash, lifetime, *data)
934                                .expect("DynamicManagedGc cannot be mutably borrowed");
935                        }
936                        std::hint::spin_loop();
937                    },
938                }
939            } else {
940                match &self.kind {
941                    Kind::Owned { lifetime, data } => DynamicManagedRefMut::new_raw(
942                        self.type_hash,
943                        lifetime
944                            .borrow_mut()
945                            .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
946                        *data,
947                    )
948                    .expect("DynamicManagedGc cannot be mutably borrowed"),
949                    Kind::Referenced { lifetime, data } => DynamicManagedRefMut::new_raw(
950                        self.type_hash,
951                        lifetime
952                            .borrow_mut()
953                            .expect("DynamicManagedGc is inaccessible for mutable borrowing"),
954                        *data,
955                    )
956                    .expect("DynamicManagedGc cannot be mutably borrowed"),
957                }
958            }
959        }
960    }
961
962    /// Takes an unclaimed handle, which claims nothing and never blocks.
963    ///
964    /// # Panics
965    ///
966    /// Panics when the value is gone.
967    pub fn lazy(&self) -> DynamicManagedLazy {
968        unsafe {
969            match &self.kind {
970                Kind::Owned { lifetime, data } => {
971                    DynamicManagedLazy::new_raw(self.type_hash, lifetime.lazy(), *data)
972                        .expect("DynamicManagedGc cannot be lazily borrowed")
973                }
974                Kind::Referenced { lifetime, data } => {
975                    DynamicManagedLazy::new_raw(self.type_hash, lifetime.clone(), *data)
976                        .expect("DynamicManagedGc cannot be lazily borrowed")
977                }
978            }
979        }
980    }
981
982    /// Returns the allocation pointer, checking nothing.
983    ///
984    /// # Safety
985    ///
986    /// Neither the type, the borrow state, nor whether the value is still
987    /// alive is checked.
988    pub unsafe fn as_ptr_raw(&self) -> *const u8 {
989        match &self.kind {
990            Kind::Owned { data, .. } => *data as *const u8,
991            Kind::Referenced { data, .. } => *data as *const u8,
992        }
993    }
994
995    /// Returns the mutable allocation pointer, checking nothing.
996    ///
997    /// # Safety
998    ///
999    /// Neither the type, the borrow state, nor whether the value is still
1000    /// alive is checked.
1001    pub unsafe fn as_mut_ptr_raw(&mut self) -> *mut u8 {
1002        match &self.kind {
1003            Kind::Owned { data, .. } => *data,
1004            Kind::Referenced { data, .. } => *data,
1005        }
1006    }
1007}
1008
1009impl TryFrom<DynamicManagedValue> for DynamicManagedGc {
1010    type Error = ();
1011
1012    fn try_from(value: DynamicManagedValue) -> Result<Self, Self::Error> {
1013        match value {
1014            DynamicManagedValue::Gc(value) => Ok(value),
1015            _ => Err(()),
1016        }
1017    }
1018}
1019
1020#[cfg(test)]
1021mod tests {
1022    use super::*;
1023
1024    #[test]
1025    fn test_is_async() {
1026        fn is_async<T: Send + Sync>() {}
1027
1028        is_async::<ManagedGc<()>>();
1029        is_async::<DynamicManagedGc>();
1030    }
1031
1032    #[test]
1033    fn test_managed_gc() {
1034        let mut managed = ManagedGc::new(42);
1035        {
1036            let read_access = managed.read::<true>();
1037            assert_eq!(*read_access, 42);
1038        }
1039        {
1040            let mut write_access = managed.write::<true>();
1041            *write_access = 100;
1042        }
1043        {
1044            let read_access = managed.read::<true>();
1045            assert_eq!(*read_access, 100);
1046        }
1047    }
1048
1049    #[test]
1050    #[allow(unused)]
1051    fn test_managed_gc_lifetimes() {
1052        struct Car {
1053            gear: i32,
1054            engine: Option<ManagedGc<Engine>>,
1055        }
1056
1057        struct Engine {
1058            owning_car: Option<ManagedGc<Car>>,
1059            horsepower: i32,
1060        }
1061
1062        let mut car = ManagedGc::new(Car {
1063            gear: 1,
1064            engine: None,
1065        });
1066        let engine = ManagedGc::new(Engine {
1067            owning_car: Some(car.reference()),
1068            horsepower: 200,
1069        });
1070        let engine2 = engine.reference();
1071        car.write::<true>().engine = Some(engine);
1072
1073        assert!(car.exists());
1074        assert!(car.is_owning());
1075        assert!(engine2.exists());
1076        assert!(engine2.is_referencing());
1077        assert!(engine2.is_owned_by(car.read::<true>().engine.as_ref().unwrap()));
1078
1079        let car2 = car.reference();
1080        assert!(car2.exists());
1081        assert!(car2.is_referencing());
1082
1083        drop(car);
1084        assert!(!car2.exists());
1085        assert!(car2.try_read().is_none());
1086        assert!(!engine2.exists());
1087        assert!(engine2.try_read().is_none());
1088    }
1089
1090    #[test]
1091    fn test_managed_gc_cycles() {
1092        #[derive(Default)]
1093        struct Foo {
1094            other: Option<ManagedGc<Self>>,
1095        }
1096
1097        {
1098            let mut a = ManagedGc::<Foo>::default();
1099            let mut b = ManagedGc::<Foo>::default();
1100            a.write::<true>().other = Some(b.reference());
1101            b.write::<true>().other = Some(a.reference());
1102
1103            assert!(a.exists());
1104            assert!(a.is_owning());
1105            assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
1106            assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&b));
1107
1108            assert!(b.exists());
1109            assert!(b.is_owning());
1110            assert!(b.read::<true>().other.as_ref().unwrap().is_referencing());
1111            assert!(b.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
1112
1113            drop(b);
1114            assert!(!a.read::<true>().other.as_ref().unwrap().exists());
1115        }
1116
1117        {
1118            let mut a = ManagedGc::<Foo>::default();
1119            a.write::<true>().other = Some(a.reference());
1120
1121            assert!(a.exists());
1122            assert!(a.is_owning());
1123            assert!(a.read::<true>().other.as_ref().unwrap().is_referencing());
1124            assert!(a.read::<true>().other.as_ref().unwrap().is_owned_by(&a));
1125        }
1126    }
1127
1128    #[test]
1129    fn test_dynamic_managed_gc() {
1130        let mut managed = DynamicManagedGc::new(42);
1131        {
1132            let read_access = managed.read::<true, i32>();
1133            assert_eq!(*read_access, 42);
1134        }
1135        {
1136            let mut write_access = managed.write::<true, i32>();
1137            *write_access = 100;
1138        }
1139        {
1140            let read_access = managed.read::<true, i32>();
1141            assert_eq!(*read_access, 100);
1142        }
1143    }
1144
1145    #[test]
1146    fn test_dynamic_managed_gc_cycles() {
1147        #[derive(Default)]
1148        struct Foo {
1149            other: Option<DynamicManagedGc>,
1150        }
1151
1152        {
1153            let mut a = DynamicManagedGc::new(Foo::default());
1154            let mut b = DynamicManagedGc::new(Foo::default());
1155            a.write::<true, Foo>().other = Some(b.reference());
1156            b.write::<true, Foo>().other = Some(a.reference());
1157
1158            assert!(a.exists());
1159            assert!(a.is_owning());
1160            assert!(
1161                a.read::<true, Foo>()
1162                    .other
1163                    .as_ref()
1164                    .unwrap()
1165                    .is_referencing()
1166            );
1167            assert!(
1168                a.read::<true, Foo>()
1169                    .other
1170                    .as_ref()
1171                    .unwrap()
1172                    .is_owned_by(&b)
1173            );
1174
1175            assert!(b.exists());
1176            assert!(b.is_owning());
1177            assert!(
1178                b.read::<true, Foo>()
1179                    .other
1180                    .as_ref()
1181                    .unwrap()
1182                    .is_referencing()
1183            );
1184            assert!(
1185                b.read::<true, Foo>()
1186                    .other
1187                    .as_ref()
1188                    .unwrap()
1189                    .is_owned_by(&a)
1190            );
1191
1192            drop(b);
1193            assert!(!a.read::<true, Foo>().other.as_ref().unwrap().exists());
1194        }
1195
1196        {
1197            let mut a = DynamicManagedGc::new(Foo::default());
1198            a.write::<true, Foo>().other = Some(a.reference());
1199
1200            assert!(a.exists());
1201            assert!(a.is_owning());
1202            assert!(
1203                a.read::<true, Foo>()
1204                    .other
1205                    .as_ref()
1206                    .unwrap()
1207                    .is_referencing()
1208            );
1209            assert!(
1210                a.read::<true, Foo>()
1211                    .other
1212                    .as_ref()
1213                    .unwrap()
1214                    .is_owned_by(&a)
1215            );
1216        }
1217    }
1218
1219    #[test]
1220    fn test_managed_gc_conversions() {
1221        let managed = ManagedGc::new(42);
1222        assert_eq!(*managed.read::<true>(), 42);
1223
1224        let mut dynamic = managed.into_dynamic();
1225        *dynamic.write::<true, i32>() = 100;
1226
1227        let managed = dynamic.into_typed::<i32>();
1228        assert_eq!(*managed.read::<true>(), 100);
1229    }
1230
1231    #[test]
1232    fn test_managed_gc_dead_owner() {
1233        let a = ManagedGc::new(42);
1234        let mut b = a.reference();
1235
1236        assert!(a.exists());
1237        assert!(b.exists());
1238        assert_eq!(*b.read::<true>(), 42);
1239
1240        drop(a);
1241        assert!(!b.exists());
1242        assert!(b.try_write().is_none());
1243    }
1244
1245    #[test]
1246    #[should_panic]
1247    fn test_managed_gc_dead_owner_panic() {
1248        let a = ManagedGc::new(42);
1249        let mut b = a.reference();
1250
1251        assert!(a.exists());
1252        assert!(b.exists());
1253        assert_eq!(*b.read::<true>(), 42);
1254
1255        drop(a);
1256        assert!(!b.exists());
1257        assert_eq!(*b.write::<true>(), 42);
1258    }
1259
1260    #[test]
1261    fn test_managed_gc_cyclic() {
1262        struct SelfReferencial {
1263            value: i32,
1264            this: ManagedGc<SelfReferencial>,
1265        }
1266
1267        let v = unsafe { ManagedGc::new_cyclic(|this| SelfReferencial { value: 42, this }) };
1268        assert_eq!(v.read::<true>().value, 42);
1269        let this = v.read::<true>().this.reference();
1270        assert_eq!(this.read::<true>().value, 42);
1271    }
1272
1273    #[test]
1274    fn test_managed_gc_transfer_ownership() {
1275        let mut a = ManagedGc::new(42);
1276        let mut b = a.reference();
1277
1278        assert!(!a.is_owned_by(&b));
1279        assert!(b.is_owned_by(&a));
1280        assert!(!b.transfer_ownership(&mut a));
1281        assert!(a.transfer_ownership(&mut b));
1282        assert!(a.is_owned_by(&b));
1283        assert!(!b.is_owned_by(&a));
1284        drop(b);
1285        assert!(!a.exists());
1286    }
1287}