diff options
Diffstat (limited to 'src/lock.rs')
| -rw-r--r-- | src/lock.rs | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/src/lock.rs b/src/lock.rs index 45dd1ad..fb74f25 100644 --- a/src/lock.rs +++ b/src/lock.rs @@ -6,18 +6,56 @@ pub struct Lock { is_locked: AtomicBool, } +#[derive(Debug)] +pub struct Key<'a> { + lock: &'a Lock, +} + +impl<'a> Key<'a> { + fn new(lock: &'a Lock) -> Self { + Self { lock } + } +} + +impl<'a> Drop for Key<'a> { + fn drop(&mut self) { + // safety: this key will soon be destroyed + unsafe { self.lock.force_unlock() } + } +} + impl Lock { + /// Create a new unlocked `Lock`. pub const fn new() -> Self { Self { is_locked: AtomicBool::new(false), } } - pub fn try_lock(&self) -> bool { - !self.is_locked.fetch_or(true, Ordering::Acquire) + /// Attempt to lock the `Lock`. + /// + /// If the lock is already locked, then this'll return false. If it is + /// unlocked, it'll return true. If the lock is currently unlocked, then it + /// will be locked after this function is called. + /// + /// This is not a fair lock. It is not recommended to call this function + /// repeatedly in a loop. + pub fn try_lock(&self) -> Option<Key> { + (!self.is_locked.fetch_or(true, Ordering::Acquire)).then_some(Key::new(self)) } - pub fn unlock(&self) { + /// Unlock the lock, without a key. + /// + /// # Safety + /// + /// This should only be called if the key to the lock has been "lost". That + /// means the program no longer has a reference to the key, but it has not + /// been dropped. + unsafe fn force_unlock(&self) { self.is_locked.store(false, Ordering::Release) } + + pub fn unlock(key: Key) { + drop(key) + } } |
