From 21ca9b89e8924f8f6169a8b1321a10649094d2ac Mon Sep 17 00:00:00 2001 From: Jake Hughes Date: Thu, 8 Apr 2021 14:23:03 +0100 Subject: [PATCH] Remove requirement that `T: Sync` This was included originally because of concerns about finalizing a non-Sync `T` value off-thread. If a value is `Sync`, it means that it is safe for two threads to access its data simultaneuosly: in other words, it has some synchronization guarantees. A common example is `RefCell`, which is safe to send between threads, but is marked `!Sync` because the dynamic borrow checking is not atomic. Finalizing `!Sync` values no longer problematic, because even though finalizers are run off-thread, they will run when the object is dead [1], so there is no chance of a data race. [1]: https://github.com/softdevteam/rustgc/pull/30 --- src/gc.rs | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/gc.rs b/src/gc.rs index 68331eb..20867cd 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -39,18 +39,15 @@ 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`. #[derive(PartialEq, Eq)] -pub struct Gc { +pub struct Gc { ptr: NonNull>, _phantom: PhantomData, } -impl + Send + Sync, U: ?Sized + Send + Sync> CoerceUnsized> for Gc {} -impl + Send + Sync, U: ?Sized + Send + Sync> DispatchFromDyn> - for Gc -{ -} +impl + Send, U: ?Sized + Send> CoerceUnsized> for Gc {} +impl + Send, U: ?Sized + Send> DispatchFromDyn> for Gc {} -impl Gc { +impl Gc { /// Constructs a new `Gc`. pub fn new(v: T) -> Self { Gc { @@ -104,8 +101,8 @@ impl Gc { } } -impl Gc { - pub fn downcast(&self) -> Result, Gc> { +impl Gc { + pub fn downcast(&self) -> Result, Gc> { if (*self).is::() { let ptr = self.ptr.cast::>(); Ok(Gc::from_inner(ptr)) @@ -125,7 +122,7 @@ pub fn needs_finalizer() -> bool { std::mem::needs_finalizer::() } -impl Gc { +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 @@ -159,7 +156,7 @@ impl Gc { } } -impl Gc> { +impl Gc> { /// As with `MaybeUninit::assume_init`, it is up to the caller to guarantee /// that the inner value really is in an initialized state. Calling this /// when the content is not yet fully initialized causes immediate undefined @@ -170,19 +167,19 @@ impl Gc> { } } -impl fmt::Display for Gc { +impl fmt::Display for Gc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(&**self, f) } } -impl fmt::Debug for Gc { +impl fmt::Debug for Gc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -impl fmt::Pointer for Gc { +impl fmt::Pointer for Gc { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Pointer::fmt(&(&**self as *const T), f) } @@ -254,7 +251,7 @@ impl GcBox> { } } -impl Deref for Gc { +impl Deref for Gc { type Target = T; fn deref(&self) -> &Self::Target { @@ -265,15 +262,15 @@ impl Deref for Gc { /// `Copy` and `Clone` are implemented manually because a reference to `Gc` /// should be copyable regardless of `T`. It differs subtly from `#[derive(Copy, /// Clone)]` in that the latter only makes `Gc` copyable if `T` is. -impl Copy for Gc {} +impl Copy for Gc {} -impl Clone for Gc { +impl Clone for Gc { fn clone(&self) -> Self { *self } } -impl Hash for Gc { +impl Hash for Gc { fn hash(&self, state: &mut H) { (**self).hash(state); } @@ -308,15 +305,15 @@ mod test { struct S2 { y: u64, } - trait T: Send + Sync { + trait T: Send { fn f(self: Gc) -> u64 where - Self: Send + Sync; + Self: Send; } impl T for S1 { fn f(self: Gc) -> u64 where - Self: Send + Sync, + Self: Send, { self.x } @@ -324,7 +321,7 @@ mod test { impl T for S2 { fn f(self: Gc) -> u64 where - Self: Send + Sync, + Self: Send, { self.y }