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