#![feature(
const_panic, // RFC 2345 - Const asserts
)]
#![deny(missing_docs)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg(any(feature = "alloc", feature = "std"))]
extern crate alloc;
use core::mem;
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
use core::marker::PhantomData;
use core::hash::{Hash, Hasher};
use core::fmt::{self, Debug, Formatter};
#[macro_use]
mod manually_traced;
pub mod cell;
pub mod prelude;
#[macro_export(local_inner_macros)]
macro_rules! safepoint_recurse {
($context:ident, |$sub_context:ident| $closure:expr) => {{
let ((), result) = safepoint_recurse!($context, (), |$sub_context, new_root| {
let () = new_root;
$closure
});
result
}};
($context:ident, $root:expr, |$sub_context:ident, $new_root:ident| $closure:expr) => {{
let mut root = $root;
let result = unsafe { __recurse_context!($context, &mut root, |$sub_context, $new_root| {
$closure
}) };
let updated_root = safepoint!($context, $root);
(updated_root, result)
}};
($context:ident, $root:expr, @managed_result, |$sub_context:ident, $new_root:ident| $closure:expr) => {{
use $crate::{GcContext};
let mut root = $root;
let erased_result = unsafe { __recurse_context!(
$context, &mut root,
|$sub_context, $new_root| {
let result = $closure;
$sub_context.rebrand_static(result)
}
) };
let result = unsafe { $context.rebrand_self(erased_result) };
safepoint!($context, (root, result))
}};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __recurse_context {
($context:ident, $root:expr, |$sub_context:ident, $new_root:ident| $closure:expr) => {{
use $crate::{GcContext};
$context.recurse_context(&mut $root, |mut $sub_context, erased_root| {
let $new_root = $sub_context.rebrand_self(erased_root);
$closure
})
}};
}
#[macro_export]
macro_rules! safepoint {
($context:ident, $value:expr) => {unsafe {
use $crate::{GcContext};
let mut erased = $context.rebrand_static($value);
$context.basic_safepoint(&mut &mut erased);
$context.rebrand_self(erased)
}};
}
#[macro_export]
macro_rules! freeze_context {
($context:ident) => {unsafe {
use $crate::{GcContext, FrozenContext};
let mut context = $context;
context.freeze();
FrozenContext::new(context)
}};
}
#[macro_export]
macro_rules! unfreeze_context {
($frozen:ident) => {unsafe {
use $crate::{FrozenContext, GcContext};
let mut context = FrozenContext::into_context($frozen);
context.unfreeze();
context
}};
}
pub unsafe trait GcSystem {
type Id: CollectorId;
type Context: GcContext<Id=Self::Id>;
}
pub unsafe trait GcHandleSystem<'gc, T: GcSafe + ?Sized + 'gc>: GcSystem
where T: GcBrand<'static, Self::Id>,
<T as GcBrand<'static, Self::Id>>::Branded: GcSafe {
type Handle: GcHandle<<T as GcBrand<'static, Self::Id>>::Branded, System=Self>;
#[doc(hidden)]
fn create_handle(gc: Gc<'gc, T, Self::Id>) -> Self::Handle;
}
pub unsafe trait GcContext: Sized {
type System: GcSystem<Context=Self, Id=Self::Id>;
type Id: CollectorId;
unsafe fn basic_safepoint<T: Trace>(&mut self, value: &mut &mut T);
unsafe fn freeze(&mut self);
unsafe fn unfreeze(&mut self);
#[inline(always)]
#[doc(hidden)]
unsafe fn rebrand_static<T>(&self, value: T) -> T::Branded
where T: GcBrand<'static, Self::Id> {
let branded = mem::transmute_copy(&value);
mem::forget(value);
branded
}
#[inline(always)]
#[doc(hidden)]
unsafe fn rebrand_self<'a, T>(&'a self, value: T) -> T::Branded
where T: GcBrand<'a, Self::Id> {
let branded = mem::transmute_copy(&value);
mem::forget(value);
branded
}
unsafe fn recurse_context<T, F, R>(&self, value: &mut &mut T, func: F) -> R
where T: Trace, F: for <'gc> FnOnce(&'gc mut Self, &'gc mut T) -> R;
}
pub unsafe trait GcSimpleAlloc<'gc, T: GcSafe + 'gc>: GcContext + 'gc {
fn alloc(&'gc self, value: T) -> Gc<'gc, T, Self::Id>;
}
#[doc(hidden)]
#[must_use]
pub struct FrozenContext<C: GcContext> {
context: C,
}
impl<C: GcContext> FrozenContext<C> {
#[doc(hidden)]
#[inline]
pub unsafe fn new(context: C) -> Self {
FrozenContext { context }
}
#[doc(hidden)]
#[inline]
pub unsafe fn into_context(self) -> C {
self.context
}
}
pub unsafe trait CollectorId: Copy + Eq + Debug + NullTrace + 'static {
type System: GcSystem<Id=Self>;
unsafe fn gc_write_barrier<'gc, T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc>(
owner: &Gc<'gc, T, Self>,
value: &Gc<'gc, V, Self>,
field_offset: usize
);
unsafe fn assume_valid_system(&self) -> &Self::System;
}
#[repr(C)]
pub struct Gc<'gc, T: GcSafe + ?Sized + 'gc, Id: CollectorId> {
value: NonNull<T>,
collector_id: Id,
marker: PhantomData<&'gc T>,
}
impl<'gc, T: GcSafe + ?Sized + 'gc, Id: CollectorId> Gc<'gc, T, Id> {
#[inline(always)]
pub unsafe fn from_raw(id: Id, value: NonNull<T>) -> Self {
Gc { collector_id: id, value, marker: PhantomData }
}
#[inline(always)]
pub fn value(&self) -> &'gc T {
unsafe { *(&self.value as *const NonNull<T> as *const &'gc T) }
}
#[inline]
pub unsafe fn as_raw_ptr(&self) -> *mut T {
self.value.as_ptr() as *const T as *mut T
}
#[inline]
pub fn create_handle(&self) -> <Id::System as GcHandleSystem<'gc, T>>::Handle
where Id::System: GcHandleSystem<'gc, T>,
T: GcBrand<'static, Id>,
<T as GcBrand<'static, Id>>::Branded: GcSafe {
<Id::System as GcHandleSystem<'gc, T>>::create_handle(*self)
}
#[inline]
pub fn system(&self) -> &'_ Id::System {
unsafe { self.collector_id.assume_valid_system() }
}
#[inline]
pub fn collector_id(&self) -> Id {
self.collector_id
}
}
unsafe impl<'gc, T: GcSafe + 'gc, Id: CollectorId> GcSafe for Gc<'gc, T, Id> {
const NEEDS_DROP: bool = true; }
unsafe impl<'gc, 'new_gc, T, Id> GcBrand<'new_gc, Id> for Gc<'gc, T, Id>
where T: GcSafe + GcBrand<'new_gc, Id>,
T::Branded: GcSafe, Id: CollectorId {
type Branded = Gc<'new_gc, <T as GcBrand<'new_gc, Id>>::Branded, Id>;
}
unsafe impl<'gc, T: GcSafe + 'gc, Id: CollectorId> Trace for Gc<'gc, T, Id> {
const NEEDS_TRACE: bool = true;
#[inline]
fn visit<V: GcVisitor>(&mut self, visitor: &mut V) -> Result<(), V::Err> {
unsafe {
V::visit_gc(visitor, self)
}
}
}
impl<'gc, T: GcSafe + 'gc, Id: CollectorId> Deref for Gc<'gc, T, Id> {
type Target = &'gc T;
#[inline(always)]
fn deref(&self) -> &Self::Target {
unsafe { &*(&self.value as *const NonNull<T> as *const &'gc T) }
}
}
unsafe impl<'gc, O, V, Id> GcDirectBarrier<'gc, Gc<'gc, O, Id>> for Gc<'gc, V,Id>
where O: GcSafe + 'gc, V: GcSafe + 'gc, Id: CollectorId {
#[inline(always)]
unsafe fn write_barrier(&self, owner: &Gc<'gc, O, Id>, field_offset: usize) {
Id::gc_write_barrier(owner, self, field_offset)
}
}
impl<'gc, T: GcSafe + ?Sized + 'gc, Id: CollectorId> Copy for Gc<'gc, T, Id> {}
impl<'gc, T: GcSafe + ?Sized + 'gc, Id: CollectorId> Clone for Gc<'gc, T, Id> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<'gc, T: GcSafe + Hash + 'gc, Id: CollectorId> Hash for Gc<'gc, T, Id> {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.value().hash(state)
}
}
impl<'gc, T: GcSafe + PartialEq + 'gc, Id: CollectorId> PartialEq for Gc<'gc, T, Id> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.value() == other.value()
}
}
impl<'gc, T: GcSafe + Eq + 'gc, Id: CollectorId> Eq for Gc<'gc, T, Id> {}
impl<'gc, T: GcSafe + PartialEq + 'gc, Id: CollectorId> PartialEq<T> for Gc<'gc, T, Id> {
#[inline]
fn eq(&self, other: &T) -> bool {
self.value() == other
}
}
impl<'gc, T: GcSafe + Debug + 'gc, Id: CollectorId> Debug for Gc<'gc, T, Id> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if !f.alternate() {
f.debug_tuple("Gc").field(self.value()).finish()
} else {
f.debug_struct("Gc")
.field("collector_id", &self.collector_id)
.field("value", self.value())
.finish()
}
}
}
unsafe impl<'gc, T, Id> Send for Gc<'gc, T, Id>
where T: GcSafe + ?Sized + Sync, Id: CollectorId + Sync {}
unsafe impl<'gc, T, Id> Sync for Gc<'gc, T, Id>
where T: GcSafe + ?Sized + Sync, Id: CollectorId + Sync {}
pub unsafe trait GcHandle<T: GcSafe + ?Sized>: Clone + NullTrace {
type System: GcSystem<Id=Self::Id>;
type Id: CollectorId;
fn use_critical<R>(&self, func: impl FnOnce(&T) -> R) -> R;
}
pub unsafe trait GcBindHandle<'new_gc, T: GcSafe + ?Sized>: GcHandle<T>
where T: GcBrand<'new_gc, Self::Id>,
<T as GcBrand<'new_gc, Self::Id>>::Branded: GcSafe {
fn bind_to(&self, context: &'new_gc <Self::System as GcSystem>::Context) -> Gc<
'new_gc,
<T as GcBrand<'new_gc, Self::Id>>::Branded,
Self::Id
>;
}
pub unsafe trait GcDirectBarrier<'gc, OwningRef>: Trace {
unsafe fn write_barrier(&self, owner: &OwningRef, field_offset: usize);
}
pub unsafe trait GcSafe: Trace {
const NEEDS_DROP: bool;
#[doc(hidden)]
fn assert_gc_safe() {}
}
#[doc(hidden)]
pub fn assert_copy<T: Copy>() {}
#[repr(transparent)]
#[derive(Copy, Clone, Debug)]
pub struct AssumeNotTraced<T>(T);
impl<T> AssumeNotTraced<T> {
#[inline]
pub unsafe fn new(value: T) -> Self {
AssumeNotTraced(value)
}
#[inline]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T> Deref for AssumeNotTraced<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for AssumeNotTraced<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
unsafe impl<T> Trace for AssumeNotTraced<T> {
const NEEDS_TRACE: bool = false;
#[inline(always)] fn visit<V: GcVisitor>(&mut self, _visitor: &mut V) -> Result<(), V::Err> {
Ok(())
}
}
unsafe impl<T> TraceImmutable for AssumeNotTraced<T> {
#[inline(always)]
fn visit_immutable<V: GcVisitor>(&self, _visitor: &mut V) -> Result<(), V::Err> {
Ok(())
}
}
unsafe impl<T> NullTrace for AssumeNotTraced<T> {}
unsafe impl<T> GcSafe for AssumeNotTraced<T> {
const NEEDS_DROP: bool = core::mem::needs_drop::<T>();
}
unsafe_gc_brand!(AssumeNotTraced, T);
pub unsafe trait GcBrand<'new_gc, Id: CollectorId>: Trace {
type Branded: Trace + 'new_gc;
}
pub unsafe trait Trace {
const NEEDS_TRACE: bool;
fn visit<V: GcVisitor>(&mut self, visitor: &mut V) -> Result<(), V::Err>;
}
pub unsafe trait TraceImmutable: Trace {
fn visit_immutable<V: GcVisitor>(&self, visitor: &mut V) -> Result<(), V::Err>;
}
pub unsafe trait NullTrace: Trace + TraceImmutable {}
pub unsafe trait GcVisitor: Sized {
type Err: Debug;
#[inline(always)]
fn visit<T: Trace + ?Sized>(&mut self, value: &mut T) -> Result<(), Self::Err> {
value.visit(self)
}
#[inline(always)]
fn visit_immutable<T: TraceImmutable + ?Sized>(&mut self, value: &T) -> Result<(), Self::Err> {
value.visit_immutable(self)
}
unsafe fn visit_gc<'gc, T: GcSafe + 'gc, Id: CollectorId>(
&mut self, gc: &mut Gc<'gc, T, Id>
) -> Result<(), Self::Err>;
}