duals 0.0.3

dual-ownership referance cells
Documentation
//! Dual-Ownership Reference Cells
//!
//! These are similar to `Rc` and `Arc`, but ensure that only two references exist.
//!
//! - `Rc` is similar to [`Dual`](crate::Dual)
//! - `Arc` is similar to [`ADual`](crate::ADual)
//!
//! See the struct's documentation for more details.
//!
//! | This Library uses **UNSAFE!** Use at your own **RISK!** |
//! | ------------------------- |

#[cfg(test)]
mod test;

struct DualInner<T, F> {
    value: T,
    flag: F
}

impl<T, F> DualInner<T, F> {
    fn new(value: T, flag: F) -> *mut Self {
        Box::into_raw(Box::new(DualInner { value, flag }))
    }
}

mod cell {
    use std::cell::Cell;
    use std::fmt::{Debug, Formatter};
    use std::ops::Deref;
    use crate::DualInner;

    /// A dual-ownership (non-sync) reference cell
    ///
    /// - uses a `Cell<bool>` internally
    /// - implements `Send` if `T` implements `Send`
    ///
    /// you can access the value using the `Deref` impl
    ///
    /// ```
    /// use duals::Dual;
    ///
    /// // create a new `Dual`
    /// let (left, right) = Dual::new(10);
    ///
    /// println!("{:?} {:?}", *left, *right);
    /// drop(left);
    /// println!("{:?}", *right);
    /// drop(right);
    /// ```
    pub struct Dual<T> {
        inner: *mut DualInner<T, Cell<bool>>
    }

    impl<T> Dual<T> {
        /// create a new `Dual`
        ///
        /// ```
        /// use duals::Dual;
        /// let (left, right) = Dual::new(10);
        /// ```
        pub fn new(value: T) -> (Self, Self) {
            let inner = DualInner::new(value, Cell::new(true));
            (Self { inner }, Self { inner })
        }

        /// check if the other `Dual` reference exists
        ///
        /// ```
        /// use duals::Dual;
        /// let (left, right) = Dual::new(10);
        ///
        /// assert!(left.other_exists()); // true;
        /// drop(right);
        /// assert!(!left.other_exists()); // false;
        /// ```
        pub fn other_exists(&self) -> bool {
            unsafe { (*self.inner).flag.get() }
        }

        /// clone the value from inside the reference
        pub fn take(&self) -> T where T: Clone {
            unsafe {
                (&*self.inner).value.clone()
            }
        }
    }

    impl<T> Deref for Dual<T> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            unsafe { &(*self.inner).value }
        }
    }


    impl<T> Drop for Dual<T> {
        fn drop(&mut self) {
            unsafe  {
                if !(*self.inner).flag.take() {
                    drop(Box::from_raw(self.inner));
                }
            }
        }
    }

    impl<T> Debug for Dual<T> where T: Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
            self.deref().fmt(f)
        }
    }

    unsafe impl<T> Send for Dual<T> where T: Send {}

}


mod atomic {
    use std::fmt::{Debug, Formatter};
    use std::ops::Deref;
    use std::sync::atomic::{AtomicBool, Ordering};
    use crate::DualInner;

    /// A dual-ownership (atomic-sync) reference cell
    ///
    /// - uses a `AtomicBool` internally
    /// - implements `Send` if `T` implements `Send`
    /// - implements `Sync` if `T` implements `Sync`
    ///
    /// you can access the value using the `Deref` impl
    ///
    /// ```
    /// use duals::ADual;
    ///
    /// // create a new `ADual`
    /// let (left, right) = ADual::new(10);
    ///
    /// println!("{:?} {:?}", *left, *right);
    /// drop(left);
    /// println!("{:?}", *right);
    /// drop(right);
    /// ```
    pub struct ADual<T> {
        inner: *mut DualInner<T, AtomicBool>
    }

    impl<T> ADual<T> {
        /// create a new `ADual`
        ///
        /// ```
        /// use duals::Dual;
        /// let (left, right) = Dual::new(10);
        /// ```
        pub fn new(value: T) -> (Self, Self) {
            let inner = DualInner::new(value, AtomicBool::new(true));
            (Self { inner }, Self { inner })
        }

        ///
        /// ```
        /// use duals::ADual;
        /// let (left, right) = ADual::new(10);
        ///
        /// assert!(left.other_exists()); // true;
        /// drop(right);
        /// assert!(!left.other_exists()); // false;
        /// ```
        pub fn other_exists(&self) -> bool {
            unsafe { (*self.inner).flag.load(Ordering::SeqCst) }
        }

        /// clone the value from inside the reference
        pub fn take(&self) -> T where T: Clone {
            unsafe {
                (&*self.inner).value.clone()
            }
        }
    }

    impl<T> Deref for ADual<T> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            unsafe { &(*self.inner).value }
        }
    }


    impl<T> Drop for ADual<T> {
        fn drop(&mut self) {
            unsafe {
                if !(*self.inner).flag.fetch_and(false, Ordering::SeqCst) {
                    drop(Box::from_raw(self.inner));
                }
            }

        }
    }

    impl<T> Debug for ADual<T> where T: Debug {
        fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
            self.deref().fmt(f)
        }
    }


    unsafe impl<T> Send for ADual<T> where T: Send {}
    unsafe impl<T> Sync for ADual<T> where T: Sync {}
}

pub use cell::Dual;
pub use atomic::ADual;