Coverage Report

Created: 2025-10-31 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/try-lock-0.2.5/src/lib.rs
Line
Count
Source
1
#![deny(missing_docs)]
2
#![deny(missing_debug_implementations)]
3
#![deny(warnings)]
4
#![cfg_attr(not(test), no_std)]
5
6
//! A light-weight lock guarded by an atomic boolean.
7
//!
8
//! Most efficient when contention is low, acquiring the lock is a single
9
//! atomic swap, and releasing it just 1 more atomic swap.
10
//!
11
//! # Example
12
//!
13
//! ```
14
//! use std::sync::Arc;
15
//! use try_lock::TryLock;
16
//!
17
//! // a thing we want to share
18
//! struct Widget {
19
//!     name: String,
20
//! }
21
//!
22
//! // lock it up!
23
//! let widget1 = Arc::new(TryLock::new(Widget {
24
//!     name: "Spanner".into(),
25
//! }));
26
//!
27
//! let widget2 = widget1.clone();
28
//!
29
//!
30
//! // mutate the widget
31
//! let mut locked = widget1.try_lock().expect("example isn't locked yet");
32
//! locked.name.push_str(" Bundle");
33
//!
34
//! // hands off, buddy
35
//! let not_locked = widget2.try_lock();
36
//! assert!(not_locked.is_none(), "widget1 has the lock");
37
//!
38
//! // ok, you can have it
39
//! drop(locked);
40
//!
41
//! let locked2 = widget2.try_lock().expect("widget1 lock is released");
42
//!
43
//! assert_eq!(locked2.name, "Spanner Bundle");
44
//! ```
45
46
#[cfg(test)]
47
extern crate core;
48
49
use core::cell::UnsafeCell;
50
use core::fmt;
51
use core::ops::{Deref, DerefMut};
52
use core::sync::atomic::{AtomicBool, Ordering};
53
use core::marker::PhantomData;
54
55
/// A light-weight lock guarded by an atomic boolean.
56
///
57
/// Most efficient when contention is low, acquiring the lock is a single
58
/// atomic swap, and releasing it just 1 more atomic swap.
59
///
60
/// It is only possible to try to acquire the lock, it is not possible to
61
/// wait for the lock to become ready, like with a `Mutex`.
62
#[derive(Default)]
63
pub struct TryLock<T> {
64
    is_locked: AtomicBool,
65
    value: UnsafeCell<T>,
66
}
67
68
impl<T> TryLock<T> {
69
    /// Create a `TryLock` around the value.
70
    #[inline]
71
0
    pub const fn new(val: T) -> TryLock<T> {
72
0
        TryLock {
73
0
            is_locked: AtomicBool::new(false),
74
0
            value: UnsafeCell::new(val),
75
0
        }
76
0
    }
77
78
    /// Try to acquire the lock of this value.
79
    ///
80
    /// If the lock is already acquired by someone else, this returns
81
    /// `None`. You can try to acquire again whenever you want, perhaps
82
    /// by spinning a few times, or by using some other means of
83
    /// notification.
84
    ///
85
    /// # Note
86
    ///
87
    /// The default memory ordering is to use `Acquire` to lock, and `Release`
88
    /// to unlock. If different ordering is required, use
89
    /// [`try_lock_explicit`](TryLock::try_lock_explicit) or
90
    /// [`try_lock_explicit_unchecked`](TryLock::try_lock_explicit_unchecked).
91
    #[inline]
92
    pub fn try_lock(&self) -> Option<Locked<T>> {
93
        unsafe {
94
            self.try_lock_explicit_unchecked(Ordering::Acquire, Ordering::Release)
95
        }
96
    }
97
98
    /// Try to acquire the lock of this value using the lock and unlock orderings.
99
    ///
100
    /// If the lock is already acquired by someone else, this returns
101
    /// `None`. You can try to acquire again whenever you want, perhaps
102
    /// by spinning a few times, or by using some other means of
103
    /// notification.
104
    #[inline]
105
    #[deprecated(
106
        since = "0.2.3",
107
        note = "This method is actually unsafe because it unsafely allows \
108
        the use of weaker memory ordering. Please use try_lock_explicit instead"
109
    )]
110
    pub fn try_lock_order(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> {
111
        unsafe {
112
            self.try_lock_explicit_unchecked(lock_order, unlock_order)
113
        }
114
    }
115
116
    /// Try to acquire the lock of this value using the specified lock and
117
    /// unlock orderings.
118
    ///
119
    /// If the lock is already acquired by someone else, this returns
120
    /// `None`. You can try to acquire again whenever you want, perhaps
121
    /// by spinning a few times, or by using some other means of
122
    /// notification.
123
    ///
124
    /// # Panic
125
    ///
126
    /// This method panics if `lock_order` is not any of `Acquire`, `AcqRel`,
127
    /// and `SeqCst`, or `unlock_order` is not any of `Release` and `SeqCst`.
128
    #[inline]
129
0
    pub fn try_lock_explicit(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> {
130
0
        match lock_order {
131
            Ordering::Acquire |
132
            Ordering::AcqRel |
133
0
            Ordering::SeqCst => {}
134
0
            _ => panic!("lock ordering must be `Acquire`, `AcqRel`, or `SeqCst`"),
135
        }
136
137
0
        match unlock_order {
138
            Ordering::Release |
139
0
            Ordering::SeqCst => {}
140
0
            _ => panic!("unlock ordering must be `Release` or `SeqCst`"),
141
        }
142
143
        unsafe {
144
0
            self.try_lock_explicit_unchecked(lock_order, unlock_order)
145
        }
146
0
    }
147
148
    /// Try to acquire the lock of this value using the specified lock and
149
    /// unlock orderings without checking that the specified orderings are
150
    /// strong enough to be safe.
151
    ///
152
    /// If the lock is already acquired by someone else, this returns
153
    /// `None`. You can try to acquire again whenever you want, perhaps
154
    /// by spinning a few times, or by using some other means of
155
    /// notification.
156
    ///
157
    /// # Safety
158
    ///
159
    /// Unlike [`try_lock_explicit`], this method is unsafe because it does not
160
    /// check that the given memory orderings are strong enough to prevent data
161
    /// race.
162
    ///
163
    /// [`try_lock_explicit`]: Self::try_lock_explicit
164
    #[inline]
165
0
    pub unsafe fn try_lock_explicit_unchecked(&self, lock_order: Ordering, unlock_order: Ordering) -> Option<Locked<T>> {
166
0
        if !self.is_locked.swap(true, lock_order) {
167
0
            Some(Locked {
168
0
                lock: self,
169
0
                order: unlock_order,
170
0
                _p: PhantomData,
171
0
            })
172
        } else {
173
0
            None
174
        }
175
0
    }
176
177
    /// Take the value back out of the lock when this is the sole owner.
178
    #[inline]
179
    pub fn into_inner(self) -> T {
180
        debug_assert!(!self.is_locked.load(Ordering::Relaxed), "TryLock was mem::forgotten");
181
        self.value.into_inner()
182
    }
183
}
184
185
unsafe impl<T: Send> Send for TryLock<T> {}
186
unsafe impl<T: Send> Sync for TryLock<T> {}
187
188
impl<T: fmt::Debug> fmt::Debug for TryLock<T> {
189
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
190
191
        // Used if the TryLock cannot acquire the lock.
192
        struct LockedPlaceholder;
193
194
        impl fmt::Debug for LockedPlaceholder {
195
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196
                f.write_str("<locked>")
197
            }
198
        }
199
200
        let mut builder = f.debug_struct("TryLock");
201
        if let Some(locked) = self.try_lock() {
202
            builder.field("value", &*locked);
203
        } else {
204
            builder.field("value", &LockedPlaceholder);
205
        }
206
        builder.finish()
207
    }
208
}
209
210
/// A locked value acquired from a `TryLock`.
211
///
212
/// The type represents an exclusive view at the underlying value. The lock is
213
/// released when this type is dropped.
214
///
215
/// This type derefs to the underlying value.
216
#[must_use = "TryLock will immediately unlock if not used"]
217
pub struct Locked<'a, T: 'a> {
218
    lock: &'a TryLock<T>,
219
    order: Ordering,
220
    /// Suppresses Send and Sync autotraits for `struct Locked`.
221
    _p: PhantomData<*mut T>,
222
}
223
224
impl<'a, T> Deref for Locked<'a, T> {
225
    type Target = T;
226
    #[inline]
227
0
    fn deref(&self) -> &T {
228
0
        unsafe { &*self.lock.value.get() }
229
0
    }
230
}
231
232
impl<'a, T> DerefMut for Locked<'a, T> {
233
    #[inline]
234
0
    fn deref_mut(&mut self) -> &mut T {
235
0
        unsafe { &mut *self.lock.value.get() }
236
0
    }
237
}
238
239
impl<'a, T> Drop for Locked<'a, T> {
240
    #[inline]
241
0
    fn drop(&mut self) {
242
0
        self.lock.is_locked.store(false, self.order);
243
0
    }
244
}
245
246
impl<'a, T: fmt::Debug> fmt::Debug for Locked<'a, T> {
247
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248
        fmt::Debug::fmt(&**self, f)
249
    }
250
}
251
252
#[cfg(test)]
253
mod tests {
254
    use super::TryLock;
255
256
    #[test]
257
    fn fmt_debug() {
258
        let lock = TryLock::new(5);
259
        assert_eq!(format!("{:?}", lock), "TryLock { value: 5 }");
260
261
        let locked = lock.try_lock().unwrap();
262
        assert_eq!(format!("{:?}", locked), "5");
263
264
        assert_eq!(format!("{:?}", lock), "TryLock { value: <locked> }");
265
    }
266
}