/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 | | } |