diff --git a/src/gc.rs b/src/gc.rs index 20867cd..70dca9c 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -38,20 +38,39 @@ pub fn gc_init() { /// /// `Gc` automatically dereferences to `T` (via the `Deref` trait), so /// you can call `T`'s methods on a value of type `Gc`. +/// +/// `Gc` will implement `Sync` as long as `T` implements `Sync`. `Gc` +/// will always implement `Send` because it requires `T` to implement `Send`. +/// This is because if `T` has a finalizer, it will be run on a seperate thread. #[derive(PartialEq, Eq)] pub struct Gc { - ptr: NonNull>, + ptr: GcPointer, _phantom: PhantomData, } +/// This zero-sized wrapper struct is needed to allow `Gc` to have the same +/// `Send` + `Sync` semantics as `T`. Without it, the inner `NonNull` type would +/// mean that a `Gc` never implements `Send` or `Sync`. +#[derive(PartialEq, Eq)] +struct GcPointer(NonNull>); + +unsafe impl Send for GcPointer {} +unsafe impl Sync for GcPointer {} + impl + Send, U: ?Sized + Send> CoerceUnsized> for Gc {} impl + Send, U: ?Sized + Send> DispatchFromDyn> for Gc {} +impl + Send, U: ?Sized + Send> CoerceUnsized> for GcPointer {} +impl + Send, U: ?Sized + Send> DispatchFromDyn> + for GcPointer +{ +} + impl Gc { /// Constructs a new `Gc`. pub fn new(v: T) -> Self { Gc { - ptr: unsafe { NonNull::new_unchecked(GcBox::new(v)) }, + ptr: unsafe { GcPointer(NonNull::new_unchecked(GcBox::new(v))) }, _phantom: PhantomData, } } @@ -94,7 +113,7 @@ impl Gc { } pub fn unregister_finalizer(&mut self) { - let ptr = self.ptr.as_ptr() as *mut GcBox; + let ptr = self.ptr.0.as_ptr() as *mut GcBox; unsafe { GcBox::unregister_finalizer(&mut *ptr); } @@ -104,10 +123,10 @@ impl Gc { impl Gc { pub fn downcast(&self) -> Result, Gc> { if (*self).is::() { - let ptr = self.ptr.cast::>(); + let ptr = self.ptr.0.cast::>(); Ok(Gc::from_inner(ptr)) } else { - Err(Gc::from_inner(self.ptr)) + Err(Gc::from_inner(self.ptr.0)) } } } @@ -125,11 +144,11 @@ pub fn needs_finalizer() -> bool { impl Gc { /// Get a raw pointer to the underlying value `T`. pub fn into_raw(this: Self) -> *const T { - this.ptr.as_ptr() as *const T + this.ptr.0.as_ptr() as *const T } pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() + this.ptr.0.as_ptr() == other.ptr.0.as_ptr() } /// Get a `Gc` from a raw pointer. @@ -143,14 +162,14 @@ impl Gc { /// size and alignment of the originally allocated block. pub fn from_raw(raw: *const T) -> Gc { Gc { - ptr: unsafe { NonNull::new_unchecked(raw as *mut GcBox) }, + ptr: unsafe { GcPointer(NonNull::new_unchecked(raw as *mut GcBox)) }, _phantom: PhantomData, } } fn from_inner(ptr: NonNull>) -> Self { Self { - ptr, + ptr: GcPointer(ptr), _phantom: PhantomData, } } @@ -162,7 +181,7 @@ impl Gc> { /// when the content is not yet fully initialized causes immediate undefined /// behaviour. pub unsafe fn assume_init(self) -> Gc { - let ptr = self.ptr.as_ptr() as *mut GcBox>; + let ptr = self.ptr.0.as_ptr() as *mut GcBox>; Gc::from_inner((&mut *ptr).assume_init()) } } @@ -255,7 +274,7 @@ impl Deref for Gc { type Target = T; fn deref(&self) -> &Self::Target { - unsafe { &*(self.ptr.as_ptr() as *const T) } + unsafe { &*(self.ptr.0.as_ptr() as *const T) } } } @@ -270,6 +289,13 @@ impl Clone for Gc { } } +impl Copy for GcPointer {} + +impl Clone for GcPointer { + fn clone(&self) -> Self { + *self + } +} impl Hash for Gc { fn hash(&self, state: &mut H) { (**self).hash(state);