shared_singleton 0.2.1

The shared_singleton trait provides singleton pattern state management with shared container.
Documentation
pub trait Singleton {
    type Container;

    fn singleton() -> Self::Container;
}

#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! __impl_singleton_base {
    ($ty:ty,$ctnr:ty,$init:expr) => {
        impl Singleton for $ty {
            type Container = $ctnr;

            fn singleton() -> Self::Container {
                static mut INSTANCE: Option<$ctnr> = None;
                static START: std::sync::Once = std::sync::Once::new();

                START.call_once(|| unsafe { INSTANCE = Some($init) });

                unsafe { INSTANCE.clone().unwrap() }
            }
        }
    };
}

#[macro_export]
macro_rules! impl_singleton_rc {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!($ty, std::rc::Rc<$ty>, std::rc::Rc::from($init));
    };
}

#[macro_export]
macro_rules! impl_singleton_rc_cell {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!(
            $ty,
            std::rc::Rc<std::cell::Cell<$ty>>,
            std::rc::Rc::from(std::cell::Cell::from($init))
        );
    };
}

#[macro_export]
macro_rules! impl_singleton_rc_refcell {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!(
            $ty,
            std::rc::Rc<std::cell::RefCell<$ty>>,
            std::rc::Rc::from(std::cell::RefCell::from($init))
        );
    };
}

#[macro_export]
macro_rules! impl_singleton_arc {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!($ty, std::sync::Arc<$ty>, std::sync::Arc::from($init));
    };
}

#[macro_export]
macro_rules! impl_singleton_arc_mutex {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!(
            $ty,
            std::sync::Arc<std::sync::Mutex<$ty>>,
            std::sync::Arc::from(std::sync::Mutex::from($init))
        );
    };
}

#[macro_export]
macro_rules! impl_singleton_arc_rwlock {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!(
            $ty,
            std::sync::Arc<std::sync::RwLock<$ty>>,
            std::sync::Arc::from(std::sync::RwLock::from($init))
        );
    };
}

#[cfg(feature = "tokio")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "tokio")))]
#[macro_export]
macro_rules! impl_singleton_arc_mutex_tokio {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!(
            $ty,
            std::sync::Arc<tokio::sync::Mutex<$ty>>,
            std::sync::Arc::from(tokio::sync::Mutex::from($init))
        );
    };
}

#[cfg(feature = "tokio")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "tokio")))]
#[macro_export]
macro_rules! impl_singleton_arc_rwlock_tokio {
    ($ty:ty,$init:expr) => {
        __impl_singleton_base!(
            $ty,
            std::sync::Arc<tokio::sync::RwLock<$ty>>,
            std::sync::Arc::from(tokio::sync::RwLock::from($init))
        );
    };
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::rc::Rc;
    use std::sync::Arc;

    #[test]
    fn rc_test() {
        struct Foo;
        impl_singleton_rc!(Foo, Foo);
        assert!(Rc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }

    #[test]
    fn rc_cell_test() {
        struct Foo;
        impl_singleton_rc_cell!(Foo, Foo);
        assert!(Rc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }

    #[test]
    fn rc_refcell_test() {
        struct Foo;
        impl_singleton_rc_refcell!(Foo, Foo);
        assert!(Rc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }

    #[test]
    fn arc_test() {
        struct Foo;
        impl_singleton_arc!(Foo, Foo);
        assert!(Arc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }

    #[test]
    fn arc_mutex_test() {
        struct Foo;
        impl_singleton_arc_mutex!(Foo, Foo);
        assert!(Arc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }

    #[test]
    fn arc_rwlock_test() {
        struct Foo;
        impl_singleton_arc_rwlock!(Foo, Foo);
        assert!(Arc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }

    #[cfg(feature = "tokio")]
    #[tokio::test]
    async fn arc_mutex_tokio_test() {
        struct Foo;
        impl_singleton_arc_mutex_tokio!(Foo, Foo);
        assert!(Arc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }

    #[cfg(feature = "tokio")]
    #[tokio::test]
    async fn arc_rwlock_tokio_test() {
        struct Foo;
        impl_singleton_arc_rwlock_tokio!(Foo, Foo);
        assert!(Arc::ptr_eq(&Foo::singleton(), &Foo::singleton()));
    }
}