cycle_ptr 0.1.0

Smart pointers, with cycles
//! Prelude imports for cycle pointer.

/// Trait that is used to overload the `ptr_eq` method on the different GC pointers.
pub trait GcPtrEq<Other> {
    /// Test if two pointers point at the same address.
    fn ptr_eq(x: &Self, y: &Other) -> bool;
}

/// Trait that is used to overload the `new_pointer` method on [Metadata][crate::Metadata].
pub trait GcMemberPtrNew<StrongPointer, MemberPointer> {
    /// Create a new member-pointer.
    ///
    /// The member pointer origin is the object associated with this metadata.
    fn new_pointer(&self, p: StrongPointer) -> MemberPointer;
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;
    #[cfg(feature = "multi_thread")]
    use crate::sync::{GcMtMemberPtr, GcMtPtr};
    use crate::{GcMemberPtr, GcPtr};

    /// A trait that includes all the [GcPtrEq] implementations that we provide.
    #[cfg(all(not(feature = "weak_pointer"), not(feature = "multi_thread")))]
    trait AllGcPtrEq<T>
    where
        T: 'static + Send + Sync,
        Self: GcPtrEq<GcPtr<T>>,
        Self: GcPtrEq<GcMemberPtr<T>>,
    {
    }

    /// A trait that includes all the [GcPtrEq] implementations that we provide.
    #[cfg(all(feature = "multi_thread", not(feature = "weak_pointer")))]
    trait AllGcPtrEq<T>
    where
        T: 'static + Send + Sync,
        Self: GcPtrEq<GcPtr<T>>,
        Self: GcPtrEq<GcMtPtr<T>>,
        Self: GcPtrEq<GcMemberPtr<T>>,
        Self: GcPtrEq<GcMtMemberPtr<T>>,
    {
    }

    /// A trait that includes all the [GcPtrEq] implementations that we provide.
    #[cfg(all(feature = "weak_pointer", not(feature = "multi_thread")))]
    trait AllGcPtrEq<T>
    where
        T: 'static + Send + Sync,
        Self: GcPtrEq<GcPtr<T>>,
        Self: GcPtrEq<GcMemberPtr<T>>,
        Self: GcPtrEq<crate::Weak<T>>,
    {
    }

    /// A trait that includes all the [GcPtrEq] implementations that we provide.
    #[cfg(all(feature = "weak_pointer", feature = "multi_thread"))]
    trait AllGcPtrEq<T>
    where
        T: 'static + Send + Sync,
        Self: GcPtrEq<GcPtr<T>>,
        Self: GcPtrEq<GcMtPtr<T>>,
        Self: GcPtrEq<GcMemberPtr<T>>,
        Self: GcPtrEq<GcMtMemberPtr<T>>,
        Self: GcPtrEq<crate::Weak<T>>,
        Self: GcPtrEq<crate::sync::Weak<T>>,
    {
    }

    /// Compile time check to confirm [GcPtr] really implements all versions of [GcPtrEq].
    impl<T> AllGcPtrEq<T> for GcPtr<T> where T: 'static + Send + Sync {}

    /// Compile time check to confirm [GcMtPtr] really implements all versions of [GcPtrEq].
    #[cfg(feature = "multi_thread")]
    impl<T> AllGcPtrEq<T> for GcMtPtr<T> where T: 'static + Send + Sync {}

    /// Compile time check to confirm [GcMemberPtr] really implements all versions of [GcPtrEq].
    impl<T> AllGcPtrEq<T> for GcMemberPtr<T> where T: 'static + Send + Sync {}

    /// Compile time check to confirm [GcMemberPtr] really implements all versions of [GcPtrEq].
    #[cfg(feature = "multi_thread")]
    impl<T> AllGcPtrEq<T> for GcMtMemberPtr<T> where T: 'static + Send + Sync {}

    /// Compile time check to confirm [Weak][crate::Weak] really implements all versions of [GcPtrEq].
    #[cfg(feature = "weak_pointer")]
    impl<T> AllGcPtrEq<T> for crate::Weak<T> where T: 'static + Send + Sync {}

    /// Compile time check to confirm [Weak][crate::sync::Weak] really implements all versions of [GcPtrEq].
    #[cfg(all(feature = "multi_thread", feature = "weak_pointer"))]
    impl<T> AllGcPtrEq<T> for crate::sync::Weak<T> where T: 'static + Send + Sync {}

    struct TestData {}

    /// Little struct to hold on to a member pointer.
    struct MemberTestData {
        member_ptr: GcMemberPtr<TestData>,
    }

    impl MemberTestData {
        fn new(test_data: GcPtr<TestData>) -> GcPtr<MemberTestData> {
            GcPtr::new(|metadata| MemberTestData {
                member_ptr: metadata.new_pointer(test_data),
            })
        }
    }

    /// Little struct to hold on to a member pointer.
    #[cfg(feature = "multi_thread")]
    struct MtMemberTestData {
        member_ptr: GcMtMemberPtr<TestData>,
    }

    #[cfg(feature = "multi_thread")]
    impl MtMemberTestData {
        fn new(test_data: GcMtPtr<TestData>) -> GcMtPtr<MtMemberTestData> {
            GcMtPtr::new(|metadata| MtMemberTestData {
                member_ptr: metadata.new_pointer(test_data),
            })
        }
    }

    struct TestPointers {
        ptr: GcPtr<TestData>,
        #[cfg(feature = "multi_thread")]
        mt_ptr: GcMtPtr<TestData>,
        mtd: GcPtr<MemberTestData>,
        #[cfg(feature = "multi_thread")]
        mt_mtd: GcMtPtr<MtMemberTestData>,
        #[cfg(feature = "weak_pointer")]
        weak: crate::Weak<TestData>,
        #[cfg(all(feature = "multi_thread", feature = "weak_pointer"))]
        mt_weak: crate::sync::Weak<TestData>,
    }

    impl Default for TestPointers {
        #[cfg(not(feature = "multi_thread"))]
        fn default() -> Self {
            let main_ptr = GcPtr::new(|_| TestData {});

            TestPointers {
                ptr: main_ptr.clone(),
                mtd: MemberTestData::new(main_ptr.clone()),
                #[cfg(feature = "weak_pointer")]
                weak: GcPtr::downgrade(&main_ptr),
            }
        }

        #[cfg(feature = "multi_thread")]
        fn default() -> Self {
            let main_ptr = GcMtPtr::new(|_| TestData {});

            TestPointers {
                ptr: main_ptr.clone().into(),
                mt_ptr: main_ptr.clone(),
                mtd: MemberTestData::new(main_ptr.clone().into()),
                mt_mtd: MtMemberTestData::new(main_ptr.clone()),
                #[cfg(feature = "weak_pointer")]
                weak: GcPtr::downgrade(&main_ptr.clone().into()),
                #[cfg(feature = "weak_pointer")]
                mt_weak: GcMtPtr::downgrade(&main_ptr),
            }
        }
    }

    /// Run asserts to confirm `ptr` is equal to all of the [TestPointers].
    fn assert_all_eq<Ptr>(ptr: &Ptr, tp: &TestPointers)
    where
        Ptr: AllGcPtrEq<TestData>,
    {
        assert!(Ptr::ptr_eq(&ptr, &tp.ptr));
        #[cfg(feature = "multi_thread")]
        assert!(Ptr::ptr_eq(&ptr, &tp.mt_ptr));
        assert!(Ptr::ptr_eq(&ptr, &tp.mtd.member_ptr));
        #[cfg(feature = "multi_thread")]
        assert!(Ptr::ptr_eq(&ptr, &tp.mt_mtd.member_ptr));
        #[cfg(feature = "weak_pointer")]
        assert!(Ptr::ptr_eq(&ptr, &tp.weak));
        #[cfg(all(feature = "multi_thread", feature = "weak_pointer"))]
        assert!(Ptr::ptr_eq(&ptr, &tp.mt_weak));
    }

    /// Run asserts to confirm `ptr` is not equal to any of the [TestPointers].
    fn assert_all_ne<Ptr>(ptr: &Ptr, tp: &TestPointers)
    where
        Ptr: AllGcPtrEq<TestData>,
    {
        assert!(!Ptr::ptr_eq(&ptr, &tp.ptr));
        #[cfg(feature = "multi_thread")]
        assert!(!Ptr::ptr_eq(&ptr, &tp.mt_ptr));
        assert!(!Ptr::ptr_eq(&ptr, &tp.mtd.member_ptr));
        #[cfg(feature = "multi_thread")]
        assert!(!Ptr::ptr_eq(&ptr, &tp.mt_mtd.member_ptr));
        #[cfg(feature = "weak_pointer")]
        assert!(!Ptr::ptr_eq(&ptr, &tp.weak));
        #[cfg(all(feature = "multi_thread", feature = "weak_pointer"))]
        assert!(!Ptr::ptr_eq(&ptr, &tp.mt_weak));
    }

    #[test]
    fn ptr_eq() {
        // `tp` is the set of test pointers we compare as equal against.
        let tp = TestPointers::default();
        // `other` is the set of test pointers that we compare as not-equal against.
        let other = TestPointers::default();

        // Test for [GcPtr]
        assert_all_eq(&tp.ptr.clone(), &tp);
        assert_all_ne(&tp.ptr.clone(), &other);

        // Test for [GcMtPtr]
        #[cfg(feature = "multi_thread")]
        assert_all_eq(&tp.mt_ptr.clone(), &tp);
        #[cfg(feature = "multi_thread")]
        assert_all_ne(&tp.mt_ptr.clone(), &other);

        // Test for [GcMemberPtr]
        assert_all_eq(&tp.mtd.member_ptr, &tp);
        assert_all_ne(&tp.mtd.member_ptr, &other);

        // Test for [GcMtMemberPtr]
        #[cfg(feature = "multi_thread")]
        assert_all_eq(&tp.mt_mtd.member_ptr, &tp);
        #[cfg(feature = "multi_thread")]
        assert_all_ne(&tp.mt_mtd.member_ptr, &other);

        // Test for [Weak][crate::Weak]
        #[cfg(feature = "weak_pointer")]
        assert_all_eq(&tp.weak.clone(), &tp);
        #[cfg(feature = "weak_pointer")]
        assert_all_ne(&tp.weak.clone(), &other);

        // Test for [Weak][crate::sync::Weak]
        #[cfg(all(feature = "multi_thread", feature = "weak_pointer"))]
        assert_all_eq(&tp.mt_weak.clone(), &tp);
        #[cfg(all(feature = "multi_thread", feature = "weak_pointer"))]
        assert_all_ne(&tp.mt_weak.clone(), &other);
    }
}