use core::{fmt, ops::DerefMut, time::Duration};
use crate::{
sync::{
nonpoison::{mutex, mutex::MutexGuard},
RawMutex, WaitTimeoutResult,
},
sys::sync as sys,
time::Instant,
};
pub struct Condvar {
inner: sys::Condvar,
}
impl core::panic::UnwindSafe for Condvar {}
impl core::panic::RefUnwindSafe for Condvar {}
impl Condvar {
#[must_use]
#[inline]
pub const fn new() -> Condvar {
Condvar {
inner: sys::Condvar::new(),
}
}
pub fn notify_one(&self) {
self.inner.notify_one()
}
pub fn notify_all(&self) {
self.inner.notify_all()
}
}
impl Condvar {
pub fn wait<'a, T, M: RawMutex>(&self, guard: &mut MutexGuard<'a, T, M>) {
let lock = mutex::guard_lock(guard);
unsafe { self.inner.wait(lock) };
}
pub fn wait_while<'a, T, F, M>(&self, guard: &mut MutexGuard<'a, T, M>, mut condition: F)
where
F: FnMut(&mut T) -> bool,
M: RawMutex,
{
while condition(&mut *guard) {
self.wait(guard);
}
}
pub fn wait_timeout<'a, T, M: RawMutex>(
&self, guard: &mut MutexGuard<'a, T, M>, dur: Duration,
) -> WaitTimeoutResult {
let success = unsafe {
let lock = mutex::guard_lock(guard);
self.inner.wait_timeout(lock, dur)
};
WaitTimeoutResult(!success)
}
pub fn wait_timeout_while<'a, T, F, M>(
&self, guard: &mut MutexGuard<'a, T, M>, dur: Duration, mut condition: F,
) -> WaitTimeoutResult
where
F: FnMut(&mut T) -> bool,
M: RawMutex,
{
let start = Instant::now();
while condition(guard.deref_mut()) {
let timeout = match dur.checked_sub(start.elapsed()) {
Some(timeout) => timeout,
None => return WaitTimeoutResult(true),
};
self.wait_timeout(guard, timeout);
}
WaitTimeoutResult(false)
}
}
impl fmt::Debug for Condvar {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Condvar").finish_non_exhaustive()
}
}
impl Default for Condvar {
fn default() -> Self {
Condvar::new()
}
}