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}