use std::{
sync::{Arc, Condvar, Mutex},
thread::available_parallelism,
};
#[derive(Debug)]
pub struct Semaphore {
permits: Mutex<usize>,
condvar: Condvar,
}
impl Semaphore {
pub fn new(permits: usize) -> Arc<Self> {
Arc::new(Semaphore {
permits: Mutex::new(permits),
condvar: Condvar::new(),
})
}
pub fn new_available_parallelism() -> Result<Arc<Self>, String> {
match available_parallelism() {
Ok(parallelism) => Ok(Arc::new(Semaphore {
permits: Mutex::new(parallelism.get()),
condvar: Condvar::new(),
})),
Err(err) => Err(err.to_string()),
}
}
#[deprecated(
since = "1.1.0",
note = "Please do not use this method anymore, there will be no replacement for it either"
)]
pub fn available_permits(self: &Arc<Self>) -> usize {
*self.permits.lock().unwrap()
}
pub fn acquire(self: &Arc<Self>) -> Permit {
let mut permits = self.permits.lock().unwrap();
while *permits == 0 {
permits = self.condvar.wait(permits).unwrap();
}
*permits -= 1;
Permit {
semaphore: Arc::clone(self),
}
}
pub fn try_acquire(self: &Arc<Self>) -> Option<Permit> {
let mut permits = self.permits.lock().unwrap();
if *permits > 0 {
*permits -= 1;
Some(Permit {
semaphore: Arc::clone(self),
})
} else {
None
}
}
pub fn release(&self) {
let mut permits = self.permits.lock().unwrap();
*permits += 1;
self.condvar.notify_one();
}
}
#[derive(Debug)]
pub struct Permit {
semaphore: Arc<Semaphore>,
}
impl Drop for Permit {
fn drop(&mut self) {
self.semaphore.release();
}
}