trait Mu {
type Guard<'a>
where
Self: 'a;
fn lock_me(&self) -> Self::Guard<'_>;
}
#[cfg(feature = "parking_lot")]
impl<T: ?Sized> Mu for parking_lot::Mutex<T> {
type Guard<'a>
= parking_lot::MutexGuard<'a, T>
where
Self: 'a;
fn lock_me(&self) -> Self::Guard<'_> {
self.lock()
}
}
#[cfg(not(feature = "parking_lot"))]
impl<T: ?Sized> Mu for std::sync::Mutex<T> {
type Guard<'a>
= std::sync::MutexGuard<'a, T>
where
Self: 'a;
fn lock_me(&self) -> Self::Guard<'_> {
self.lock().unwrap_or_else(|e| e.into_inner())
}
}
#[cfg(feature = "parking_lot")]
use parking_lot::{Condvar, Mutex};
#[cfg(not(feature = "triomphe"))]
use std::sync::Arc;
#[cfg(not(feature = "parking_lot"))]
use std::sync::{Condvar, Mutex};
#[cfg(feature = "triomphe")]
use triomphe::Arc;
struct Inner {
cvar: Condvar,
count: Mutex<usize>,
}
pub struct WaitGroup {
inner: Arc<Inner>,
}
impl Default for WaitGroup {
fn default() -> Self {
Self {
inner: Arc::new(Inner {
cvar: Condvar::new(),
count: Mutex::new(0),
}),
}
}
}
impl From<usize> for WaitGroup {
fn from(count: usize) -> Self {
Self {
inner: Arc::new(Inner {
cvar: Condvar::new(),
count: Mutex::new(count),
}),
}
}
}
impl Clone for WaitGroup {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
}
}
}
impl std::fmt::Debug for WaitGroup {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let count = self.inner.count.lock_me();
f.debug_struct("WaitGroup").field("count", &*count).finish()
}
}
impl core::ops::AddAssign<usize> for WaitGroup {
fn add_assign(&mut self, rhs: usize) {
self.add(rhs);
}
}
impl WaitGroup {
pub fn new() -> Self {
Self::default()
}
pub fn add(&self, num: usize) -> Self {
let mut ctr = self.inner.count.lock_me();
*ctr = ctr.checked_add(num).expect("WaitGroup counter overflow");
Self {
inner: self.inner.clone(),
}
}
pub fn done(&self) -> usize {
let mut val = self.inner.count.lock_me();
*val = if val.eq(&1) {
self.inner.cvar.notify_all();
0
} else if val.eq(&0) {
0
} else {
*val - 1
};
*val
}
pub fn remaining(&self) -> usize {
*self.inner.count.lock_me()
}
pub fn wait(&self) {
let mut ctr = self.inner.count.lock_me();
if ctr.eq(&0) {
return;
}
while *ctr > 0 {
#[cfg(feature = "parking_lot")]
{
self.inner.cvar.wait(&mut ctr);
}
#[cfg(not(feature = "parking_lot"))]
{
ctr = self.inner.cvar.wait(ctr).unwrap_or_else(|e| e.into_inner());
}
}
}
}