use std::{
ops::{Deref, DerefMut},
panic::Location,
};
pub use crate::common::error::NotAvailable;
use crate::{
backend::sync::{Mutex as NativeMutex, MutexGuard as NativeGuard},
flash::diag::{self, PrimEntry, PrimKind},
sync::Arc,
};
pub struct Mutex<T> {
inner: NativeMutex<T>,
meta: Option<Arc<PrimEntry>>,
}
impl<T> Mutex<T> {
#[track_caller]
#[inline]
pub fn new(value: T) -> Self {
let meta = diag::register(PrimKind::Mutex, None, Location::caller());
Self {
meta,
inner: NativeMutex::new(value),
}
}
#[track_caller]
#[inline]
pub fn lock(&self) -> MutexGuard<'_, T> {
let at = Location::caller();
if let Some(m) = &self.meta {
m.enter_pending(at);
}
let inner = self.inner.lock();
if let Some(m) = &self.meta {
m.acquired(at);
}
MutexGuard {
inner,
at,
meta: self.meta.as_deref(),
}
}
#[track_caller]
#[inline]
pub fn try_lock(&self) -> Result<MutexGuard<'_, T>, NotAvailable> {
let at = Location::caller();
let inner = self.inner.try_lock()?;
if let Some(m) = &self.meta {
m.acquired(at);
}
Ok(MutexGuard {
inner,
at,
meta: self.meta.as_deref(),
})
}
}
impl<T: Default> Default for Mutex<T> {
fn default() -> Self {
Self::new(T::default())
}
}
#[derive(fieldwork::Fieldwork)]
#[fieldwork(opt_in, get)]
pub struct MutexGuard<'a, T> {
#[field(get = site, vis = "pub(in crate::flash)")]
at: &'static Location<'static>,
inner: NativeGuard<'a, T>,
#[field(get, vis = "pub(in crate::flash)")]
meta: Option<&'a PrimEntry>,
}
impl<'a, T> MutexGuard<'a, T> {
#[inline]
pub(in crate::flash) fn native_mut(&mut self) -> &mut NativeGuard<'a, T> {
&mut self.inner
}
#[inline]
pub fn unlocked<F: FnOnce()>(&mut self, f: F) {
if let Some(m) = self.meta {
m.released();
}
self.inner.unlocked(f);
if let Some(m) = self.meta {
m.acquired(self.at);
}
}
}
impl<T> Drop for MutexGuard<'_, T> {
#[inline]
fn drop(&mut self) {
if let Some(m) = self.meta {
m.released();
}
}
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
#[inline]
fn deref(&self) -> &T {
&self.inner
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
#[inline]
fn deref_mut(&mut self) -> &mut T {
&mut self.inner
}
}