use crate::{Gc, GcWeak}; pub use gc_arena_derive::Collect; /// A trait for garbage collected objects that can be placed into `Gc` pointers. This trait is /// unsafe, because `Gc` pointers inside an Arena are assumed never to be dangling, and in order to /// ensure this certain rules must be followed: /// /// 1. `Collect::trace` *must* trace over *every* `Gc` and `GcWeak` pointer held inside this type. /// 2. Held `Gc` and `GcWeak` pointers must not be accessed inside `Drop::drop` since during drop /// any such pointer may be dangling. /// 3. Internal mutability *must* not be used to adopt new `Gc` or `GcWeak` pointers without /// calling appropriate write barrier operations during the same arena mutation. /// /// It is, however, possible to implement this trait safely by procedurally deriving it (see /// [`gc_arena_derive::Collect`]), which requires that every field in the structure also implement /// `Collect`, and ensures that `Drop` cannot safely be implemented. Internally mutable types like /// `Cell` and `RefCell` do not implement `Collect` in such a way that it is possible to store /// `Gc` pointers inside them, so write barrier requirements cannot be broken when procedurally /// deriving `Collect`. A safe way of providing internal mutability in this case is to use /// [`crate::lock::Lock`] and [`crate::lock::RefLock`], which provides internal mutability /// while ensuring that write barriers are correctly executed. pub unsafe trait Collect<'gc> { /// As an optimization, if this type can never hold a `Gc` pointer and `trace` is unnecessary /// to call, you may set this to `false`. The default value is `true`, signaling that /// `Collect::trace` must be called. const NEEDS_TRACE: bool = true; /// *Must* call [`Trace::trace_gc`] (resp. [`Trace::trace_gc_weak`]) on all directly owned /// [`Gc`] (resp. [`GcWeak`]) pointers. If this type holds inner types that implement `Collect`, /// a valid implementation would simply call [`Trace::trace`] on all the held values to ensure /// this. /// /// # Tracing pointers /// /// [`Gc`] and [`GcWeak`] have their own implementations of `Collect` which in turn call /// [`Trace::trace_gc`] and [`Trace::trace_gc_weak`] respectively. Because of this, it is not /// actually ever necessary to call [`Trace::trace_gc`] and [`Trace::trace_gc_weak`] directly, /// but be careful! It is important that owned pointers *themselves* are traced and NOT their /// contents (the content type will usually also implement `Collect`, so this is easy to /// accidentally do). /// /// It is always okay to use the [`Trace::trace_gc`] and [`Trace::trace_gc_weak`] directly as a /// potentially less risky alternative when manually implementing `Collect`. #[inline] #[allow(unused_variables)] fn trace>(&self, cc: &mut T) {} } /// The trait that is passed to the [`Collect::trace`] method. /// /// Though [`Collect::trace`] is primarily used during the marking phase of the mark and sweep /// collector, this is a trait rather than a concrete type to facilitate other kinds of uses. /// /// This trait is not itself unsafe, but implementers of [`Collect`] *must* uphold the safety /// guarantees of [`Collect`] when using this trait. pub trait Trace<'gc> { /// Trace a [`Gc`] pointer (of any real type). fn trace_gc(&mut self, gc: Gc<'gc, ()>); /// Trace a [`GcWeak`] pointer (of any real type). fn trace_gc_weak(&mut self, gc: GcWeak<'gc, ()>); /// This is a convenience method that calls [`Collect::trace`] but automatically adds a /// [`Collect::NEEDS_TRACE`] check around it. /// /// Manual implementations of [`Collect`] are encouraged to use this to ensure that there /// is a [`Collect::NEEDS_TRACE`] check without having to implement it manually. This can be /// important in cases where the [`Collect::trace`] method impl is not `#[inline]` or does not /// have its own early exit. /// /// There is generally no need for custom `Trace` implementations to override this method. #[inline] fn trace + ?Sized>(&mut self, value: &C) where Self: Sized, { if C::NEEDS_TRACE { value.trace(self); } } } /// If a type is static, we know that it can never hold `Gc` pointers, so it is safe to provide a /// simple empty `Collect` implementation. /// /// This macro may be called in multiple ways: /// /// ```ignore /// static_collect!(MyTrait<'gc>); /// static_collect!( MyTrait<'gc, T> where T: Clone); /// static_collect!( MyTrait<'gc, Assoc = T>); /// ``` /// /// Type parameters may be declared using `` at the beginning of the macro, along with an /// optional trailing where clause. #[macro_export] macro_rules! static_collect { (<$($params:tt),+ $(,)*> $type:ty $(where $($bounds:tt)+)?) => { unsafe impl<'gc, $($params),*> $crate::Collect<'gc> for $type where $type: 'static, $($($bounds)+)* { const NEEDS_TRACE: bool = false; } }; ($type:ty) => { unsafe impl<'gc> $crate::Collect<'gc> for $type where $type: 'static, { const NEEDS_TRACE: bool = false; } } } /// An object safe version of the [`Collect`] trait. /// /// This is automatically implemented for all types that implement the normal `Collect` trait. /// /// The `dyn DynCollect` trait object implements `Collect` automatically, but trait objects for user /// defined traits that have `DynCollect` as a parent trait can also be made to implement `Collect` /// by using the [`dyn_collect`] macro. pub unsafe trait DynCollect<'gc> { fn dyn_trace(&self, cc: &mut dyn Trace<'gc>); } unsafe impl<'gc> Collect<'gc> for dyn DynCollect<'gc> { fn trace>(&self, cc: &mut T) { self.dyn_trace(cc) } } unsafe impl<'gc, T: Collect<'gc>> DynCollect<'gc> for T { fn dyn_trace(&self, cc: &mut dyn Trace<'gc>) { struct TraceWrap<'a, 'gc>(&'a mut dyn Trace<'gc>); impl<'a, 'gc> Trace<'gc> for TraceWrap<'a, 'gc> { fn trace_gc(&mut self, gc: Gc<'gc, ()>) { self.0.trace_gc(gc) } fn trace_gc_weak(&mut self, gc: GcWeak<'gc, ()>) { self.0.trace_gc_weak(gc) } } self.trace(&mut TraceWrap(cc)) } } /// Implement [`Collect`] for custom trait objects. /// /// The trait being implemented must have [`DynCollect`] as a supertrait. /// /// This macro may be called in multiple ways: /// /// ```ignore /// dyn_collect!(dyn MyTrait<'gc>); /// dyn_collect!( dyn MyTrait<'gc, T> where T: Clone); /// dyn_collect!( dyn MyTrait<'gc, Assoc = T>); /// ``` /// /// The generated impl always has a single `'gc` lifetime parameter that is used as the `'gc` /// parameter on the `Collect` trait. Additional type and lifetime parameters may be declared using /// `` at the beginning of the macro, along with an optional trailing where clause. #[doc(hidden)] #[macro_export] macro_rules! __dyn_collect { (<$($params:tt),+ $(,)*> $trait:ty $(where $($bounds:tt)+)?) => { unsafe impl<'gc, $($params),*> $crate::Collect<'gc> for $trait where $($($bounds)+)* { fn trace<_T: $crate::collect::Trace<'gc>>(&self, cc: &mut _T) { $crate::collect::DynCollect::dyn_trace(self, cc); } } }; ($trait:ty) => { unsafe impl<'gc> $crate::Collect<'gc> for $trait { fn trace<_T: $crate::collect::Trace<'gc>>(&self, cc: &mut _T) { $crate::collect::DynCollect::dyn_trace(self, cc); } } } } #[doc(inline)] pub use crate::__dyn_collect as dyn_collect;