Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions oscars/src/alloc/arena2/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ impl<T: ?Sized> ArenaHeapItem<T> {
///
/// 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<Self>) -> *mut T {
// SAFETY: `&raw mut` computes the field address without creating a reference
unsafe { &raw mut (*ptr.as_ptr()).value }
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion oscars/src/alloc/mempool3/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PoolItem<T>>) -> Self {
Self(raw, PhantomData)
}
Expand Down
2 changes: 1 addition & 1 deletion oscars/src/collectors/mark_sweep_branded/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl<'gc, T: Trace + 'gc> Deref for Gc<'gc, T> {
}
}

impl<T: Trace> Finalize for Gc<'_, T> {}
impl<T: Trace + ?Sized> Finalize for Gc<'_, T> {}
unsafe impl<T: Trace> Trace for Gc<'_, T> {
unsafe fn trace(&self, tracer: &mut crate::collectors::mark_sweep_branded::trace::Tracer) {
tracer.mark(self);
Expand Down
148 changes: 137 additions & 11 deletions oscars/src/collectors/null_collector_branded/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use core::cell::{Ref, RefCell, RefMut};
use core::ops::{Deref, DerefMut};

/// GC aware wrapper around [`RefCell<T>`]
pub struct GcRefCell<T: Trace> {
pub struct GcRefCell<T: Trace + ?Sized> {
inner: RefCell<T>,
}

Expand All @@ -13,7 +13,9 @@ impl<T: Trace> GcRefCell<T> {
inner: RefCell::new(value),
}
}
}

impl<T: Trace + ?Sized> GcRefCell<T> {
/// Acquires a shared borrow of the inner value.
///
/// # Panics
Expand All @@ -31,37 +33,104 @@ impl<T: Trace> GcRefCell<T> {
pub fn borrow_mut(&self) -> GcRefMut<'_, T> {
GcRefMut(self.inner.borrow_mut())
}

pub fn try_borrow(&self) -> Result<GcRef<'_, T>, core::cell::BorrowError> {
self.inner.try_borrow().map(GcRef)
}

pub fn try_borrow_mut(&self) -> Result<GcRefMut<'_, T>, 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<T: Trace> Deref for GcRef<'_, T> {
impl<T: Trace + ?Sized> 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<T: Trace> Deref for GcRefMut<'_, T> {
impl<T: Trace + ?Sized> Deref for GcRefMut<'_, T> {
type Target = T;
fn deref(&self) -> &T {
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}

impl<T: Trace> DerefMut for GcRefMut<'_, T> {
fn deref_mut(&mut self) -> &mut T {
impl<T: Trace + ?Sized> DerefMut for GcRefMut<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}

impl<T: Trace> Finalize for GcRefCell<T> {}
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<U: Trace + ?Sized, F>(orig: GcRef<'a, T>, f: F) -> GcRef<'a, U>
where
F: FnOnce(&T) -> &U,
{
GcRef(Ref::map(orig.0, f))
}
pub fn try_map<U: Trace + ?Sized, F>(orig: GcRef<'a, T>, f: F) -> Option<GcRef<'a, U>>
where
F: FnOnce(&T) -> Option<&U>,
{
Ref::filter_map(orig.0, f).ok().map(GcRef)
}
/// Casts a `GcRef<T>` to a `GcRef<U>` without type checking.
///
/// # Safety
///
/// `T` and `U` must be pointer-compatible. The underlying value must be
/// a valid `U`.
pub unsafe fn cast<U: Trace>(orig: GcRef<'a, T>) -> GcRef<'a, U> {
GcRef(Ref::map(orig.0, |t| unsafe {
&*((t as *const T).cast::<U>())
}))
}
}

impl<'a, T: Trace + ?Sized> GcRefMut<'a, T> {
pub fn map<U: Trace + ?Sized, F>(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<U: Trace + ?Sized, F>(orig: GcRefMut<'a, T>, f: F) -> Option<GcRefMut<'a, U>>
where
F: FnOnce(&mut T) -> Option<&mut U>,
{
RefMut::filter_map(orig.0, f).ok().map(GcRefMut)
}
/// Casts a `GcRefMut<T>` to a `GcRefMut<U>` without type checking.
///
/// # Safety
///
/// `T` and `U` must be pointer compatible, the underlying value must be
/// a valid `U`
pub unsafe fn cast<U: Trace>(orig: GcRefMut<'a, T>) -> GcRefMut<'a, U> {
GcRefMut(RefMut::map(orig.0, |t| unsafe {
&mut *((t as *mut T).cast::<U>())
}))
}
}

unsafe impl<T: Trace> Trace for GcRefCell<T> {
impl<T: Trace + ?Sized> Finalize for GcRefCell<T> {}

unsafe impl<T: Trace + ?Sized> Trace for GcRefCell<T> {
#[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.
Expand All @@ -71,3 +140,60 @@ unsafe impl<T: Trace> Trace for GcRefCell<T> {
}
}
}

impl<T: Trace + Default> Default for GcRefCell<T> {
#[inline]
fn default() -> Self {
Self::new(T::default())
}
}

impl<T: Trace + core::fmt::Debug> core::fmt::Debug for GcRefCell<T> {
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("<borrowed>")
}
}
f.debug_tuple("GcRefCell")
.field(&BorrowedPlaceholder)
.finish()
}
}
}
}

impl<T: Trace + Clone> Clone for GcRefCell<T> {
#[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)
}
}
7 changes: 4 additions & 3 deletions oscars/src/collectors/null_collector_branded/gc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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<T: Trace + ?Sized> Finalize for Gc<'_, T> {}

unsafe impl<T: Trace + ?Sized> Trace for Gc<'_, T> {
unsafe fn trace(&self, tracer: &mut crate::collectors::null_collector_branded::trace::Tracer) {
tracer.mark(self);
Expand Down
12 changes: 9 additions & 3 deletions oscars/src/collectors/null_collector_branded/gc_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@ use core::ptr::NonNull;

use crate::alloc::mempool3::PoolAllocator;

pub(crate) type DropFn = unsafe fn(&mut PoolAllocator<'static>, NonNull<u8>);
pub type DropFn = unsafe fn(&mut PoolAllocator<'static>, NonNull<u8>);

/// Heap wrapper for a garbage collected value.
///
/// Allocated via [`PoolAllocator`]
pub(crate) struct GcBox<T: ?Sized> {
pub struct GcBox<T: ?Sized> {
/// 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,
}

impl<T> GcBox<T> {
/// 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::<T>(),
value,
}
}
}