      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107

    use crate::sys::mutex as imp;

    /// An OS-based mutual exclusion lock, meant for use in static variables.
    ///
    /// This mutex has a const constructor ([`StaticMutex::new`]), does not
    /// implement `Drop` to cleanup resources, and causes UB when moved or used
    /// reentrantly.
    ///
    /// This mutex does not implement poisoning.
    ///
    /// This is a wrapper around `imp::Mutex` that does *not* call `init()` and
    /// `destroy()`.
    pub struct StaticMutex(imp::Mutex);

    unsafe impl Sync for StaticMutex {}

    impl StaticMutex {
        /// Creates a new mutex for use.
        ///
        /// Behavior is undefined if the mutex is moved after it is
        /// first used with any of the functions below.
        /// Also, the behavior is undefined if this mutex is ever used reentrantly,
        /// i.e., `lock` is called by the thread currently holding the lock.
        #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")]
        pub const fn new() -> Self {
            Self(imp::Mutex::new())
        }

        /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex
        /// will be unlocked.
        ///
        /// It is undefined behaviour to call this function while locked, or if the
        /// mutex has been moved since the last time this was called.
        #[inline]
        pub unsafe fn lock(&self) -> StaticMutexGuard<'_> {
            self.0.lock();
            StaticMutexGuard(&self.0)
        }
    }

    #[must_use]
    pub struct StaticMutexGuard<'a>(&'a imp::Mutex);

    impl Drop for StaticMutexGuard<'_> {
        #[inline]
        fn drop(&mut self) {
            unsafe {
                self.0.unlock();
            }
        }
    }

    /// An OS-based mutual exclusion lock.
    ///
    /// This mutex does *not* have a const constructor, cleans up its resources in
    /// its `Drop` implementation, may safely be moved (when not borrowed), and
    /// does not cause UB when used reentrantly.
    ///
    /// This mutex does not implement poisoning.
    ///
    /// This is either a wrapper around `Box<imp::Mutex>` or `imp::Mutex`,
    /// depending on the platform. It is boxed on platforms where `imp::Mutex` may
    /// not be moved.
    pub struct MovableMutex(imp::MovableMutex);

    unsafe impl Sync for MovableMutex {}

    impl MovableMutex {
        /// Creates a new mutex.
        pub fn new() -> Self {
            let mut mutex = imp::MovableMutex::from(imp::Mutex::new());
            unsafe { mutex.init() };
            Self(mutex)
        }

        pub(super) fn raw(&self) -> &imp::Mutex {
            &self.0
        }

        /// Locks the mutex blocking the current thread until it is available.
        #[inline]
        pub fn raw_lock(&self) {
            unsafe { self.0.lock() }
        }

        /// Attempts to lock the mutex without blocking, returning whether it was
        /// successfully acquired or not.
        #[inline]
        pub fn try_lock(&self) -> bool {
            unsafe { self.0.try_lock() }
        }

        /// Unlocks the mutex.
        ///
        /// Behavior is undefined if the current thread does not actually hold the
        /// mutex.
        #[inline]
        pub unsafe fn raw_unlock(&self) {
            self.0.unlock()
        }
    }

    impl Drop for MovableMutex {
        fn drop(&mut self) {
            unsafe { self.0.destroy() };
        }
    }