use core::{
fmt,
ops::{Deref, DerefMut},
};
use super::{
RawRwSemaphore, RtCriticalGuard, RwSemaphore, RwSemaphoreReadGuard, RwSemaphoreWriteGuard,
};
pub struct SpinRwLock<T: ?Sized> {
lock: RwSemaphore<T>,
}
#[must_use]
pub struct SpinRwLockReadGuard<'a, T: ?Sized> {
migration: Option<RtCriticalGuard>,
owner: RwSemaphoreReadGuard<'a, T>,
}
#[must_use]
pub struct SpinRwLockWriteGuard<'a, T: ?Sized> {
migration: Option<RtCriticalGuard>,
owner: RwSemaphoreWriteGuard<'a, T>,
}
impl<T> SpinRwLock<T> {
pub const fn new(value: T) -> Self {
Self {
lock: RwSemaphore::const_new(RawRwSemaphore::with_wait_state(true), value),
}
}
pub fn into_inner(self) -> T {
self.lock.into_inner()
}
}
impl<T: ?Sized> SpinRwLock<T> {
pub fn read(&self) -> SpinRwLockReadGuard<'_, T> {
crate::thread::current::validate_rt_lock_context()
.expect("RT rwlock requires task context");
let owner = self.lock.read();
let migration = RtCriticalGuard::new().expect("RT reader migration pin");
SpinRwLockReadGuard {
migration: Some(migration),
owner,
}
}
pub fn write(&self) -> SpinRwLockWriteGuard<'_, T> {
crate::thread::current::validate_rt_lock_context()
.expect("RT rwlock requires task context");
let owner = self.lock.write();
let migration = RtCriticalGuard::new().expect("RT writer migration pin");
SpinRwLockWriteGuard {
migration: Some(migration),
owner,
}
}
pub fn try_read(&self) -> Option<SpinRwLockReadGuard<'_, T>> {
crate::thread::current::validate_rt_lock_context().ok()?;
let owner = self.lock.try_read()?;
let migration = RtCriticalGuard::new().expect("RT reader migration pin");
Some(SpinRwLockReadGuard {
migration: Some(migration),
owner,
})
}
pub fn try_write(&self) -> Option<SpinRwLockWriteGuard<'_, T>> {
crate::thread::current::validate_rt_lock_context().ok()?;
let owner = self.lock.try_write()?;
let migration = RtCriticalGuard::new().expect("RT writer migration pin");
Some(SpinRwLockWriteGuard {
migration: Some(migration),
owner,
})
}
pub fn read_irqsave(&self) -> SpinRwLockReadGuard<'_, T> {
self.read()
}
pub fn write_irqsave(&self) -> SpinRwLockWriteGuard<'_, T> {
self.write()
}
pub fn try_read_irqsave(&self) -> Option<SpinRwLockReadGuard<'_, T>> {
self.try_read()
}
pub fn try_write_irqsave(&self) -> Option<SpinRwLockWriteGuard<'_, T>> {
self.try_write()
}
pub fn get_mut(&mut self) -> &mut T {
self.lock.get_mut()
}
}
impl<T: ?Sized> Deref for SpinRwLockReadGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.owner
}
}
impl<T: ?Sized> Deref for SpinRwLockWriteGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
&self.owner
}
}
impl<T: ?Sized> DerefMut for SpinRwLockWriteGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
&mut self.owner
}
}
impl<T: ?Sized> Drop for SpinRwLockReadGuard<'_, T> {
fn drop(&mut self) {
drop(self.migration.take());
}
}
impl<T: ?Sized> Drop for SpinRwLockWriteGuard<'_, T> {
fn drop(&mut self) {
drop(self.migration.take());
}
}
impl<T: Default> Default for SpinRwLock<T> {
fn default() -> Self {
Self::new(T::default())
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for SpinRwLock<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.lock.fmt(f)
}
}