safe_lock/
lib.rs

1//! # ARCHIVED ARCHIVED ARCHIVED
2//! This crate is archived and will not be updated.
3//!
4//! [`std::sync::Mutex`] got a `const` constructor, making this crate unnecessary.
5//! See [rustlang/rust#66806](https://github.com/rust-lang/rust/issues/66806).
6//! Don't use this crate.  Just use [`std::sync::Mutex`].
7//!
8//! For folks who continue using this crate,
9//! `SafeLock` is now a simple wrapper around [`std::sync::Mutex`],
10//! so their tests will run a bit faster.
11//!
12//! ----
13//!
14//! # safe-lock
15//!
16//! A simple `SafeLock` struct.
17//!
18//! # Use Cases
19//! - Run tests sequentially
20//! - Prevent concurrent operations on atomic values
21//! - Prevent concurrent operations on data and systems outside the Rust runtime
22//!
23//! # Features
24//! - Const constructor
25//! - Depends only on `std`
26//! - `forbid(unsafe_code)`
27//! - 100% test coverage
28//!
29//! # Limitations
30//! - Not a `Mutex<T>`.  Does not contain a value.
31//! - Unoptimized.  Uses
32//!   [`AtomicBool`](https://doc.rust-lang.org/core/sync/atomic/struct.AtomicBool.html)
33//!   in a spinlock, not fast OS locks.
34//! - Not a fair lock.  If multiple threads acquire the lock in loops,
35//!   some may never acquire it.
36//!
37//! # Alternatives
38//! - [`rusty-fork`](https://crates.io/crates/rusty-fork)
39//!   - Run tests in separate processes
40//! - [`std::sync::Mutex`](https://doc.rust-lang.org/std/sync/struct.Mutex.html)
41//!   - Part of the Rust standard library: well reviewed, well tested, and well maintained.
42//!   - Uses fast OS locks
43//!   - Has no const constructor.  See [rust#66806](https://github.com/rust-lang/rust/issues/66806)
44//!     and [const-eval#3](https://github.com/rust-lang/const-eval/issues/3).
45//!     You can work around this with unstable
46//!     [`core::lazy::OnceCell`](https://doc.rust-lang.org/core/lazy/struct.OnceCell.html)
47//!     or various `unsafe` crates:
48//!     [`lazy_static`](https://crates.io/crates/lazy_static),
49//!     [`once_cell`](https://crates.io/crates/once_cell),
50//!     [`lazycell`](https://crates.io/crates/lazycell), and
51//!     [`conquer-once`](https://crates.io/crates/conquer-once).
52//! - [`parking_lot`](https://crates.io/crates/parking_lot)
53//!   - Well written code.
54//!     Many hope that it will end up in the Rust standard library someday.
55//!   - Contains plenty of `unsafe`
56//! - [`try-lock`](https://crates.io/crates/try-lock)
57//!   - Popular
58//!   - No dependencies, `no_std`
59//!   - Uses `unsafe`
60//! - [`ruspiro-lock`](https://crates.io/crates/ruspiro-lock)
61//!   - Sync and async locks
62//!   - No dependencies, `no_std`
63//!   - Uses `unsafe`
64//! - [`flexible-locks`](https://crates.io/crates/flexible-locks)
65//!   - Lots of `unsafe`
66//!   - Uses fast OS locks
67//!   - Unmaintained
68//!
69//! # Related Crates
70//! - [`safina-sync`](https://crates.io/crates/safina-sync)
71//!   provides a safe async `Mutex`
72//!
73//! # Example
74//!
75//! Make some tests run sequentially so they don't interfere with each other:
76//! ```unknown
77//! use safe_lock::SafeLock;
78//! static LOCK: SafeLock = SafeLock::new();
79//!
80//! [#test]
81//! fn test1() {
82//!     let _guard = LOCK.lock();
83//!     // ...
84//! }
85//!
86//! [#test]
87//! fn test2() {
88//!     let _guard = LOCK.lock();
89//!     // ...
90//! }
91//! ```
92//!
93//! # Cargo Geiger Safety Report
94//! # Changelog
95//! - v0.1.4
96//!    - Make `SafeLock` a wrapper around [`std::sync::Mutex`] since it got a const constructor.
97//!    - Add archival notice.
98//! - v0.1.3 - Increase test coverage
99//! - v0.1.2 - Use `Acquire` and `Release` ordering
100//! - v0.1.1 - Update docs
101//! - v0.1.0 - Initial version
102#![forbid(unsafe_code)]
103use std::sync::{Mutex, MutexGuard, PoisonError};
104
105/// A handle to the acquired lock.  Drop this to release the lock.
106#[allow(dead_code)]
107pub struct SafeLockGuard<'x>(MutexGuard<'x, ()>);
108
109/// A lock.
110///
111/// See [`lock`](#method.lock).
112///
113/// This is not a fair lock.
114/// If multiple threads acquire the lock in loops,
115/// some may never acquire it.
116///
117/// # Example
118///
119/// Make some tests run sequentially so they don't interfere with each other:
120/// ```unknown
121/// use safe_lock::SafeLock;
122/// static LOCK: SafeLock = SafeLock::new();
123///
124/// [#test]
125/// fn test1() {
126///     let _guard = LOCK.lock();
127///     // ...
128/// }
129///
130/// [#test]
131/// fn test2() {
132///     let _guard = LOCK.lock();
133///     // ...
134/// }
135/// ```
136pub struct SafeLock(Mutex<()>);
137impl SafeLock {
138    #[must_use]
139    pub const fn new() -> SafeLock {
140        SafeLock(Mutex::new(()))
141    }
142
143    /// Waits until the lock is free, then acquires the lock.
144    ///
145    /// Multiple threads can call `lock` but only one will acquire the lock
146    /// and return.
147    ///
148    /// Drop the returned `SafeLockGuard` to release the lock.
149    ///
150    /// This is not a fair lock.
151    /// If multiple threads acquire the lock in loops,
152    /// some may never acquire it.
153    #[must_use]
154    pub fn lock(&self) -> Option<SafeLockGuard> {
155        let guard = self.0.lock().unwrap_or_else(PoisonError::into_inner);
156        Some(SafeLockGuard(guard))
157    }
158}
159impl Default for SafeLock {
160    fn default() -> Self {
161        Self::new()
162    }
163}