From 252b58ac2ffae84c6e1962750c6dd55dafd57104 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Mon, 31 Aug 2020 07:35:09 +0200 Subject: [PATCH] Fix minor SharedPtr/SharedRef issues, and add unit tests * The `Default` trait did not actually get derived for `SharedPtr`. This is solved by implementing `Default` manually. * Trait function `Shared::get()` used to return a mutable raw pointer (`*mut Self`), but it would be inconceivable to ever mutate the referenced value. It was changed to return a const pointer instead. * Added some basic unit tests for types `SharedPtr` and `SharedRef`. --- src/array_buffer.rs | 4 +-- src/support.rs | 85 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 85 insertions(+), 4 deletions(-) diff --git a/src/array_buffer.rs b/src/array_buffer.rs index 1c106f1734..2d196930da 100644 --- a/src/array_buffer.rs +++ b/src/array_buffer.rs @@ -113,7 +113,7 @@ impl Shared for Allocator { ) } } - fn get(ptr: &SharedPtrBase) -> *mut Self { + fn get(ptr: &SharedPtrBase) -> *const Self { unsafe { std__shared_ptr__v8__ArrayBuffer__Allocator__get(ptr) } } fn reset(ptr: &mut SharedPtrBase) { @@ -219,7 +219,7 @@ impl Shared for BackingStore { std__shared_ptr__v8__BackingStore__CONVERT__std__unique_ptr(unique_ptr) } } - fn get(ptr: &SharedPtrBase) -> *mut Self { + fn get(ptr: &SharedPtrBase) -> *const Self { unsafe { std__shared_ptr__v8__BackingStore__get(ptr) } } fn reset(ptr: &mut SharedPtrBase) { diff --git a/src/support.rs b/src/support.rs index 856fef539f..1941516238 100644 --- a/src/support.rs +++ b/src/support.rs @@ -178,7 +178,7 @@ where { fn clone(shared_ptr: &SharedPtrBase) -> SharedPtrBase; fn from_unique_ptr(unique_ptr: UniquePtr) -> SharedPtrBase; - fn get(shared_ptr: &SharedPtrBase) -> *mut Self; + fn get(shared_ptr: &SharedPtrBase) -> *const Self; fn reset(shared_ptr: &mut SharedPtrBase); fn use_count(shared_ptr: &SharedPtrBase) -> long; } @@ -186,6 +186,7 @@ where /// Private base type which is shared by the `SharedPtr` and `SharedRef` /// implementations. #[repr(C)] +#[derive(Eq, PartialEq)] pub struct SharedPtrBase([usize; 2], PhantomData); unsafe impl Send for SharedPtrBase {} @@ -205,7 +206,6 @@ impl Drop for SharedPtrBase { /// Wrapper around a C++ shared_ptr. A shared_ptr may be be null. #[repr(C)] -#[derive(Default)] pub struct SharedPtr(SharedPtrBase); impl SharedPtr { @@ -238,6 +238,12 @@ impl Clone for SharedPtr { } } +impl Default for SharedPtr { + fn default() -> Self { + Self(Default::default()) + } +} + impl From for SharedPtr where T: Shared, @@ -625,13 +631,85 @@ where #[cfg(test)] mod tests { use super::*; + use std::ptr::null; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; + #[derive(Eq, PartialEq)] + struct MockSharedObj { + pub inner: u32, + } + + impl MockSharedObj { + const INSTANCE_A: Self = Self { inner: 11111 }; + const INSTANCE_B: Self = Self { inner: 22222 }; + + const SHARED_PTR_BASE_A: SharedPtrBase = + SharedPtrBase([1, 1], PhantomData); + const SHARED_PTR_BASE_B: SharedPtrBase = + SharedPtrBase([2, 2], PhantomData); + } + + impl Shared for MockSharedObj { + fn clone(_: &SharedPtrBase) -> SharedPtrBase { + unimplemented!() + } + + fn from_unique_ptr(_: UniquePtr) -> SharedPtrBase { + unimplemented!() + } + + fn get(p: &SharedPtrBase) -> *const Self { + match p { + &Self::SHARED_PTR_BASE_A => &Self::INSTANCE_A, + &Self::SHARED_PTR_BASE_B => &Self::INSTANCE_B, + p if p == &Default::default() => null(), + _ => unreachable!(), + } + } + + fn reset(p: &mut SharedPtrBase) { + forget(take(p)); + } + + fn use_count(_: &SharedPtrBase) -> long { + unimplemented!() + } + } + + #[test] + fn shared_ptr_and_shared_ref() { + let mut shared_ptr_a1 = SharedPtr(MockSharedObj::SHARED_PTR_BASE_A); + assert!(!shared_ptr_a1.is_null()); + + let shared_ref_a: SharedRef<_> = shared_ptr_a1.take().unwrap(); + assert_eq!(shared_ref_a.inner, 11111); + + assert!(shared_ptr_a1.is_null()); + + let shared_ptr_a2: SharedPtr<_> = shared_ref_a.into(); + assert!(!shared_ptr_a2.is_null()); + assert_eq!(shared_ptr_a2.unwrap().inner, 11111); + + let mut shared_ptr_b1 = SharedPtr(MockSharedObj::SHARED_PTR_BASE_B); + assert!(!shared_ptr_b1.is_null()); + + let shared_ref_b: SharedRef<_> = shared_ptr_b1.take().unwrap(); + assert_eq!(shared_ref_b.inner, 22222); + + assert!(shared_ptr_b1.is_null()); + + let shared_ptr_b2: SharedPtr<_> = shared_ref_b.into(); + assert!(!shared_ptr_b2.is_null()); + assert_eq!(shared_ptr_b2.unwrap().inner, 22222); + } + static TEST_OBJ_DROPPED: AtomicBool = AtomicBool::new(false); + struct TestObj { pub id: u32, } + impl Drop for TestObj { fn drop(&mut self) { assert!(!TEST_OBJ_DROPPED.swap(true, Ordering::SeqCst)); @@ -639,12 +717,15 @@ mod tests { } struct TestObjRef(TestObj); + impl Deref for TestObjRef { type Target = TestObj; + fn deref(&self) -> &TestObj { &self.0 } } + impl Borrow for TestObjRef { fn borrow(&self) -> &TestObj { &**self