pub unsafe trait Collect {
// Provided methods
fn needs_trace() -> bool
where Self: Sized { ... }
fn trace(&self, _cc: &Collection) { ... }
}
Expand description
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:
Collect::trace
must trace over everyGc
pointer held inside this type, and cannot fail.- Held
Gc
pointers must not be accessed insideDrop::drop
since during drop any such pointer may be dangling. - Internal mutability must not be used to adopt new
Gc
pointers without callingGc::write
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 the write barrier requirement cannot be broken when procedurally
deriving Collect
. A safe way of providing internal mutability in this case is to use
crate::lock::Lock<T>
and crate::lock::RefLock<T>
, which provides internal mutability
while ensuring that the write barrier is always executed.
Provided Methods§
sourcefn needs_trace() -> boolwhere
Self: Sized,
fn needs_trace() -> boolwhere
Self: Sized,
As an optimization, if this type can never hold a Gc
pointer and trace
is unnecessary
to call, you may implement this method and return false. The default implementation returns
true, signaling that Collect::trace
must be called.
sourcefn trace(&self, _cc: &Collection)
fn trace(&self, _cc: &Collection)
Must call Collect::trace
on all held Gc
pointers. If this type holds inner types that
implement Collect
, a valid implementation would simply call Collect::trace
on all the
held values to ensure this.
Implementations on Foreign Types§
source§impl<A> Collect for (A,)where
A: Collect,
impl<A> Collect for (A,)where
A: Collect,
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B> Collect for (A, B)
impl<A, B> Collect for (A, B)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C> Collect for (A, B, C)
impl<A, B, C> Collect for (A, B, C)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D> Collect for (A, B, C, D)
impl<A, B, C, D> Collect for (A, B, C, D)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E> Collect for (A, B, C, D, E)
impl<A, B, C, D, E> Collect for (A, B, C, D, E)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F> Collect for (A, B, C, D, E, F)
impl<A, B, C, D, E, F> Collect for (A, B, C, D, E, F)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G> Collect for (A, B, C, D, E, F, G)
impl<A, B, C, D, E, F, G> Collect for (A, B, C, D, E, F, G)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H> Collect for (A, B, C, D, E, F, G, H)
impl<A, B, C, D, E, F, G, H> Collect for (A, B, C, D, E, F, G, H)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I> Collect for (A, B, C, D, E, F, G, H, I)
impl<A, B, C, D, E, F, G, H, I> Collect for (A, B, C, D, E, F, G, H, I)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I, J> Collect for (A, B, C, D, E, F, G, H, I, J)
impl<A, B, C, D, E, F, G, H, I, J> Collect for (A, B, C, D, E, F, G, H, I, J)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I, J, K> Collect for (A, B, C, D, E, F, G, H, I, J, K)
impl<A, B, C, D, E, F, G, H, I, J, K> Collect for (A, B, C, D, E, F, G, H, I, J, K)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I, J, K, L> Collect for (A, B, C, D, E, F, G, H, I, J, K, L)
impl<A, B, C, D, E, F, G, H, I, J, K, L> Collect for (A, B, C, D, E, F, G, H, I, J, K, L)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I, J, K, L, M> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M)
impl<A, B, C, D, E, F, G, H, I, J, K, L, M> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M, N)
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M, N)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)
impl<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P> Collect for (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P)
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<K, V> Collect for BTreeMap<K, V>
impl<K, V> Collect for BTreeMap<K, V>
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<K, V, S> Collect for HashMap<K, V, S>
impl<K, V, S> Collect for HashMap<K, V, S>
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T> Collect for BTreeSet<T>where
T: Collect,
impl<T> Collect for BTreeSet<T>where
T: Collect,
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T> Collect for PhantomData<T>
impl<T> Collect for PhantomData<T>
fn needs_trace() -> bool
source§impl<T, S> Collect for HashSet<T, S>where
T: Collect,
S: 'static,
impl<T, S> Collect for HashSet<T, S>where
T: Collect,
S: 'static,
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: Collect> Collect for Option<T>
impl<T: Collect> Collect for Option<T>
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: Collect> Collect for [T]
impl<T: Collect> Collect for [T]
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: Collect> Collect for LinkedList<T>
impl<T: Collect> Collect for LinkedList<T>
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: Collect> Collect for VecDeque<T>
impl<T: Collect> Collect for VecDeque<T>
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: Collect> Collect for Vec<T>
impl<T: Collect> Collect for Vec<T>
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: Collect, E: Collect> Collect for Result<T, E>
impl<T: Collect, E: Collect> Collect for Result<T, E>
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: Collect, const N: usize> Collect for [T; N]
impl<T: Collect, const N: usize> Collect for [T; N]
fn needs_trace() -> bool
fn trace(&self, cc: &Collection)
source§impl<T: ?Sized + 'static> Collect for &'static T
impl<T: ?Sized + 'static> Collect for &'static T
SAFETY: We know that a &'static
reference cannot possibly point to 'gc
data, so it is safe
to keep in a rooted objet and we do not have to trace through it.
HOWEVER, There is an extra bound here that seems superfluous. If we have a &'static T
, why do
we require T: 'static
, shouldn’t this be implied, otherwise a &'static T
would not be well-
formed? WELL, there are currently some neat compiler bugs, observe…
let arena = Arena::<Rootable![&'static Gc<'gc, i32>]>::new(Default::default(), |mc| {
Box::leak(Box::new(Gc::new(mc, 4)))
});
At the time of this writing, without the extra T: static
bound, the above code compiles and
produces an arena with a reachable but un-traceable Gc<'gc, i32>
, and this is unsound. This
is ofc the stored type of the root, since the Arena is actually constructing a &'static Gc<'static, i32>
as the root object, but this should still not rightfully compile due to the
signature of the constructor callback passed to Arena::new
. In fact, the ’static lifetime is a
red herring, it is possible to change the internals of Arena
such that the ’gc lifetime given
to the callback is not ’static, and the problem persists.
It should not be required to have this extra lifetime bound, and yet! It fixes the above issue perfectly and the given example of unsoundness no longer compiles. So, until this rustc bug is fixed…
DO NOT REMOVE THIS EXTRA T: 'static
BOUND