use std::fmt::{self, Debug, Formatter};
use std::sync::Arc;
use std::ptr::NonNull;
use std::marker::PhantomData;
use slog::{Logger, o};
use zerogc::{Gc, GcSafe, GcSystem, Trace, GcSimpleAlloc, NullTrace, TraceImmutable, GcVisitor};
use crate::{CollectorContext};
use crate::state::{CollectionManager, RawContext};
pub unsafe trait RawCollectorImpl: 'static + Sized {
type GcDynPointer: Copy + Debug + 'static;
type Ptr: CollectorPtr<Self>;
type Manager: CollectionManager<Self, Context=Self::RawContext>;
type RawContext: RawContext<Self>;
const SINGLETON: bool;
const SYNC: bool;
unsafe fn create_dyn_pointer<T: Trace>(t: *mut T) -> Self::GcDynPointer;
fn init(logger: Logger) -> NonNull<Self>;
#[inline]
fn id(&self) -> CollectorId<Self> {
CollectorId { ptr: unsafe { Self::Ptr::from_raw(self as *const _ as *mut _) } }
}
unsafe fn gc_write_barrier<'gc, T, V>(
owner: &Gc<'gc, T, CollectorId<Self>>,
value: &Gc<'gc, V, CollectorId<Self>>,
field_offset: usize
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc;
fn logger(&self) -> &Logger;
fn manager(&self) -> &Self::Manager;
fn should_collect(&self) -> bool;
fn allocated_size(&self) -> crate::utils::MemorySize;
unsafe fn perform_raw_collection(&self, contexts: &[*mut Self::RawContext]);
}
pub unsafe trait SyncCollector: RawCollectorImpl + Sync {
}
pub unsafe trait SingletonCollector: RawCollectorImpl<Ptr=PhantomData<&'static Self>> {
fn global_ptr() -> *const Self;
fn init_global(logger: Logger);
}
impl<C: RawCollectorImpl> PartialEq for CollectorId<C> {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.ptr == other.ptr
}
}
impl<C: RawCollectorImpl> Eq for CollectorId<C> {}
impl<C: RawCollectorImpl> Clone for CollectorId<C> {
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<C: RawCollectorImpl> Copy for CollectorId<C> {}
impl<C: RawCollectorImpl> Debug for CollectorId<C> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut debug = f.debug_struct("CollectorId");
if !C::SINGLETON {
debug.field("ptr", &format_args!("{:p}", self.ptr.as_ptr()));
}
debug.finish()
}
}
pub unsafe trait CollectorPtr<C: RawCollectorImpl<Ptr=Self>>: Copy + Eq
+ self::sealed::Sealed + 'static {
type Weak: Clone + 'static;
unsafe fn from_raw(ptr: *mut C) -> Self;
unsafe fn clone_owned(&self) -> Self;
fn as_ptr(&self) -> *mut C;
unsafe fn drop(self);
fn upgrade_weak_raw(weak: &Self::Weak) -> Option<Self>;
#[inline]
fn upgrade_weak(weak: &Self::Weak) -> Option<CollectorRef<C>> {
match Self::upgrade_weak_raw(weak) {
Some(ptr) => Some(CollectorRef { ptr }),
None => None
}
}
unsafe fn assume_weak_valid(weak: &Self::Weak) -> Self;
unsafe fn create_weak(&self) -> Self::Weak;
}
unsafe impl<C: RawCollectorImpl<Ptr=Self>> CollectorPtr<C> for NonNull<C> {
type Weak = std::sync::Weak<C>;
#[inline]
unsafe fn from_raw(ptr: *mut C) -> Self {
assert!(!C::SINGLETON, "Collector is a singleton!");
debug_assert!(!ptr.is_null());
NonNull::new_unchecked(ptr)
}
#[inline]
unsafe fn clone_owned(&self) -> Self {
let original = Arc::from_raw(self.as_ptr());
let cloned = Arc::clone(&original);
std::mem::forget(original);
NonNull::new_unchecked(Arc::into_raw(cloned) as *mut _)
}
#[inline]
fn as_ptr(&self) -> *mut C {
NonNull::as_ptr(*self)
}
#[inline]
unsafe fn drop(self) {
drop(Arc::from_raw(self.as_ptr() as *const _))
}
#[inline]
fn upgrade_weak_raw(weak: &Self::Weak) -> Option<Self> {
match weak.upgrade() {
Some(arc) => {
Some(unsafe {
Self::from_raw(Arc::into_raw(arc) as *mut _)
})
},
None => None
}
}
#[inline]
unsafe fn assume_weak_valid(weak: &Self::Weak) -> Self {
debug_assert!(
weak.upgrade().is_some(),
"Dead collector"
);
NonNull::new_unchecked(weak.as_ptr() as *mut _)
}
#[inline]
unsafe fn create_weak(&self) -> Self::Weak {
let arc = Arc::from_raw(self.as_ptr());
let weak = Arc::downgrade(&arc);
std::mem::forget(arc);
weak
}
}
impl<C: RawCollectorImpl> self::sealed::Sealed for NonNull<C> {}
unsafe impl<C: SingletonCollector<Ptr=Self>> CollectorPtr<C> for PhantomData<&'static C> {
type Weak = PhantomData<&'static C>;
#[inline]
unsafe fn from_raw(ptr: *mut C) -> Self {
assert!(C::SINGLETON, "Expected a singleton");
debug_assert_eq!(ptr, C::global_ptr() as *mut _);
PhantomData
}
#[inline]
unsafe fn clone_owned(&self) -> Self {
*self
}
#[inline]
fn as_ptr(&self) -> *mut C {
assert!(C::SINGLETON, "Expected a singleton");
C::global_ptr() as *mut C
}
#[inline]
unsafe fn drop(self) {}
#[inline]
fn upgrade_weak_raw(weak: &Self::Weak) -> Option<Self> {
assert!(C::SINGLETON);
Some(*weak) }
#[inline]
unsafe fn assume_weak_valid(weak: &Self::Weak) -> Self {
assert!(C::SINGLETON); *weak
}
#[inline]
unsafe fn create_weak(&self) -> Self::Weak {
*self
}
}
impl<C: SingletonCollector> self::sealed::Sealed for PhantomData<&'static C> {}
#[repr(C)]
pub struct CollectorId<C: RawCollectorImpl> {
ptr: C::Ptr,
}
impl<C: RawCollectorImpl> CollectorId<C> {
#[inline]
pub const unsafe fn from_raw(ptr: C::Ptr) -> CollectorId<C> {
CollectorId { ptr }
}
#[inline]
pub unsafe fn as_ref(&self) -> &C {
&*self.ptr.as_ptr()
}
#[inline]
pub unsafe fn weak_ref(&self) -> WeakCollectorRef<C> {
WeakCollectorRef { weak: self.ptr.create_weak() }
}
}
unsafe impl<C: RawCollectorImpl> ::zerogc::CollectorId for CollectorId<C> {
type System = CollectorRef<C>;
#[inline(always)]
unsafe fn gc_write_barrier<'gc, T, V>(
owner: &Gc<'gc, T, Self>,
value: &Gc<'gc, V, Self>,
field_offset: usize
) where T: GcSafe + ?Sized + 'gc, V: GcSafe + ?Sized + 'gc {
C::gc_write_barrier(owner, value, field_offset)
}
#[inline]
unsafe fn assume_valid_system(&self) -> &Self::System {
assert_eq!(
std::mem::size_of::<Self>(),
std::mem::size_of::<CollectorRef<C>>()
);
&*(self as *const CollectorId<C> as *const CollectorRef<C>)
}
}
unsafe impl<C: RawCollectorImpl> Trace for CollectorId<C> {
const NEEDS_TRACE: bool = false;
#[inline(always)]
fn visit<V: GcVisitor>(&mut self, _visitor: &mut V) -> Result<(), V::Err> {
Ok(())
}
}
unsafe impl<C: RawCollectorImpl> TraceImmutable for CollectorId<C> {
#[inline(always)]
fn visit_immutable<V: GcVisitor>(&self, _visitor: &mut V) -> Result<(), <V as GcVisitor>::Err> {
Ok(())
}
}
unsafe impl<C: RawCollectorImpl> NullTrace for CollectorId<C> {}
pub struct WeakCollectorRef<C: RawCollectorImpl> {
weak: <C::Ptr as CollectorPtr<C>>::Weak,
}
impl<C: RawCollectorImpl> WeakCollectorRef<C> {
#[inline]
pub unsafe fn assume_valid(&self) -> CollectorId<C> {
CollectorId { ptr: C::Ptr::assume_weak_valid(&self.weak) }
}
pub fn ensure_valid<R>(&self, func: impl FnOnce(CollectorId<C>) -> R) -> R {
self.try_ensure_valid(|id| match id{
Some(id) => func(id),
None => panic!("Dead collector")
})
}
#[inline]
pub fn try_ensure_valid<R>(&self, func: impl FnOnce(Option<CollectorId<C>>) -> R) -> R{
func(C::Ptr::upgrade_weak(&self.weak).map(|r| r.id()))
}
}
pub unsafe trait RawSimpleAlloc: RawCollectorImpl {
fn alloc<'gc, T: GcSafe + 'gc>(context: &'gc CollectorContext<Self>, value: T) -> Gc<'gc, T, CollectorId<Self>>;
}
unsafe impl<'gc, T, C> GcSimpleAlloc<'gc, T> for CollectorContext<C>
where T: GcSafe + 'gc, C: RawSimpleAlloc {
#[inline]
fn alloc(&'gc self, value: T) -> Gc<'gc, T, Self::Id> {
C::alloc(self, value)
}
}
#[repr(C)]
pub struct CollectorRef<C: RawCollectorImpl> {
ptr: C::Ptr
}
unsafe impl<C: SyncCollector> Send for CollectorRef<C> {}
#[cfg(feature = "sync")]
unsafe impl<C: SyncCollector> Sync for CollectorRef<C> {}
#[doc(hidden)]
pub trait CollectorInit<C: RawCollectorImpl<Ptr=Self>>: CollectorPtr<C> {
fn create() -> CollectorRef<C> {
Self::with_logger(Logger::root(
slog::Discard,
o!()
))
}
fn with_logger(logger: Logger) -> CollectorRef<C>;
}
impl<C: RawCollectorImpl<Ptr=NonNull<C>>> CollectorInit<C> for NonNull<C> {
fn with_logger(logger: Logger) -> CollectorRef<C> {
assert!(!C::SINGLETON);
let raw_ptr = C::init(logger);
CollectorRef { ptr: raw_ptr }
}
}
impl<C> CollectorInit<C> for PhantomData<&'static C>
where C: SingletonCollector {
fn with_logger(logger: Logger) -> CollectorRef<C> {
assert!(C::SINGLETON);
C::init_global(logger); CollectorRef { ptr: PhantomData }
}
}
impl<C: RawCollectorImpl> CollectorRef<C> {
#[inline]
pub fn create() -> Self where C::Ptr: CollectorInit<C> {
<C::Ptr as CollectorInit<C>>::create()
}
#[inline]
pub fn with_logger(logger: Logger) -> Self where C::Ptr: CollectorInit<C> {
<C::Ptr as CollectorInit<C>>::with_logger(logger)
}
#[inline]
pub(crate) fn clone_internal(&self) -> CollectorRef<C> {
CollectorRef { ptr: unsafe { self.ptr.clone_owned() } }
}
#[inline]
pub fn as_raw(&self) -> &C {
unsafe { &*self.ptr.as_ptr() }
}
#[inline]
pub fn id(&self) -> CollectorId<C> {
CollectorId { ptr: self.ptr }
}
pub fn into_context(self) -> CollectorContext<C> {
unsafe { CollectorContext::register_root(&self) }
}
}
impl<C: SyncCollector> CollectorRef<C> {
pub fn create_context(&self) -> CollectorContext<C> {
unsafe { CollectorContext::register_root(&self) }
}
}
impl<C: RawCollectorImpl> Drop for CollectorRef<C> {
#[inline]
fn drop(&mut self) {
unsafe { self.ptr.drop(); }
}
}
unsafe impl<C: RawCollectorImpl> GcSystem for CollectorRef<C> {
type Id = CollectorId<C>;
type Context = CollectorContext<C>;
}
mod sealed {
pub trait Sealed {}
}