echeneis 0.1.0

Testing framework for non-blocking code
//! crate internal sync plumbing for testing

#![allow(
    dead_code,
    unused_imports,
    unknown_lints,
    clippy::disallowed_modules,
    missing_docs
)]

#[cfg(all(not(loom), not(shuttle)))]
pub(crate) use core_::*;
#[cfg(loom)]
pub(crate) use loom_::*;
#[cfg(shuttle)]
pub(crate) use shuttle_::*;

#[cfg(shuttle)]
mod shuttle_ {
    pub(crate) use shuttle::{
        hint,
        sync::{Arc, Weak, atomic},
        thread,
        thread_local,
    };

    pub(crate) mod cell {
        #[derive(Debug)]
        pub(crate) struct UnsafeCell<T>(core::cell::UnsafeCell<T>);

        #[allow(dead_code)]
        impl<T> UnsafeCell<T> {
            pub(crate) fn new(data: T) -> UnsafeCell<T> {
                UnsafeCell(core::cell::UnsafeCell::new(data))
            }

            pub(crate) fn with<R>(&self, f: impl FnOnce(*const T) -> R) -> R {
                f(self.0.get())
            }

            pub(crate) fn with_mut<R>(&self, f: impl FnOnce(*mut T) -> R) -> R {
                f(self.0.get())
            }
        }

        impl<T: Default> Default for UnsafeCell<T> {
            fn default() -> Self {
                Self::new(T::default())
            }
        }
    }
}

#[cfg(loom)]
mod loom_ {
    pub(crate) use loom::{
        cell,
        hint,
        sync::{Arc, Weak, atomic},
        thread,
        thread_local,
    };
}

#[cfg(all(not(loom), not(shuttle)))]
mod core_ {
    pub(crate) mod cell {
        //! UnsafeCell
        #[derive(Debug)]
        /// wraps core::cell::UnsafeCell
        pub(crate) struct UnsafeCell<T>(std::cell::UnsafeCell<T>);

        #[allow(dead_code)]
        impl<T> UnsafeCell<T> {
            /// creates a new UnsafeCell
            pub(crate) fn new(data: T) -> UnsafeCell<T> {
                UnsafeCell(std::cell::UnsafeCell::new(data))
            }

            /// allows immutable acces to the stored value
            pub(crate) fn with<R>(&self, f: impl FnOnce(*const T) -> R) -> R {
                f(self.0.get())
            }

            /// allows mutable access to the stored value
            pub(crate) fn with_mut<R>(&self, f: impl FnOnce(*mut T) -> R) -> R {
                f(self.0.get())
            }
        }

        impl<T: Default> Default for UnsafeCell<T> {
            fn default() -> Self {
                Self::new(T::default())
            }
        }
    }

    #[cfg(not(feature = "portable-atomics"))]
    pub(crate) use std::sync::atomic;
    pub(crate) use std::{
        hint,
        sync::{Arc, Condvar},
        thread,
        thread_local,
    };

    #[cfg(feature = "portable-atomics")]
    pub(crate) use portable_atomic as atomic;
}

#[cfg(all(not(loom), not(shuttle)))]
pub(crate) use mutex::*;

#[cfg(all(not(loom), not(shuttle)))]
mod mutex {
    pub(crate) use std::sync::MutexGuard;

    #[derive(Debug, Default)]
    /// wraps std::sync::Mutex
    pub(crate) struct Mutex<T>(std::sync::Mutex<T>);

    impl<T> Mutex<T> {
        #[allow(dead_code)]
        /// Constructs a new Mutex
        pub(crate) const fn new(t: T) -> Self {
            Self(std::sync::Mutex::new(t))
        }

        /// locks the Mutex. This calls unwrap() on the internal Mutex, panicking on poison.
        pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
            self.0.lock().unwrap()
        }
    }

    pub(crate) use std::sync::{RwLockReadGuard, RwLockWriteGuard};

    #[derive(Debug, Default)]
    /// wraps std::sync::RwLock
    pub(crate) struct RwLock<T>(std::sync::RwLock<T>);

    impl<T> RwLock<T> {
        #[allow(dead_code)]
        /// Constructs a new RwLock
        pub(crate) const fn new(t: T) -> Self {
            Self(std::sync::RwLock::new(t))
        }

        /// read locks the RwLock. This calls unwrap() on the internal RwLock, panicking on poison.
        pub(crate) fn read(&self) -> RwLockReadGuard<'_, T> {
            self.0.read().unwrap()
        }

        /// write locks the RwLock. This calls unwrap() on the internal RwLock, panicking on poison.
        pub(crate) fn write(&self) -> RwLockWriteGuard<'_, T> {
            self.0.write().unwrap()
        }
    }
}

#[cfg(loom)]
pub(crate) use mutex::*;

#[cfg(loom)]
mod mutex {
    use core::ops::{Deref, DerefMut};

    pub(crate) use loom::sync::{Arc, MutexGuard};

    #[derive(Debug, Default)]
    /// wraps a loom:::sync::Mutext
    pub(crate) struct Mutex<T>(loom::sync::Mutex<T>);

    impl<T> Mutex<T> {
        #[allow(dead_code)]
        /// constructs a new Mutex
        pub(crate) const fn new(t: T) -> Self {
            Self(loom::sync::Mutex::new(t))
        }

        /// locks the mutex. unwraps poison
        pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
            self.0.lock().unwrap()
        }
    }

    pub(crate) use loom::sync::{RwLockReadGuard, RwLockWriteGuard};

    #[derive(Debug, Default)]
    /// wraps loom::sync::RwLock
    pub(crate) struct RwLock<T>(loom::sync::RwLock<T>);

    impl<T> RwLock<T> {
        #[allow(dead_code)]
        /// Constructs a new RwLock
        pub(crate) const fn new(t: T) -> Self {
            Self(loom::sync::RwLock::new(t))
        }

        /// read locks the RwLock. This calls unwrap() on the internal RwLock, panicking on poison.
        pub(crate) fn read(&self) -> RwLockReadGuard<'_, T> {
            self.0.read().unwrap()
        }

        /// write locks the RwLock. This calls unwrap() on the internal RwLock, panicking on poison.
        pub(crate) fn write(&self) -> RwLockWriteGuard<'_, T> {
            self.0.write().unwrap()
        }
    }
}

#[cfg(shuttle)]
pub(crate) use mutex::*;

#[cfg(shuttle)]
mod mutex {
    use core::ops::{Deref, DerefMut};

    pub(crate) use shuttle::sync::{Arc, MutexGuard};

    #[derive(Debug, Default)]
    /// wraps a shuttle::sync::mutex
    pub(crate) struct Mutex<T>(shuttle::sync::Mutex<T>);

    impl<T> Mutex<T> {
        #[allow(dead_code)]
        /// constructs a new mutex
        pub(crate) const fn new(t: T) -> Self {
            Self(shuttle::sync::Mutex::new(t))
        }

        /// locks the mutex. unwrapsp poison
        pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
            self.0.lock().unwrap()
        }
    }

    pub(crate) use shuttle::sync::{RwLockReadGuard, RwLockWriteGuard};

    #[derive(Debug, Default)]
    /// wraps shuttle::sync::RwLock
    pub(crate) struct RwLock<T>(shuttle::sync::RwLock<T>);

    impl<T> RwLock<T> {
        #[allow(dead_code)]
        /// Constructs a new RwLock
        pub(crate) const fn new(t: T) -> Self {
            Self(shuttle::sync::RwLock::new(t))
        }

        /// read locks the RwLock. This calls unwrap() on the internal RwLock, panicking on poison.
        pub(crate) fn read(&self) -> RwLockReadGuard<'_, T> {
            self.0.read().unwrap()
        }

        /// write locks the RwLock. This calls unwrap() on the internal RwLock, panicking on poison.
        pub(crate) fn write(&self) -> RwLockWriteGuard<'_, T> {
            self.0.write().unwrap()
        }
    }
}