use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[derive(Debug)]
pub(super) struct Limit {
capacity: usize,
held: AtomicUsize,
}
impl Limit {
pub(super) const fn new(capacity: usize) -> Self {
Self {
capacity,
held: AtomicUsize::new(0),
}
}
pub(super) fn enter(self: &Arc<Self>) -> Option<Permit> {
let mut held = self.held.load(Ordering::Acquire);
loop {
if held >= self.capacity {
return None;
}
match self.held.compare_exchange_weak(
held,
held + 1,
Ordering::AcqRel,
Ordering::Acquire,
) {
Ok(_) => return Some(Permit(Arc::clone(self))),
Err(current) => held = current,
}
}
}
}
pub(super) struct Permit(Arc<Limit>);
impl Drop for Permit {
fn drop(&mut self) {
self.0.held.fetch_sub(1, Ordering::Release);
}
}