option_lock/
lock.rs

1use core::{
2    cell::UnsafeCell,
3    fmt::{self, Debug, Formatter},
4    hint::spin_loop,
5    mem::{self, transmute, ManuallyDrop, MaybeUninit},
6    ops::Deref,
7    ptr::drop_in_place,
8    sync::atomic::{AtomicU8, Ordering},
9};
10
11#[cfg(feature = "alloc")]
12use alloc::sync::Arc;
13
14#[cfg(feature = "alloc")]
15use super::arc::{MutexGuardArc, OptionGuardArc};
16
17use super::error::OptionLockError;
18
19use super::mutex::MutexGuard;
20
21#[repr(transparent)]
22pub(crate) struct State(AtomicU8);
23
24impl State {
25    pub const FREE: u8 = 1 << 0;
26    pub const SOME: u8 = 1 << 1;
27    pub const AVAILABLE: u8 = Self::FREE | Self::SOME;
28
29    pub const fn new(value: u8) -> Self {
30        Self(AtomicU8::new(value))
31    }
32
33    #[inline]
34    pub fn is_some_mut(&mut self) -> bool {
35        *self.0.get_mut() & State::SOME != 0
36    }
37
38    #[inline]
39    pub fn value(&self) -> u8 {
40        self.0.load(Ordering::Relaxed)
41    }
42}
43
44impl Deref for State {
45    type Target = AtomicU8;
46
47    #[inline]
48    fn deref(&self) -> &AtomicU8 {
49        &self.0
50    }
51}
52
53impl Debug for State {
54    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
55        f.write_str(match self.0.load(Ordering::Relaxed) {
56            Self::FREE => "None",
57            Self::AVAILABLE => "Some",
58            _ => "Locked",
59        })
60    }
61}
62
63impl PartialEq<u8> for State {
64    #[inline]
65    fn eq(&self, other: &u8) -> bool {
66        self.0.load(Ordering::Relaxed) == *other
67    }
68}
69
70/// A read/write lock around an `Option` value.
71pub struct OptionLock<T> {
72    data: UnsafeCell<MaybeUninit<T>>,
73    pub(crate) state: State,
74}
75
76impl<T> Default for OptionLock<T> {
77    fn default() -> Self {
78        Self::empty()
79    }
80}
81
82unsafe impl<T: Send> Send for OptionLock<T> {}
83unsafe impl<T: Send> Sync for OptionLock<T> {}
84
85impl<T> OptionLock<T> {
86    /// Create a new instance with no stored value.
87    pub const fn empty() -> Self {
88        Self {
89            data: UnsafeCell::new(MaybeUninit::uninit()),
90            state: State::new(State::FREE),
91        }
92    }
93
94    /// Create a new populated instance.
95    pub const fn new(value: T) -> Self {
96        Self {
97            data: UnsafeCell::new(MaybeUninit::new(value)),
98            state: State::new(State::AVAILABLE),
99        }
100    }
101
102    #[inline]
103    pub(crate) unsafe fn as_ptr(&self) -> *const T {
104        (&*self.data.get()).as_ptr()
105    }
106
107    #[inline]
108    pub(crate) unsafe fn as_mut_ptr(&self) -> *mut T {
109        (&mut *self.data.get()).as_mut_ptr()
110    }
111
112    /// Check if there is no stored value and no guard held.
113    #[inline]
114    pub fn is_none_unlocked(&self) -> bool {
115        self.state == State::FREE
116    }
117
118    /// Check if there is a stored value and no guard held.
119    #[inline]
120    pub fn is_some_unlocked(&self) -> bool {
121        self.state == State::AVAILABLE
122    }
123
124    #[inline]
125    pub(crate) fn is_some(&self) -> bool {
126        self.state.value() & State::SOME != 0
127    }
128
129    /// Check if a guard is held.
130    #[inline]
131    pub fn is_locked(&self) -> bool {
132        self.state.value() & State::FREE == 0
133    }
134
135    /// Get a mutable reference to the contained value, if any.
136    pub fn get_mut(&mut self) -> Option<&mut T> {
137        if self.is_some() {
138            Some(unsafe { &mut *self.as_mut_ptr() })
139        } else {
140            None
141        }
142    }
143
144    /// Unwrap an owned lock instance.
145    pub fn into_inner(mut self) -> Option<T> {
146        if self.state.is_some_mut() {
147            let slf = ManuallyDrop::new(self);
148            Some(unsafe { slf.as_mut_ptr().read() })
149        } else {
150            None
151        }
152    }
153
154    /// In a spin loop, wait to get an exclusive lock on the contained value.
155    pub fn spin_get(&self) -> MutexGuard<'_, T> {
156        loop {
157            if let Ok(guard) = self.try_get() {
158                return guard;
159            }
160            while !self.is_some_unlocked() {
161                spin_loop();
162            }
163        }
164    }
165
166    /// In a spin loop, wait to acquire the lock.
167    pub fn spin_lock(&self) -> OptionGuard<'_, T> {
168        loop {
169            if let Ok(guard) = self.try_lock() {
170                return guard;
171            }
172            while self.is_locked() {
173                spin_loop();
174            }
175        }
176    }
177
178    /// In a spin loop, wait to acquire the lock with an empty slot.
179    pub fn spin_lock_none(&self) -> OptionGuard<'_, T> {
180        loop {
181            if let Ok(guard) = self.try_lock_none() {
182                return guard;
183            }
184            while !self.is_none_unlocked() {
185                spin_loop();
186            }
187        }
188    }
189
190    /// In a spin loop, wait to take a value from the lock.
191    pub fn spin_take(&self) -> T {
192        loop {
193            if let Ok(result) = self.try_take() {
194                return result;
195            }
196            while !self.is_some_unlocked() {
197                spin_loop();
198            }
199        }
200    }
201
202    /// Try to acquire an exclusive lock around a contained value.
203    ///
204    /// On successful acquisition a `MutexGuard<'_, T>` is returned, representing
205    /// an exclusive read/write lock.
206    pub fn try_get(&self) -> Result<MutexGuard<'_, T>, OptionLockError> {
207        match self.state.compare_exchange(
208            State::AVAILABLE,
209            State::SOME,
210            Ordering::AcqRel,
211            Ordering::Relaxed,
212        ) {
213            Ok(_) => Ok(MutexGuard::new(OptionGuard::new(self, true))),
214            Err(State::FREE) => Err(OptionLockError::FillState),
215            Err(_) => Err(OptionLockError::Unavailable),
216        }
217    }
218
219    #[cfg(feature = "alloc")]
220    /// Try to acquire an exclusive lock around the value in an `Arc<OptionLock>`.
221    ///
222    /// On successful acquisition a `MutexGuardArc<T>` is returned, representing
223    /// an exclusive read/write lock.
224    pub fn try_get_arc(self: &Arc<Self>) -> Result<MutexGuardArc<T>, OptionLockError> {
225        self.try_get()
226            .map(|guard| MutexGuardArc::new(unsafe { transmute(self.clone()) }, guard))
227    }
228
229    /// Try to store a value, if the slot is currently empty and a lock can be acquired.
230    pub fn try_fill(&self, value: T) -> Result<(), T> {
231        match self
232            .state
233            .compare_exchange(State::FREE, 0, Ordering::AcqRel, Ordering::Relaxed)
234        {
235            Ok(_) => {
236                OptionGuard::new(self, false).replace(value);
237                Ok(())
238            }
239            Err(_) => Err(value),
240        }
241    }
242
243    /// Store the result of an initializer function if the slot is currently empty
244    /// and a lock can be acquired. If a lock cannot be acquired, then the initializer
245    /// is never called.
246    pub fn try_fill_with(&self, f: impl FnOnce() -> T) -> Result<(), OptionLockError> {
247        self.try_lock_none()?.replace(f());
248        Ok(())
249    }
250
251    /// Try to acquire an exclusive lock.
252    ///
253    /// On successful acquisition an `OptionGuard<'_, T>` is returned, representing
254    /// an exclusive read/write lock.
255    pub fn try_lock(&self) -> Result<OptionGuard<'_, T>, OptionLockError> {
256        let state = self.state.fetch_and(!State::FREE, Ordering::Release);
257        if state & State::FREE != 0 {
258            Ok(OptionGuard::new(self, state & State::SOME != 0))
259        } else {
260            Err(OptionLockError::Unavailable)
261        }
262    }
263
264    #[cfg(feature = "alloc")]
265    /// Try to acquire an exclusive lock from a reference to an `Arc<OptionLock>`.
266    ///
267    /// On successful acquisition an `OptionGuardArc<T>` is returned, representing
268    /// an exclusive read/write lock.
269    pub fn try_lock_arc(self: &Arc<Self>) -> Result<OptionGuardArc<T>, OptionLockError> {
270        self.try_lock()
271            .map(|guard| OptionGuardArc::new(self.clone(), guard))
272    }
273
274    /// Try to acquire an exclusive lock when there is no value currently stored.
275    pub fn try_lock_none(&self) -> Result<OptionGuard<'_, T>, OptionLockError> {
276        match self
277            .state
278            .compare_exchange(State::FREE, 0, Ordering::AcqRel, Ordering::Relaxed)
279        {
280            Ok(_) => return Ok(OptionGuard::new(self, false)),
281            Err(State::AVAILABLE) => Err(OptionLockError::FillState),
282            Err(_) => Err(OptionLockError::Unavailable),
283        }
284    }
285
286    #[cfg(feature = "alloc")]
287    /// Try to acquire an exclusive lock when there is no value currently stored.
288    pub fn try_lock_empty_arc(self: &Arc<Self>) -> Result<OptionGuardArc<T>, OptionLockError> {
289        self.try_lock_none()
290            .map(|guard| OptionGuardArc::new(self.clone(), guard))
291    }
292
293    /// Try to take a stored value from the lock.
294    #[inline]
295    pub fn try_take(&self) -> Result<T, OptionLockError> {
296        self.try_get().map(MutexGuard::extract)
297    }
298
299    /// Replace the value in an owned `OptionLock`.
300    pub fn replace(&mut self, value: T) -> Option<T> {
301        let result = if self.is_some() {
302            Some(unsafe { self.as_mut_ptr().read() })
303        } else {
304            self.state.fetch_or(State::SOME, Ordering::Relaxed);
305            None
306        };
307        unsafe { self.as_mut_ptr().write(value) };
308        result
309    }
310
311    /// Take the value (if any) from an owned `OptionLock`.
312    pub fn take(&mut self) -> Option<T> {
313        if self.is_some() {
314            self.state.fetch_and(!State::SOME, Ordering::Relaxed);
315            Some(unsafe { self.as_mut_ptr().read() })
316        } else {
317            None
318        }
319    }
320}
321
322impl<T: Clone> OptionLock<T> {
323    /// Try to clone the contained resource.
324    #[inline]
325    pub fn try_clone(&self) -> Result<T, OptionLockError> {
326        self.try_get().map(|g| (*g).clone())
327    }
328}
329
330impl<T: Copy> OptionLock<T> {
331    /// Try to copy the contained resource.
332    #[inline]
333    pub fn try_copy(&self) -> Result<T, OptionLockError> {
334        self.try_get().map(|g| *g)
335    }
336}
337
338impl<T> Drop for OptionLock<T> {
339    fn drop(&mut self) {
340        if self.state.is_some_mut() {
341            unsafe {
342                drop_in_place(self.as_mut_ptr());
343            }
344        }
345    }
346}
347
348impl<T> From<T> for OptionLock<T> {
349    fn from(data: T) -> Self {
350        Self::new(data)
351    }
352}
353
354impl<T> From<Option<T>> for OptionLock<T> {
355    fn from(data: Option<T>) -> Self {
356        if let Some(data) = data {
357            Self::new(data)
358        } else {
359            Self::empty()
360        }
361    }
362}
363
364impl<T> Into<Option<T>> for OptionLock<T> {
365    fn into(mut self) -> Option<T> {
366        self.take()
367    }
368}
369
370impl<T> Debug for OptionLock<T> {
371    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
372        write!(f, "OptionLock({:?})", &self.state)
373    }
374}
375
376/// An exclusive guard for the value of an [`OptionLock`]
377pub struct OptionGuard<'a, T> {
378    lock: &'a OptionLock<T>,
379    is_some: bool,
380}
381
382impl<'a, T> OptionGuard<'a, T> {
383    #[inline]
384    pub(crate) fn new(lock: &'a OptionLock<T>, is_some: bool) -> Self {
385        Self { lock, is_some }
386    }
387}
388
389impl<T> OptionGuard<'_, T> {
390    /// Obtain a shared reference to the contained value, if any.
391    pub fn as_ref(&self) -> Option<&T> {
392        if self.is_some {
393            Some(unsafe { &*self.lock.as_ptr() })
394        } else {
395            None
396        }
397    }
398
399    /// Obtain an exclusive reference to the contained value, if any.
400    pub fn as_mut(&mut self) -> Option<&mut T> {
401        if self.is_some {
402            Some(unsafe { &mut *self.lock.as_mut_ptr() })
403        } else {
404            None
405        }
406    }
407
408    /// Check if the lock contains `None`.
409    #[inline]
410    pub fn is_none(&self) -> bool {
411        !self.is_some
412    }
413
414    /// Check if the lock contains `Some(T)`.
415    #[inline]
416    pub fn is_some(&self) -> bool {
417        self.is_some
418    }
419
420    /// Replace the value in the lock, returning the previous value, if any.
421    pub fn replace(&mut self, value: T) -> Option<T> {
422        if self.is_some {
423            Some(mem::replace(unsafe { &mut *self.lock.as_mut_ptr() }, value))
424        } else {
425            self.is_some = true;
426            unsafe {
427                self.lock.as_mut_ptr().write(value);
428            }
429            None
430        }
431    }
432
433    /// Take the current value from the lock, if any.
434    pub fn take(&mut self) -> Option<T> {
435        if self.is_some {
436            self.is_some = false;
437            Some(unsafe { self.lock.as_ptr().read() })
438        } else {
439            None
440        }
441    }
442}
443
444impl<T: Debug> Debug for OptionGuard<'_, T> {
445    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
446        f.debug_tuple("OptionGuard").field(&self.as_ref()).finish()
447    }
448}
449
450impl<'a, T> Drop for OptionGuard<'a, T> {
451    fn drop(&mut self) {
452        self.lock.state.store(
453            if self.is_some {
454                State::AVAILABLE
455            } else {
456                State::FREE
457            },
458            Ordering::Release,
459        );
460    }
461}
462
463unsafe impl<T: Send> Send for OptionGuard<'_, T> {}
464unsafe impl<T: Sync> Sync for OptionGuard<'_, T> {}