use crate::mutex::{MutexGuard, RawMutex, RawMutexTimed};
use core::{fmt, ops::DerefMut};
pub unsafe trait RawCondvar {
#[allow(clippy::declare_interior_mutable_const)]
const INIT: Self;
type RawMutex: RawMutex;
unsafe fn wait(&self, mutex: &Self::RawMutex);
fn notify_one(&self) -> bool;
fn notify_all(&self) -> usize;
}
pub unsafe trait RawCondvarTimed: RawCondvar
where
Self::RawMutex: RawMutexTimed,
{
fn checked_duration_to_instant(
timeout: &<Self::RawMutex as RawMutexTimed>::Duration,
) -> Option<<Self::RawMutex as RawMutexTimed>::Instant>;
unsafe fn wait_until(
&self,
mutex: &Self::RawMutex,
timeout: &<Self::RawMutex as RawMutexTimed>::Instant,
) -> bool;
unsafe fn wait_for(
&self,
mutex: &Self::RawMutex,
timeout: &<Self::RawMutex as RawMutexTimed>::Duration,
) -> bool {
unsafe {
match Self::checked_duration_to_instant(timeout) {
Some(timeout) => self.wait_until(mutex, &timeout),
None => {
<Self as RawCondvar>::wait(&self, mutex);
false
}
}
}
}
}
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub struct WaitTimeoutResult(bool);
impl WaitTimeoutResult {
#[inline]
pub fn timed_out(self) -> bool {
self.0
}
}
pub struct Condvar<C> {
inner: C,
}
impl<C: RawCondvar> Condvar<C> {
#[inline]
pub const fn new() -> Condvar<C> {
Condvar { inner: C::INIT }
}
#[inline]
pub fn raw(&self) -> &C {
&self.inner
}
#[inline]
pub fn notify_one(&self) -> bool {
self.inner.notify_one()
}
#[inline]
pub fn notify_all(&self) -> usize {
self.inner.notify_all()
}
#[inline]
pub fn wait<T: ?Sized>(&self, mutex_guard: &mut MutexGuard<'_, C::RawMutex, T>) {
unsafe {
self.inner.wait(MutexGuard::mutex(mutex_guard).raw());
}
}
#[inline]
pub fn wait_while<T, F>(
&self,
mutex_guard: &mut MutexGuard<'_, C::RawMutex, T>,
mut condition: F,
) where
T: ?Sized,
F: FnMut(&mut T) -> bool,
{
while condition(mutex_guard.deref_mut()) {
unsafe {
self.inner.wait(MutexGuard::mutex(mutex_guard).raw());
}
}
}
}
impl<R: RawMutexTimed, C: RawCondvarTimed<RawMutex = R>> Condvar<C> {
#[inline]
pub fn wait_until<T: ?Sized>(
&self,
mutex_guard: &mut MutexGuard<'_, C::RawMutex, T>,
timeout: <C::RawMutex as RawMutexTimed>::Instant,
) -> WaitTimeoutResult {
WaitTimeoutResult(unsafe {
self.inner
.wait_until(MutexGuard::mutex(mutex_guard).raw(), &timeout)
})
}
#[inline]
pub fn wait_for<T: ?Sized>(
&self,
mutex_guard: &mut MutexGuard<'_, C::RawMutex, T>,
timeout: <C::RawMutex as RawMutexTimed>::Duration,
) -> WaitTimeoutResult {
WaitTimeoutResult(unsafe {
self.inner
.wait_for(MutexGuard::mutex(mutex_guard).raw(), &timeout)
})
}
#[inline]
pub fn wait_while_until<T, F>(
&self,
mutex_guard: &mut MutexGuard<'_, C::RawMutex, T>,
mut condition: F,
timeout: <C::RawMutex as RawMutexTimed>::Instant,
) -> WaitTimeoutResult
where
T: ?Sized,
F: FnMut(&mut T) -> bool,
{
let mut result = WaitTimeoutResult(false);
while !result.timed_out() && condition(mutex_guard.deref_mut()) {
result = WaitTimeoutResult(unsafe {
self.inner
.wait_until(MutexGuard::mutex(mutex_guard).raw(), &timeout)
});
}
result
}
#[inline]
pub fn wait_while_for<T: ?Sized, F>(
&self,
mutex_guard: &mut MutexGuard<'_, C::RawMutex, T>,
condition: F,
timeout: <C::RawMutex as RawMutexTimed>::Duration,
) -> WaitTimeoutResult
where
F: FnMut(&mut T) -> bool,
{
match C::checked_duration_to_instant(&timeout) {
Some(timeout) => self.wait_while_until(mutex_guard, condition, timeout),
None => {
self.wait_while(mutex_guard, condition);
WaitTimeoutResult(false)
}
}
}
}
impl<C: RawCondvar> Default for Condvar<C> {
#[inline]
fn default() -> Condvar<C> {
Condvar::new()
}
}
impl<C> fmt::Debug for Condvar<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("Condvar { .. }")
}
}