diff --git a/oscars/src/alloc/arena2/alloc.rs b/oscars/src/alloc/arena2/alloc.rs index f1a2c86..ec22503 100644 --- a/oscars/src/alloc/arena2/alloc.rs +++ b/oscars/src/alloc/arena2/alloc.rs @@ -48,6 +48,7 @@ impl ArenaHeapItem { /// /// This avoids creating a `&mut self` reference, which can lead to stacked borrows /// if shared references to the heap item exist + #[allow(dead_code)] pub(crate) fn as_value_ptr(ptr: NonNull) -> *mut T { // SAFETY: `&raw mut` computes the field address without creating a reference unsafe { &raw mut (*ptr.as_ptr()).value } @@ -147,6 +148,7 @@ impl<'arena> ErasedArenaPointer<'arena> { /// SAFETY: /// /// safe because the gc collector owns the arena and keeps it alive + #[allow(dead_code)] pub(crate) unsafe fn extend_lifetime(self) -> ErasedArenaPointer<'static> { ErasedArenaPointer(self.0, PhantomData) } @@ -202,6 +204,7 @@ impl<'arena, T> ArenaPointer<'arena, T> { /// SAFETY: /// /// safe because the gc collector owns the arena and keeps it alive + #[allow(dead_code)] pub(crate) unsafe fn extend_lifetime(self) -> ArenaPointer<'static, T> { // SAFETY: upheld by caller ArenaPointer(unsafe { self.0.extend_lifetime() }, PhantomData) diff --git a/oscars/src/alloc/mempool3/alloc.rs b/oscars/src/alloc/mempool3/alloc.rs index 64e5ba3..813440f 100644 --- a/oscars/src/alloc/mempool3/alloc.rs +++ b/oscars/src/alloc/mempool3/alloc.rs @@ -107,7 +107,7 @@ impl<'pool, T: ?Sized> PoolPointer<'pool, T> { } } -impl<'pool, T> PoolPointer<'pool, T> { +impl<'pool, T: ?Sized> PoolPointer<'pool, T> { pub(crate) unsafe fn from_raw(raw: NonNull>) -> Self { Self(raw, PhantomData) } diff --git a/oscars/src/collectors/mark_sweep_branded/gc.rs b/oscars/src/collectors/mark_sweep_branded/gc.rs index 073e706..e220515 100644 --- a/oscars/src/collectors/mark_sweep_branded/gc.rs +++ b/oscars/src/collectors/mark_sweep_branded/gc.rs @@ -60,7 +60,7 @@ impl<'gc, T: Trace + 'gc> Deref for Gc<'gc, T> { } } -impl Finalize for Gc<'_, T> {} +impl Finalize for Gc<'_, T> {} unsafe impl Trace for Gc<'_, T> { unsafe fn trace(&self, tracer: &mut crate::collectors::mark_sweep_branded::trace::Tracer) { tracer.mark(self); diff --git a/oscars/src/collectors/null_collector_branded/cell.rs b/oscars/src/collectors/null_collector_branded/cell.rs index cdedb43..ca36252 100644 --- a/oscars/src/collectors/null_collector_branded/cell.rs +++ b/oscars/src/collectors/null_collector_branded/cell.rs @@ -3,7 +3,7 @@ use core::cell::{Ref, RefCell, RefMut}; use core::ops::{Deref, DerefMut}; /// GC aware wrapper around [`RefCell`] -pub struct GcRefCell { +pub struct GcRefCell { inner: RefCell, } @@ -13,7 +13,9 @@ impl GcRefCell { inner: RefCell::new(value), } } +} +impl GcRefCell { /// Acquires a shared borrow of the inner value. /// /// # Panics @@ -31,37 +33,104 @@ impl GcRefCell { pub fn borrow_mut(&self) -> GcRefMut<'_, T> { GcRefMut(self.inner.borrow_mut()) } + + pub fn try_borrow(&self) -> Result, core::cell::BorrowError> { + self.inner.try_borrow().map(GcRef) + } + + pub fn try_borrow_mut(&self) -> Result, core::cell::BorrowMutError> { + self.inner.try_borrow_mut().map(GcRefMut) + } } /// Shared borrow guard returned by [`GcRefCell::borrow`] -pub struct GcRef<'a, T: Trace>(Ref<'a, T>); +pub struct GcRef<'a, T: Trace + ?Sized>(Ref<'a, T>); -impl Deref for GcRef<'_, T> { +impl Deref for GcRef<'_, T> { type Target = T; - fn deref(&self) -> &T { + #[inline] + fn deref(&self) -> &Self::Target { &self.0 } } /// A mutable borrow guard returned by [`GcRefCell::borrow_mut`] -pub struct GcRefMut<'a, T: Trace>(RefMut<'a, T>); +pub struct GcRefMut<'a, T: Trace + ?Sized>(RefMut<'a, T>); -impl Deref for GcRefMut<'_, T> { +impl Deref for GcRefMut<'_, T> { type Target = T; - fn deref(&self) -> &T { + #[inline] + fn deref(&self) -> &Self::Target { &self.0 } } -impl DerefMut for GcRefMut<'_, T> { - fn deref_mut(&mut self) -> &mut T { +impl DerefMut for GcRefMut<'_, T> { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } -impl Finalize for GcRefCell {} +impl<'a, T: Trace + ?Sized> GcRef<'a, T> { + pub fn clone(orig: &GcRef<'a, T>) -> GcRef<'a, T> { + GcRef(Ref::clone(&orig.0)) + } + pub fn map(orig: GcRef<'a, T>, f: F) -> GcRef<'a, U> + where + F: FnOnce(&T) -> &U, + { + GcRef(Ref::map(orig.0, f)) + } + pub fn try_map(orig: GcRef<'a, T>, f: F) -> Option> + where + F: FnOnce(&T) -> Option<&U>, + { + Ref::filter_map(orig.0, f).ok().map(GcRef) + } + /// Casts a `GcRef` to a `GcRef` without type checking. + /// + /// # Safety + /// + /// `T` and `U` must be pointer-compatible. The underlying value must be + /// a valid `U`. + pub unsafe fn cast(orig: GcRef<'a, T>) -> GcRef<'a, U> { + GcRef(Ref::map(orig.0, |t| unsafe { + &*((t as *const T).cast::()) + })) + } +} + +impl<'a, T: Trace + ?Sized> GcRefMut<'a, T> { + pub fn map(orig: GcRefMut<'a, T>, f: F) -> GcRefMut<'a, U> + where + F: FnOnce(&mut T) -> &mut U, + { + GcRefMut(RefMut::map(orig.0, f)) + } + pub fn try_map(orig: GcRefMut<'a, T>, f: F) -> Option> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + RefMut::filter_map(orig.0, f).ok().map(GcRefMut) + } + /// Casts a `GcRefMut` to a `GcRefMut` without type checking. + /// + /// # Safety + /// + /// `T` and `U` must be pointer compatible, the underlying value must be + /// a valid `U` + pub unsafe fn cast(orig: GcRefMut<'a, T>) -> GcRefMut<'a, U> { + GcRefMut(RefMut::map(orig.0, |t| unsafe { + &mut *((t as *mut T).cast::()) + })) + } +} -unsafe impl Trace for GcRefCell { +impl Finalize for GcRefCell {} + +unsafe impl Trace for GcRefCell { + #[inline] unsafe fn trace(&self, tracer: &mut Tracer) { // SAFETY: We only access the inner value for tracing and do not mutate it. // The null collector's trace is a no-op, so this is safe. @@ -71,3 +140,60 @@ unsafe impl Trace for GcRefCell { } } } + +impl Default for GcRefCell { + #[inline] + fn default() -> Self { + Self::new(T::default()) + } +} + +impl core::fmt::Debug for GcRefCell { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self.inner.try_borrow() { + Ok(borrow) => f.debug_tuple("GcRefCell").field(&*borrow).finish(), + Err(_) => { + struct BorrowedPlaceholder; + impl core::fmt::Debug for BorrowedPlaceholder { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("") + } + } + f.debug_tuple("GcRefCell") + .field(&BorrowedPlaceholder) + .finish() + } + } + } +} + +impl Clone for GcRefCell { + #[inline] + fn clone(&self) -> Self { + Self::new(self.inner.borrow().clone()) + } +} + +impl<'a, T: Trace + core::fmt::Debug + ?Sized> core::fmt::Debug for GcRef<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, T: Trace + core::fmt::Display + ?Sized> core::fmt::Display for GcRef<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Display::fmt(&**self, f) + } +} + +impl<'a, T: Trace + core::fmt::Debug + ?Sized> core::fmt::Debug for GcRefMut<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Debug::fmt(&**self, f) + } +} + +impl<'a, T: Trace + core::fmt::Display + ?Sized> core::fmt::Display for GcRefMut<'a, T> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + core::fmt::Display::fmt(&**self, f) + } +} diff --git a/oscars/src/collectors/null_collector_branded/gc.rs b/oscars/src/collectors/null_collector_branded/gc.rs index 37d5cd4..32ec3c2 100644 --- a/oscars/src/collectors/null_collector_branded/gc.rs +++ b/oscars/src/collectors/null_collector_branded/gc.rs @@ -36,11 +36,10 @@ impl<'gc, T: Trace + ?Sized + 'gc> Gc<'gc, T> { } impl<'gc, T: Trace + ?Sized + 'gc> Gc<'gc, T> { - /// Returns a shared reference to the value. + /// Gets a reference to the inner value. #[inline] pub fn get(&self) -> &T { - // SAFETY: `ptr` is non-null and valid for `'gc` by construction. - unsafe { &(*self.ptr.as_ptr().as_ptr()).0.value } + unsafe { &self.ptr.as_ptr().as_ref().0.value } } #[inline] @@ -57,12 +56,14 @@ impl<'gc, T: Trace + ?Sized + fmt::Display + 'gc> fmt::Display for Gc<'gc, T> { impl<'gc, T: Trace + ?Sized + 'gc> Deref for Gc<'gc, T> { type Target = T; + #[inline] fn deref(&self) -> &T { self.get() } } impl Finalize for Gc<'_, T> {} + unsafe impl Trace for Gc<'_, T> { unsafe fn trace(&self, tracer: &mut crate::collectors::null_collector_branded::trace::Tracer) { tracer.mark(self); diff --git a/oscars/src/collectors/null_collector_branded/gc_box.rs b/oscars/src/collectors/null_collector_branded/gc_box.rs index 97f806e..2514b95 100644 --- a/oscars/src/collectors/null_collector_branded/gc_box.rs +++ b/oscars/src/collectors/null_collector_branded/gc_box.rs @@ -2,14 +2,16 @@ use core::ptr::NonNull; use crate::alloc::mempool3::PoolAllocator; -pub(crate) type DropFn = unsafe fn(&mut PoolAllocator<'static>, NonNull); +pub type DropFn = unsafe fn(&mut PoolAllocator<'static>, NonNull); /// Heap wrapper for a garbage collected value. /// /// Allocated via [`PoolAllocator`] -pub(crate) struct GcBox { +pub struct GcBox { /// Type erased finalize and free fn pub(crate) drop_fn: DropFn, + /// Type name of the underlying value + pub(crate) type_name: &'static str, /// User value pub(crate) value: T, } @@ -17,6 +19,10 @@ pub(crate) struct GcBox { impl GcBox { /// Create a [`GcBox`] for `value` pub(crate) fn new(value: T, drop_fn: DropFn) -> Self { - Self { drop_fn, value } + Self { + drop_fn, + type_name: core::any::type_name::(), + value, + } } }