#![allow(unsafe_code)]
pub mod guard;
use core::{cell::UnsafeCell, fmt, marker::PhantomData};
use crate::{id::LockId, level::IsLevel, raw_mutex::RawMutex};
#[cfg(feature = "std")]
use crate::level::Base;
#[cfg(feature = "escape-hatch")]
use guard::MutexGuard;
#[cfg(feature = "std")]
pub struct Mutex<T, Lvl: IsLevel = Base, R: RawMutex = crate::raw_mutex::std_mutex::StdMutex> {
id: LockId,
pub(crate) raw: R,
pub(crate) data: UnsafeCell<T>,
_level: PhantomData<Lvl>,
}
#[cfg(not(feature = "std"))]
pub struct Mutex<T, Lvl: IsLevel, R: RawMutex> {
id: LockId,
pub(crate) raw: R,
pub(crate) data: UnsafeCell<T>,
_level: PhantomData<Lvl>,
}
impl<T, Lvl: IsLevel, R: RawMutex> Mutex<T, Lvl, R> {
#[must_use]
pub fn new(data: T) -> Self {
Self {
id: LockId::next(),
raw: RawMutex::new(),
data: UnsafeCell::new(data),
_level: PhantomData,
}
}
#[must_use]
pub const fn id(&self) -> LockId {
self.id
}
#[must_use]
pub const fn get_mut(&mut self) -> &mut T {
self.data.get_mut()
}
#[must_use]
pub fn into_inner(self) -> T {
self.data.into_inner()
}
}
#[cfg(feature = "std")]
impl<T> Mutex<T> {
#[must_use]
pub fn new_higher<Parents: NewHigher<T, crate::raw_mutex::std_mutex::StdMutex>>(
data: T,
parents: Parents,
) -> Mutex<T, Parents::NextLvl, crate::raw_mutex::std_mutex::StdMutex> {
parents.new_higher(data)
}
}
#[cfg(feature = "escape-hatch")]
impl<T, Lvl: IsLevel, R: RawMutex> Mutex<T, Lvl, R> {
pub fn unchecked_lock(&self) -> MutexGuard<'_, R, T> {
let raw_guard = self.raw.lock();
MutexGuard {
data: &self.data,
_raw_guard: raw_guard,
}
}
}
impl<T: fmt::Debug, Lvl: IsLevel, R: RawMutex> fmt::Debug for Mutex<T, Lvl, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Mutex")
.field("id", &self.id)
.finish_non_exhaustive()
}
}
unsafe impl<T: Send, Lvl: IsLevel, R: RawMutex + Send> Send for Mutex<T, Lvl, R> {}
unsafe impl<T: Send, Lvl: IsLevel, R: RawMutex + Sync> Sync for Mutex<T, Lvl, R> {}
use crate::level::MutexLevel;
impl<T, Lvl: IsLevel, R: RawMutex> MutexLevel for &Mutex<T, Lvl, R> {
type Lvl = Lvl;
}
#[cfg(target_has_atomic = "ptr")]
impl<T, Lvl: IsLevel, R: RawMutex> MutexLevel for &alloc::sync::Arc<Mutex<T, Lvl, R>> {
type Lvl = Lvl;
}
impl<T, Lvl: IsLevel, R: RawMutex> MutexLevel for &alloc::rc::Rc<Mutex<T, Lvl, R>> {
type Lvl = Lvl;
}
impl<T, Lvl: IsLevel, R: RawMutex> MutexLevel for &alloc::boxed::Box<Mutex<T, Lvl, R>> {
type Lvl = Lvl;
}
use crate::level::NewHigher;
impl<ParentT, ChildT, Lvl: IsLevel + crate::level::NextLevel, R: RawMutex> NewHigher<ChildT, R>
for Mutex<ParentT, Lvl, R>
{
type NextLvl = Lvl::Next;
fn new_higher(&self, data: ChildT) -> Mutex<ChildT, Lvl::Next, R> {
Mutex {
id: LockId::next(),
raw: RawMutex::new(),
data: UnsafeCell::new(data),
_level: PhantomData,
}
}
}
impl<ChildT, R: RawMutex, T: NewHigher<ChildT, R> + ?Sized> NewHigher<ChildT, R> for &T {
type NextLvl = T::NextLvl;
fn new_higher(&self, data: ChildT) -> Mutex<ChildT, T::NextLvl, R> {
T::new_higher(self, data)
}
}
#[cfg(target_has_atomic = "ptr")]
impl<ChildT, R: RawMutex, T: NewHigher<ChildT, R>> NewHigher<ChildT, R> for alloc::sync::Arc<T> {
type NextLvl = T::NextLvl;
fn new_higher(&self, data: ChildT) -> Mutex<ChildT, T::NextLvl, R> {
T::new_higher(self, data)
}
}
impl<ChildT, R: RawMutex, T: NewHigher<ChildT, R>> NewHigher<ChildT, R> for alloc::rc::Rc<T> {
type NextLvl = T::NextLvl;
fn new_higher(&self, data: ChildT) -> Mutex<ChildT, T::NextLvl, R> {
T::new_higher(self, data)
}
}
impl<ChildT, R: RawMutex, T: NewHigher<ChildT, R>> NewHigher<ChildT, R> for alloc::boxed::Box<T> {
type NextLvl = T::NextLvl;
fn new_higher(&self, data: ChildT) -> Mutex<ChildT, T::NextLvl, R> {
T::new_higher(self, data)
}
}
macro_rules! impl_new_higher_tuple {
($a_wrapper:ty, $b_wrapper:ty) => {
impl<
ChildT,
ParentT1,
ParentT2,
Lvl1: IsLevel + crate::level::MaxLevel<Lvl2>,
Lvl2: IsLevel,
R: RawMutex,
> NewHigher<ChildT, R> for (&$a_wrapper, &$b_wrapper)
where
<Lvl1 as crate::level::MaxLevel<Lvl2>>::Max: crate::level::NextLevel,
{
type NextLvl =
<<Lvl1 as crate::level::MaxLevel<Lvl2>>::Max as crate::level::NextLevel>::Next;
fn new_higher(&self, data: ChildT) -> Mutex<ChildT, Self::NextLvl, R> {
Mutex {
id: LockId::next(),
raw: RawMutex::new(),
data: UnsafeCell::new(data),
_level: PhantomData,
}
}
}
};
}
impl_new_higher_tuple!(Mutex<ParentT1, Lvl1, R>, Mutex<ParentT2, Lvl2, R>);
impl_new_higher_tuple!(Mutex<ParentT1, Lvl1, R>, alloc::rc::Rc<Mutex<ParentT2, Lvl2, R>>);
impl_new_higher_tuple!(Mutex<ParentT1, Lvl1, R>, alloc::boxed::Box<Mutex<ParentT2, Lvl2, R>>);
impl_new_higher_tuple!(alloc::rc::Rc<Mutex<ParentT1, Lvl1, R>>, Mutex<ParentT2, Lvl2, R>);
impl_new_higher_tuple!(
alloc::rc::Rc<Mutex<ParentT1, Lvl1, R>>,
alloc::rc::Rc<Mutex<ParentT2, Lvl2, R>>
);
impl_new_higher_tuple!(
alloc::rc::Rc<Mutex<ParentT1, Lvl1, R>>,
alloc::boxed::Box<Mutex<ParentT2, Lvl2, R>>
);
impl_new_higher_tuple!(alloc::boxed::Box<Mutex<ParentT1, Lvl1, R>>, Mutex<ParentT2, Lvl2, R>);
impl_new_higher_tuple!(
alloc::boxed::Box<Mutex<ParentT1, Lvl1, R>>,
alloc::rc::Rc<Mutex<ParentT2, Lvl2, R>>
);
impl_new_higher_tuple!(
alloc::boxed::Box<Mutex<ParentT1, Lvl1, R>>,
alloc::boxed::Box<Mutex<ParentT2, Lvl2, R>>
);
#[cfg(target_has_atomic = "ptr")]
impl_new_higher_tuple!(Mutex<ParentT1, Lvl1, R>, alloc::sync::Arc<Mutex<ParentT2, Lvl2, R>>);
#[cfg(target_has_atomic = "ptr")]
impl_new_higher_tuple!(alloc::sync::Arc<Mutex<ParentT1, Lvl1, R>>, Mutex<ParentT2, Lvl2, R>);
#[cfg(target_has_atomic = "ptr")]
impl_new_higher_tuple!(
alloc::sync::Arc<Mutex<ParentT1, Lvl1, R>>,
alloc::sync::Arc<Mutex<ParentT2, Lvl2, R>>
);
#[cfg(target_has_atomic = "ptr")]
impl_new_higher_tuple!(
alloc::sync::Arc<Mutex<ParentT1, Lvl1, R>>,
alloc::rc::Rc<Mutex<ParentT2, Lvl2, R>>
);
#[cfg(target_has_atomic = "ptr")]
impl_new_higher_tuple!(
alloc::sync::Arc<Mutex<ParentT1, Lvl1, R>>,
alloc::boxed::Box<Mutex<ParentT2, Lvl2, R>>
);
#[cfg(target_has_atomic = "ptr")]
impl_new_higher_tuple!(
alloc::rc::Rc<Mutex<ParentT1, Lvl1, R>>,
alloc::sync::Arc<Mutex<ParentT2, Lvl2, R>>
);
#[cfg(target_has_atomic = "ptr")]
impl_new_higher_tuple!(
alloc::boxed::Box<Mutex<ParentT1, Lvl1, R>>,
alloc::sync::Arc<Mutex<ParentT2, Lvl2, R>>
);