safe_lock/
lib.rs

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! # ARCHIVED ARCHIVED ARCHIVED
//! This crate is archived and will not be updated.
//!
//! [`std::sync::Mutex`] got a `const` constructor, making this crate unnecessary.
//! See [rustlang/rust#66806](https://github.com/rust-lang/rust/issues/66806).
//! Don't use this crate.  Just use [`std::sync::Mutex`].
//!
//! For folks who continue using this crate,
//! `SafeLock` is now a simple wrapper around [`std::sync::Mutex`],
//! so their tests will run a bit faster.
//!
//! ----
//!
//! # safe-lock
//!
//! A simple `SafeLock` struct.
//!
//! # Use Cases
//! - Run tests sequentially
//! - Prevent concurrent operations on atomic values
//! - Prevent concurrent operations on data and systems outside the Rust runtime
//!
//! # Features
//! - Const constructor
//! - Depends only on `std`
//! - `forbid(unsafe_code)`
//! - 100% test coverage
//!
//! # Limitations
//! - Not a `Mutex<T>`.  Does not contain a value.
//! - Unoptimized.  Uses
//!   [`AtomicBool`](https://doc.rust-lang.org/core/sync/atomic/struct.AtomicBool.html)
//!   in a spinlock, not fast OS locks.
//! - Not a fair lock.  If multiple threads acquire the lock in loops,
//!   some may never acquire it.
//!
//! # Alternatives
//! - [`rusty-fork`](https://crates.io/crates/rusty-fork)
//!   - Run tests in separate processes
//! - [`std::sync::Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)
//!   - Part of the Rust standard library: well reviewed, well tested, and well maintained.
//!   - Uses fast OS locks
//!   - Has no const constructor.  See [rust#66806](https://github.com/rust-lang/rust/issues/66806)
//!     and [const-eval#3](https://github.com/rust-lang/const-eval/issues/3).
//!     You can work around this with unstable
//!     [`core::lazy::OnceCell`](https://doc.rust-lang.org/core/lazy/struct.OnceCell.html)
//!     or various `unsafe` crates:
//!     [`lazy_static`](https://crates.io/crates/lazy_static),
//!     [`once_cell`](https://crates.io/crates/once_cell),
//!     [`lazycell`](https://crates.io/crates/lazycell), and
//!     [`conquer-once`](https://crates.io/crates/conquer-once).
//! - [`parking_lot`](https://crates.io/crates/parking_lot)
//!   - Well written code.
//!     Many hope that it will end up in the Rust standard library someday.
//!   - Contains plenty of `unsafe`
//! - [`try-lock`](https://crates.io/crates/try-lock)
//!   - Popular
//!   - No dependencies, `no_std`
//!   - Uses `unsafe`
//! - [`ruspiro-lock`](https://crates.io/crates/ruspiro-lock)
//!   - Sync and async locks
//!   - No dependencies, `no_std`
//!   - Uses `unsafe`
//! - [`flexible-locks`](https://crates.io/crates/flexible-locks)
//!   - Lots of `unsafe`
//!   - Uses fast OS locks
//!   - Unmaintained
//!
//! # Related Crates
//! - [`safina-sync`](https://crates.io/crates/safina-sync)
//!   provides a safe async `Mutex`
//!
//! # Example
//!
//! Make some tests run sequentially so they don't interfere with each other:
//! ```unknown
//! use safe_lock::SafeLock;
//! static LOCK: SafeLock = SafeLock::new();
//!
//! [#test]
//! fn test1() {
//!     let _guard = LOCK.lock();
//!     // ...
//! }
//!
//! [#test]
//! fn test2() {
//!     let _guard = LOCK.lock();
//!     // ...
//! }
//! ```
//!
//! # Cargo Geiger Safety Report
//! # Changelog
//! - v0.1.4
//!    - Make `SafeLock` a wrapper around [`std::sync::Mutex`] since it got a const constructor.
//!    - Add archival notice.
//! - v0.1.3 - Increase test coverage
//! - v0.1.2 - Use `Acquire` and `Release` ordering
//! - v0.1.1 - Update docs
//! - v0.1.0 - Initial version
#![forbid(unsafe_code)]
use std::sync::{Mutex, MutexGuard, PoisonError};

/// A handle to the acquired lock.  Drop this to release the lock.
#[allow(dead_code)]
pub struct SafeLockGuard<'x>(MutexGuard<'x, ()>);

/// A lock.
///
/// See [`lock`](#method.lock).
///
/// This is not a fair lock.
/// If multiple threads acquire the lock in loops,
/// some may never acquire it.
///
/// # Example
///
/// Make some tests run sequentially so they don't interfere with each other:
/// ```unknown
/// use safe_lock::SafeLock;
/// static LOCK: SafeLock = SafeLock::new();
///
/// [#test]
/// fn test1() {
///     let _guard = LOCK.lock();
///     // ...
/// }
///
/// [#test]
/// fn test2() {
///     let _guard = LOCK.lock();
///     // ...
/// }
/// ```
pub struct SafeLock(Mutex<()>);
impl SafeLock {
    #[must_use]
    pub const fn new() -> SafeLock {
        SafeLock(Mutex::new(()))
    }

    /// Waits until the lock is free, then acquires the lock.
    ///
    /// Multiple threads can call `lock` but only one will acquire the lock
    /// and return.
    ///
    /// Drop the returned `SafeLockGuard` to release the lock.
    ///
    /// This is not a fair lock.
    /// If multiple threads acquire the lock in loops,
    /// some may never acquire it.
    #[must_use]
    pub fn lock(&self) -> Option<SafeLockGuard> {
        let guard = self.0.lock().unwrap_or_else(PoisonError::into_inner);
        Some(SafeLockGuard(guard))
    }
}
impl Default for SafeLock {
    fn default() -> Self {
        Self::new()
    }
}