use core::{fmt, marker::PhantomData, mem::MaybeUninit};
use crate::{
abi,
error::{Error, ErrorCode, ErrorKind, Kind},
time::Timeout,
};
define_error_kind! {
pub enum LockError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(all(not(feature = "none"), feature = "rstr_task"))]
NotSupported,
#[cfg(not(feature = "none"))]
BadId,
#[cfg(any())]
AccessDenied,
#[cfg(not(feature = "none"))]
Released,
#[cfg(not(feature = "none"))]
TerminateRequest,
#[cfg(all(not(feature = "none"), feature = "dcre"))]
Deleted,
#[cfg(not(feature = "none"))]
BadParam,
#[cfg(not(feature = "none"))]
Deadlock,
}
}
impl ErrorKind for LockError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(all(not(feature = "none"), feature = "rstr_task"))]
abi::E_NOSPT => Some(Self::NotSupported(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ID | abi::E_NOEXS => Some(Self::BadId(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_RLWAI => Some(Self::Released(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_RASTER => Some(Self::TerminateRequest(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
#[cfg(all(not(feature = "none"), feature = "dcre"))]
abi::E_DLT => Some(Self::Deleted(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ILUSE => Some(Self::BadParam(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_OBJ => Some(Self::Deadlock(Kind::from_error_code(code))),
_ => None,
}
}
}
define_error_kind! {
pub enum LockTimeoutError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(all(not(feature = "none"), feature = "rstr_task"))]
NotSupported,
#[cfg(not(feature = "none"))]
BadId,
#[cfg(any())]
AccessDenied,
#[cfg(not(feature = "none"))]
Timeout,
#[cfg(not(feature = "none"))]
Released,
#[cfg(not(feature = "none"))]
TerminateRequest,
#[cfg(all(not(feature = "none"), feature = "dcre"))]
Deleted,
#[cfg(not(feature = "none"))]
BadParam,
#[cfg(not(feature = "none"))]
Deadlock,
}
}
impl ErrorKind for LockTimeoutError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(all(not(feature = "none"), feature = "rstr_task"))]
abi::E_NOSPT => Some(Self::NotSupported(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ID | abi::E_NOEXS => Some(Self::BadId(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_TMOUT => Some(Self::Timeout(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_RLWAI => Some(Self::Released(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_RASTER => Some(Self::TerminateRequest(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
#[cfg(all(not(feature = "none"), feature = "dcre"))]
abi::E_DLT => Some(Self::Deleted(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ILUSE => Some(Self::BadParam(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_OBJ => Some(Self::Deadlock(Kind::from_error_code(code))),
_ => None,
}
}
}
define_error_kind! {
pub enum TryLockError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(not(feature = "none"))]
BadId,
#[cfg(any())]
AccessDenied,
#[cfg(not(feature = "none"))]
BadParam,
#[cfg(not(feature = "none"))]
Deadlock,
#[cfg(not(feature = "none"))]
Timeout,
}
}
impl ErrorKind for TryLockError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ID | abi::E_NOEXS => Some(Self::BadId(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ILUSE => Some(Self::BadParam(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_OBJ => Some(Self::Deadlock(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_TMOUT => Some(Self::Timeout(Kind::from_error_code(code))),
_ => None,
}
}
}
define_error_kind! {
pub enum UnlockError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(not(feature = "none"))]
BadId,
#[cfg(any())]
AccessDenied,
#[cfg(not(feature = "none"))]
BadSequence,
}
}
impl ErrorKind for UnlockError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ID | abi::E_NOEXS => Some(Self::BadId(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_OBJ => Some(Self::BadSequence(Kind::from_error_code(code))),
_ => None,
}
}
}
define_error_kind! {
pub enum InitializeError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(not(feature = "none"))]
BadId,
#[cfg(any())]
AccessDenied,
}
}
impl ErrorKind for InitializeError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ID | abi::E_NOEXS => Some(Self::BadId(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
_ => None,
}
}
}
define_error_kind! {
pub enum InfoError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(not(feature = "none"))]
BadId,
#[cfg(any())]
AccessDenied,
}
}
impl ErrorKind for InfoError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ID | abi::E_NOEXS => Some(Self::BadId(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
_ => None,
}
}
}
define_error_kind! {
#[cfg(feature = "dcre")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "dcre")))]
pub enum BuildError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(any())]
AccessDenied,
#[cfg(not(feature = "none"))]
OutOfMemory,
#[cfg(not(feature = "none"))]
BadParam,
}
}
#[cfg(feature = "dcre")]
impl ErrorKind for BuildError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_NOID => Some(Self::OutOfMemory(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_PAR | abi::E_RSATR => Some(Self::BadParam(Kind::from_error_code(code))),
#[cfg(any(
all(feature = "asp3", feature = "subprio"),
feature = "fmp3",
feature = "solid_fmp3"
))]
abi::E_ILUSE => Some(Self::BadParam(Kind::from_error_code(code))),
_ => None,
}
}
}
define_error_kind! {
#[cfg(feature = "dcre")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "dcre")))]
pub enum DeleteError {
#[cfg(not(feature = "none"))]
BadContext,
#[cfg(not(feature = "none"))]
BadId,
#[cfg(any())]
AccessDenied,
#[cfg(not(feature = "none"))]
BadState,
}
}
#[cfg(feature = "dcre")]
impl ErrorKind for DeleteError {
fn from_error_code(code: ErrorCode) -> Option<Self> {
match code.get() {
#[cfg(not(feature = "none"))]
abi::E_CTX => Some(Self::BadContext(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_ID | abi::E_NOEXS => Some(Self::BadId(Kind::from_error_code(code))),
#[cfg(any())]
abi::E_OACV => Some(Self::AccessDenied(Kind::from_error_code(code))),
#[cfg(not(feature = "none"))]
abi::E_OBJ => Some(Self::BadState(Kind::from_error_code(code))),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Info {
#[cfg(not(feature = "none"))]
raw: abi::T_RMTX,
}
impl Info {
#[inline]
pub fn owning_task_id(&self) -> Option<abi::NonNullID> {
match () {
#[cfg(not(feature = "none"))]
() => abi::NonNullID::new(self.raw.htskid),
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
#[inline]
pub fn first_waiting_task_id(&self) -> Option<abi::NonNullID> {
match () {
#[cfg(not(feature = "none"))]
() => abi::NonNullID::new(self.raw.wtskid),
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct MutexRef<'a> {
id: abi::NonNullID,
_phantom: PhantomData<&'a ()>,
}
impl fmt::Debug for MutexRef<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Mutex({})", self.id)
}
}
impl MutexRef<'_> {
#[inline]
pub const unsafe fn from_raw_nonnull(id: abi::NonNullID) -> Self {
Self {
id,
_phantom: PhantomData,
}
}
#[inline]
pub const fn as_raw(self) -> abi::ID {
self.id.get()
}
#[inline]
pub const fn as_raw_nonnull(self) -> abi::NonNullID {
self.id
}
}
impl MutexRef<'_> {
#[inline]
#[doc(alias = "del_mtx")]
#[cfg(feature = "dcre")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "dcre")))]
pub unsafe fn delete(self) -> Result<(), Error<DeleteError>> {
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
Error::err_if_negative(abi::del_mtx(self.as_raw()))?;
Ok(())
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
#[inline]
#[doc(alias = "ref_mtx")]
pub fn info(self) -> Result<Info, Error<InfoError>> {
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
let mut pri = MaybeUninit::uninit();
Error::err_if_negative(abi::ref_mtx(self.as_raw(), pri.as_mut_ptr()))?;
Ok(Info {
raw: pri.assume_init(),
})
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
}
impl MutexRef<'_> {
#[inline]
#[doc(alias = "loc_mtx")]
pub fn lock(self) -> Result<(), Error<LockError>> {
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
Error::err_if_negative(abi::loc_mtx(self.as_raw()))?;
Ok(())
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
#[inline]
#[doc(alias = "tloc_mtx")]
pub fn lock_timeout(self, tmo: Timeout) -> Result<(), Error<LockTimeoutError>> {
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
Error::err_if_negative(abi::tloc_mtx(self.as_raw(), tmo.as_raw()))?;
Ok(())
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
#[inline]
#[doc(alias = "ploc_mtx")]
pub fn try_lock(self) -> Result<(), Error<TryLockError>> {
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
Error::err_if_negative(abi::ploc_mtx(self.as_raw()))?;
Ok(())
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
#[inline]
#[doc(alias = "unl_mtx")]
pub fn unlock(self) -> Result<(), Error<UnlockError>> {
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
Error::err_if_negative(abi::unl_mtx(self.as_raw()))?;
Ok(())
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
#[inline]
#[doc(alias = "ini_mtx")]
pub fn initialize(self) -> Result<(), Error<InitializeError>> {
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
Error::err_if_negative(abi::ini_mtx(self.as_raw()))?;
Ok(())
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
}
#[cfg(feature = "dcre")]
pub use self::owned::*;
#[cfg(feature = "dcre")]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "dcre")))]
mod owned {
use super::*;
use crate::wait::QueueOrder;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "dcre")))]
pub enum PriorityProtection {
None,
Ceiling {
priority: crate::task::Priority,
},
#[cfg(any(feature = "none", all(feature = "solid_asp3", feature = "pi_mutex")))]
#[cfg_attr(
feature = "doc_cfg",
doc(cfg(any(feature = "none", all(feature = "solid_asp3", feature = "pi_mutex"))))
)]
Inherit,
}
impl PriorityProtection {
#[inline]
#[allow(unreachable_code)]
pub const fn inherit() -> Option<Self> {
#[cfg(any(feature = "none", all(feature = "solid_asp3", feature = "pi_mutex")))]
{
return Some(Self::Inherit);
}
None
}
}
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "dcre")))]
#[must_use = "`Builder` creates nothing unless you call `.finish()`"]
pub struct Builder {
#[cfg(not(feature = "none"))]
raw: abi::T_CMTX,
priority_protection: PriorityProtection,
}
impl Mutex {
#[inline]
#[doc(alias = "acre_mtx")]
pub fn build() -> Builder {
Builder {
#[cfg(not(feature = "none"))]
raw: abi::T_CMTX {
mtxatr: abi::TA_NULL,
ceilpri: 0,
},
priority_protection: PriorityProtection::None,
}
}
}
impl Builder {
#[inline]
pub fn priority_protection(self, value: PriorityProtection) -> Builder {
Builder {
#[cfg(not(feature = "none"))]
priority_protection: value,
..self
}
}
#[inline]
pub fn queue_order(self, value: QueueOrder) -> Builder {
Builder {
#[cfg(not(feature = "none"))]
raw: abi::T_CMTX {
mtxatr: value.as_raw_atr(),
..self.raw
},
..self
}
}
}
impl Builder {
#[allow(unused_mut)]
pub fn finish(mut self) -> Result<Mutex, Error<BuildError>> {
match self.priority_protection {
#[cfg(not(feature = "none"))]
PriorityProtection::None => {}
#[cfg(not(feature = "none"))]
PriorityProtection::Ceiling { priority } => {
self.raw.mtxatr = abi::TA_CEILING;
self.raw.ceilpri = priority;
}
#[cfg(all(feature = "solid_asp3", feature = "pi_mutex"))]
PriorityProtection::Inherit => {
self.raw.mtxatr = abi::TA_INHERIT;
}
#[cfg(feature = "none")]
_ => unimplemented!(),
}
match () {
#[cfg(not(feature = "none"))]
() => unsafe {
let id = Error::err_if_negative(abi::acre_mtx(&self.raw))?;
Ok(Mutex::from_raw_nonnull(abi::NonNullID::new_unchecked(id)))
},
#[cfg(feature = "none")]
() => unimplemented!(),
}
}
}
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "dcre")))]
pub struct Mutex(MutexRef<'static>);
impl fmt::Debug for Mutex {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Drop for Mutex {
#[inline]
fn drop(&mut self) {
unsafe { self.0.delete().unwrap() };
}
}
impl Mutex {
#[inline]
pub const unsafe fn from_raw_nonnull(id: abi::NonNullID) -> Self {
Self(unsafe { MutexRef::from_raw_nonnull(id) })
}
#[inline]
pub const fn leak<'a>(self) -> MutexRef<'a> {
let out = self.0;
core::mem::forget(self);
out
}
#[inline]
pub const fn as_raw(&self) -> abi::ID {
self.0.as_raw()
}
#[inline]
pub const fn as_raw_nonnull(&self) -> abi::NonNullID {
self.0.as_raw_nonnull()
}
#[inline]
pub const fn as_ref(&self) -> MutexRef<'_> {
self.0
}
}
}