1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
//! Traits for items that are "Lockable", e.g., `Mutex`es.
#![no_std]
extern crate spin;
extern crate sync_irq;
use core::ops::{Deref, DerefMut};
/// A trait representing types that can be locked, e.g., `Mutex`es.
///
/// It also can represent types like `RwLock` (read-write lock)
/// that allow multiple concurrent readers but only one concurrent writer.
///
/// Note: an optional design choice would be to remove the generic `T` parameter
/// and instead assign it as an associated type, e.g., `type Inner: 't`.
///
pub trait Lockable<'t, T: 't + ?Sized> {
/// The immutable "guard" type returned by the [`Self::lock()`] function.
type Guard: Deref<Target = T>;
/// The mutable "guard" type returned by the [`Self::lock_mut()`] function.
///
/// For locks like `RwLock` that differentiate between read-only and read-write locks,
/// this should be set to the read-write guard type.
/// For locks like `Mutex` that only have one locking function,
/// this should be set to the same type as [`Self::Guard`].
type GuardMut: DerefMut<Target = T>;
/// Obtain the lock in a blocking fashion,
/// returning an immutable guard that dereferences into the inner data.
fn lock(&'t self) -> Self::Guard;
/// Attempt to obtain the lock in a non-blocking fashion,
/// returning an immutable guard that dereferences into the inner data.
///
/// If the lock is already locked, this returns `None`.
fn try_lock(&'t self) -> Option<Self::Guard>;
/// Obtain the lock in a blocking fashion,
/// returning a mutable guard that dereferences into the inner data.
fn lock_mut(&'t self) -> Self::GuardMut;
/// Attempt to obtain the lock in a non-blocking fashion,
/// returning a mutable guard that dereferences into the inner data.
///
/// If the lock is already locked, this returns `None`.
fn try_lock_mut(&'t self) -> Option<Self::GuardMut>;
/// Returns `true` if this lock is currently locked.
///
/// For types like `RwLock` that can lock in a read-only or read-write manner,
/// this should return `true` if the singular writer lock is obtained,
/// and `false` if only the reader lock is obtained.
fn is_locked(&self) -> bool;
/// Returns a mutable reference to the underlying data.
fn get_mut(&'t mut self) -> &'t mut T;
}
/// An extension of the [`Lockable`] trait that adds the `into_inner()` method
/// only for types `T` that are `Sized`.
pub trait LockableSized<'t, T: 't + Sized>: Lockable<'t, T> {
/// Consumes the lock, returning the underlying data.
fn into_inner(self) -> T;
}
/// Implement `Lockable` for [`spin::Mutex`].
impl<'t, T> Lockable<'t, T> for spin::Mutex<T> where T: 't + ?Sized {
type Guard = spin::MutexGuard<'t, T>;
type GuardMut = Self::Guard;
fn lock(&'t self) -> Self::Guard { self.lock() }
fn try_lock(&'t self) -> Option<Self::Guard> { self.try_lock() }
fn lock_mut(&'t self) -> Self::GuardMut { self.lock() }
fn try_lock_mut(&'t self) -> Option<Self::GuardMut> { self.try_lock() }
fn is_locked(&self) -> bool { self.is_locked() }
fn get_mut(&'t mut self) -> &mut T { self.get_mut() }
}
/// Implement `LockableSized` for [`spin::Mutex`].
impl<'t, T> LockableSized<'t, T> for spin::Mutex<T> where T: 't + Sized {
fn into_inner(self) -> T { self.into_inner() }
}
/// Implement `Lockable` for [`spin::RwLock`].
impl<'t, T> Lockable<'t, T> for spin::RwLock<T> where T: 't + ?Sized {
type Guard = spin::RwLockReadGuard<'t, T>;
type GuardMut = spin::RwLockWriteGuard<'t, T>;
fn lock(&'t self) -> Self::Guard { self.read() }
fn try_lock(&'t self) -> Option<Self::Guard> { self.try_read() }
fn lock_mut(&'t self) -> Self::GuardMut { self.write() }
fn try_lock_mut(&'t self) -> Option<Self::GuardMut> { self.try_write() }
fn is_locked(&self) -> bool { self.writer_count() > 0 }
fn get_mut(&'t mut self) -> &mut T { self.get_mut() }
}
/// Implement `LockableSized` for [`spin::RwLock`].
impl<'t, T> LockableSized<'t, T> for spin::RwLock<T> where T: 't + Sized {
fn into_inner(self) -> T { self.into_inner() }
}
/// Implement `Lockable` for [`sync_irq::IrqSafeMutex`].
impl<'t, T> Lockable<'t, T> for sync_irq::IrqSafeMutex<T> where T: 't {
type Guard = sync_irq::IrqSafeMutexGuard<'t, T>;
type GuardMut = Self::Guard;
fn lock(&'t self) -> Self::Guard { self.lock() }
fn try_lock(&'t self) -> Option<Self::Guard> { self.try_lock() }
fn lock_mut(&'t self) -> Self::GuardMut { self.lock() }
fn try_lock_mut(&'t self) -> Option<Self::GuardMut> { self.try_lock() }
fn is_locked(&self) -> bool { self.is_locked() }
fn get_mut(&'t mut self) -> &mut T { self.get_mut() }
}
/// Implement `LockableSized` for [`sync_irq::IrqSafeMutex`].
impl<'t, T> LockableSized<'t, T> for sync_irq::IrqSafeMutex<T> where T: 't + Sized {
fn into_inner(self) -> T { self.into_inner() }
}
/// Implement `Lockable` for [`sync_irq::IrqSafeRwLock`].
impl<'t, T> Lockable<'t, T> for sync_irq::IrqSafeRwLock<T> where T: 't {
type Guard = sync_irq::IrqSafeRwLockReadGuard<'t, T>;
type GuardMut = sync_irq::IrqSafeRwLockWriteGuard<'t, T>;
fn lock(&'t self) -> Self::Guard { self.read() }
fn try_lock(&'t self) -> Option<Self::Guard> { self.try_read() }
fn lock_mut(&'t self) -> Self::GuardMut { self.write() }
fn try_lock_mut(&'t self) -> Option<Self::GuardMut> { self.try_write() }
fn is_locked(&self) -> bool { self.writer_count() > 0 }
fn get_mut(&'t mut self) -> &mut T { self.get_mut() }
}
/// Implement `LockableSized` for [`sync_irq::IrqSafeRwLock`].
impl<'t, T> LockableSized<'t, T> for sync_irq::IrqSafeRwLock<T> where T: 't + Sized {
fn into_inner(self) -> T { self.into_inner() }
}