use core::num::Wrapping;
use crate::prelude::*;
use crate::{GcDirectBarrier, CollectorId};
macro_rules! trace_tuple {
{ $($param:ident)* } => {
unsafe impl<$($param),*> Trace for ($($param,)*)
where $($param: Trace),* {
const NEEDS_TRACE: bool = $($param::NEEDS_TRACE || )* false;
#[inline]
fn visit<Visit: $crate::GcVisitor>(&mut self, #[allow(unused)] visitor: &mut Visit) -> Result<(), Visit::Err> {
#[allow(non_snake_case)]
let ($(ref mut $param,)*) = *self;
$(visitor.visit::<$param>($param)?;)*
Ok(())
}
}
unsafe impl<$($param),*> TraceImmutable for ($($param,)*)
where $($param: TraceImmutable),* {
#[inline]
fn visit_immutable<V: $crate::GcVisitor>(&self, #[allow(unused)] visitor: &mut V) -> Result<(), V::Err> {
#[allow(non_snake_case)]
let ($(ref $param,)*) = *self;
$(visitor.visit_immutable::<$param>($param)?;)*
Ok(())
}
}
unsafe impl<$($param: NullTrace),*> NullTrace for ($($param,)*) {}
unsafe impl<'new_gc, Id, $($param),*> $crate::GcRebrand<'new_gc, Id> for ($($param,)*)
where Id: $crate::CollectorId, $($param: $crate::GcRebrand<'new_gc, Id>,)*
$(<$param as $crate::GcRebrand<'new_gc, Id>>::Branded: Sized,)* {
type Branded = ($(<$param as $crate::GcRebrand<'new_gc, Id>>::Branded,)*);
}
unsafe impl<'a, Id, $($param),*> $crate::GcErase<'a, Id> for ($($param,)*)
where Id: $crate::CollectorId, $($param: $crate::GcErase<'a, Id>,)*
$(<$param as $crate::GcErase<'a, Id>>::Erased: Sized,)* {
type Erased = ($(<$param as $crate::GcErase<'a, Id>>::Erased,)*);
}
unsafe impl<$($param: GcSafe),*> GcSafe for ($($param,)*) {
const NEEDS_DROP: bool = false $(|| <$param as GcSafe>::NEEDS_DROP)*;
}
unsafe impl<'gc, OwningRef, $($param),*> $crate::GcDirectBarrier<'gc, OwningRef> for ($($param,)*)
where $($param: $crate::GcDirectBarrier<'gc, OwningRef>),* {
#[inline]
unsafe fn write_barrier(
&self, #[allow(unused)] owner: &OwningRef,
#[allow(unused)] start_offset: usize
) {
#[allow(non_snake_case)]
let ($(ref $param,)*) = *self;
$({
let field_offset = ($param as *const $param as usize)
- (self as *const Self as usize);
$param.write_barrier(owner, field_offset + start_offset);
};)*
}
}
};
}
unsafe_trace_primitive!(i8);
unsafe_trace_primitive!(i16);
unsafe_trace_primitive!(i32);
unsafe_trace_primitive!(i64);
unsafe_trace_primitive!(isize);
unsafe_trace_primitive!(u8);
unsafe_trace_primitive!(u16);
unsafe_trace_primitive!(u32);
unsafe_trace_primitive!(u64);
unsafe_trace_primitive!(usize);
unsafe_trace_primitive!(f32);
unsafe_trace_primitive!(f64);
unsafe_trace_primitive!(bool);
unsafe_trace_primitive!(char);
unsafe_trace_primitive!(&'static str);
trace_tuple! {}
trace_tuple! { A }
trace_tuple! { A B }
trace_tuple! { A B C }
trace_tuple! { A B C D }
trace_tuple! { A B C D E }
trace_tuple! { A B C D E F }
trace_tuple! { A B C D E F G }
trace_tuple! { A B C D E F G H }
trace_tuple! { A B C D E F G H I }
macro_rules! trace_array {
($size:tt) => {
unsafe impl<T: Trace> Trace for [T; $size] {
const NEEDS_TRACE: bool = T::NEEDS_TRACE;
#[inline]
fn visit<V: $crate::GcVisitor>(&mut self, visitor: &mut V) -> Result<(), V::Err> {
visitor.visit::<[T]>(self as &mut [T])
}
}
unsafe impl<T: $crate::TraceImmutable> $crate::TraceImmutable for [T; $size] {
#[inline]
fn visit_immutable<V: $crate::GcVisitor>(&self, visitor: &mut V) -> Result<(), V::Err> {
visitor.visit_immutable::<[T]>(self as &[T])
}
}
unsafe impl<T: $crate::NullTrace> $crate::NullTrace for [T; $size] {}
unsafe impl<T: GcSafe> GcSafe for [T; $size] {
const NEEDS_DROP: bool = core::mem::needs_drop::<T>();
}
unsafe impl<'new_gc, Id, T> $crate::GcRebrand<'new_gc, Id> for [T; $size]
where Id: CollectorId, T: GcRebrand<'new_gc, Id>,
<T as GcRebrand<'new_gc, Id>>::Branded: Sized {
type Branded = [<T as GcRebrand<'new_gc, Id>>::Branded; $size];
}
unsafe impl<'a, Id, T> $crate::GcErase<'a, Id> for [T; $size]
where Id: CollectorId, T: GcErase<'a, Id>,
<T as GcErase<'a, Id>>::Erased: Sized {
type Erased = [<T as GcErase<'a, Id>>::Erased; $size];
}
};
{ $($size:tt),* } => ($(trace_array!($size);)*)
}
trace_array! {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
24, 32, 48, 64, 100, 128, 256, 512, 1024, 2048, 4096
}
unsafe impl<'a, T: TraceImmutable> Trace for &'a T {
const NEEDS_TRACE: bool = T::NEEDS_TRACE;
#[inline(always)]
fn visit<V: GcVisitor>(&mut self, visitor: &mut V) -> Result<(), V::Err> {
visitor.visit_immutable::<T>(*self)
}
}
unsafe impl<'a, T: TraceImmutable> TraceImmutable for &'a T {
#[inline(always)]
fn visit_immutable<V: GcVisitor>(&self, visitor: &mut V) -> Result<(), V::Err> {
visitor.visit_immutable::<T>(*self)
}
}
unsafe impl<'a, T: NullTrace> NullTrace for &'a T {}
unsafe impl<'a, T: GcSafe + TraceImmutable> GcSafe for &'a T {
const NEEDS_DROP: bool = false;
}
unsafe impl<'a, 'new_gc, Id, T> GcRebrand<'new_gc, Id> for &'a T
where Id: CollectorId, T: NullTrace, 'a: 'new_gc {
type Branded = &'a T;
}
unsafe impl<'a, Id, T> GcErase<'a, Id> for &'a T
where Id: CollectorId, T: NullTrace {
type Erased = &'a T;
}
unsafe impl<'a, T: Trace> Trace for &'a mut T {
const NEEDS_TRACE: bool = T::NEEDS_TRACE;
#[inline(always)]
fn visit<V: GcVisitor>(&mut self, visitor: &mut V) -> Result<(), V::Err> {
visitor.visit::<T>(*self)
}
}
unsafe impl<'a, T: TraceImmutable> TraceImmutable for &'a mut T {
#[inline(always)]
fn visit_immutable<V: GcVisitor>(&self, visitor: &mut V) -> Result<(), V::Err> {
visitor.visit_immutable::<T>(&**self)
}
}
unsafe impl<'a, T: NullTrace> NullTrace for &'a mut T {}
unsafe impl<'a, T: GcSafe> GcSafe for &'a mut T {
const NEEDS_DROP: bool = false;
}
unsafe impl<'a, 'new_gc, Id, T> GcRebrand<'new_gc, Id> for &'a mut T
where Id: CollectorId, T: NullTrace, 'a: 'new_gc {
type Branded = &'a mut T;
}
unsafe impl<'a, Id, T> GcErase<'a, Id> for &'a mut T
where Id: CollectorId, T: NullTrace {
type Erased = &'a mut T;
}
unsafe impl<T: Trace> Trace for [T] {
const NEEDS_TRACE: bool = T::NEEDS_TRACE ;
#[inline]
fn visit<V: GcVisitor>(&mut self, visitor: &mut V) -> Result<(), V::Err> {
if !T::NEEDS_TRACE { return Ok(()) };
for value in self {
visitor.visit(value)?;
}
Ok(())
}
}
unsafe impl<T: TraceImmutable> TraceImmutable for [T] {
#[inline]
fn visit_immutable<V: GcVisitor>(&self, visitor: &mut V) -> Result<(), <V as GcVisitor>::Err> {
if !T::NEEDS_TRACE { return Ok(()) };
for value in self {
visitor.visit_immutable(value)?;
}
Ok(())
}
}
unsafe impl<T: NullTrace> NullTrace for [T] {}
unsafe impl<T: GcSafe> GcSafe for [T] {
const NEEDS_DROP: bool = core::mem::needs_drop::<T>();
}
unsafe impl<T: Trace> Trace for Option<T> {
const NEEDS_TRACE: bool = T::NEEDS_TRACE;
#[inline]
fn visit<V: GcVisitor>(&mut self, visitor: &mut V) -> Result<(), V::Err> {
match *self {
None => Ok(()),
Some(ref mut value) => visitor.visit(value),
}
}
}
unsafe impl<T: TraceImmutable> TraceImmutable for Option<T> {
#[inline]
fn visit_immutable<V: GcVisitor>(&self, visitor: &mut V) -> Result<(), <V as GcVisitor>::Err> {
match *self {
None => Ok(()),
Some(ref value) => visitor.visit_immutable(value),
}
}
}
unsafe impl<T: NullTrace> NullTrace for Option<T> {}
unsafe impl<T: GcSafe> GcSafe for Option<T> {
const NEEDS_DROP: bool = T::NEEDS_DROP;
}
unsafe impl<'gc, OwningRef, V> GcDirectBarrier<'gc, OwningRef> for Option<V>
where V: GcDirectBarrier<'gc, OwningRef> {
#[inline]
unsafe fn write_barrier(&self, owner: &OwningRef, start_offset: usize) {
match *self {
None => { },
Some(ref value) => {
let value_offset = (value as *const V as usize) -
(self as *const Self as usize);
value.write_barrier(owner, start_offset + value_offset)
},
}
}
}
unsafe_gc_brand!(Option, T);
unsafe_trace_deref!(Wrapping, T; immut = false; |wrapping| &mut wrapping.0);
unsafe impl<T: TraceImmutable> TraceImmutable for Wrapping<T> {
#[inline]
fn visit_immutable<V: GcVisitor>(&self, visitor: &mut V) -> Result<(), V::Err> {
visitor.visit_immutable(&self.0)
}
}