use std::sync::Arc;
use crate::internal::semaphore;
#[cfg(test)]
mod tests;
#[derive(Debug)]
pub struct Semaphore {
s: semaphore::Semaphore,
}
impl Semaphore {
pub const fn new(permits: usize) -> Self {
Self {
s: semaphore::Semaphore::new(permits),
}
}
pub fn available_permits(&self) -> usize {
self.s.available_permits()
}
#[must_use = "`drain_permits` may drain fewer permits than requested"]
pub fn drain_permits(&self, up_to: usize) -> usize {
self.s.drain_permits(up_to)
}
pub fn reduce_permits(&self, n: usize) {
self.s.reduce_permits(n);
}
pub fn release(&self, permits: usize) {
self.s.release(permits);
}
pub fn try_acquire(&self, permits: usize) -> Option<SemaphorePermit<'_>> {
if self.s.try_acquire(permits) {
Some(SemaphorePermit { sem: self, permits })
} else {
None
}
}
pub async fn acquire(&self, permits: usize) -> SemaphorePermit<'_> {
self.s.acquire(permits).await;
SemaphorePermit { sem: self, permits }
}
pub fn try_acquire_owned(self: Arc<Self>, permits: usize) -> Option<OwnedSemaphorePermit> {
if self.s.try_acquire(permits) {
Some(OwnedSemaphorePermit { sem: self, permits })
} else {
None
}
}
pub async fn acquire_owned(self: Arc<Self>, permits: usize) -> OwnedSemaphorePermit {
self.s.acquire(permits).await;
OwnedSemaphorePermit { sem: self, permits }
}
}
#[must_use = "permits are released immediately when dropped"]
#[derive(Debug)]
pub struct SemaphorePermit<'a> {
sem: &'a Semaphore,
permits: usize,
}
impl SemaphorePermit<'_> {
pub fn forget(mut self) {
self.permits = 0;
}
#[track_caller]
pub fn merge(&mut self, mut other: Self) {
assert!(
std::ptr::eq(self.sem, other.sem),
"merging permits from different semaphore instances"
);
self.permits = self
.permits
.checked_add(other.permits)
.expect("merged permit count would overflow usize::MAX");
other.permits = 0;
}
pub fn split(&mut self, n: usize) -> Option<Self> {
if n > self.permits {
return None;
}
self.permits -= n;
Some(Self {
sem: self.sem,
permits: n,
})
}
pub fn permits(&self) -> usize {
self.permits
}
}
impl Drop for SemaphorePermit<'_> {
fn drop(&mut self) {
self.sem.release(self.permits);
}
}
#[must_use = "permits are released immediately when dropped"]
#[derive(Debug)]
pub struct OwnedSemaphorePermit {
sem: Arc<Semaphore>,
permits: usize,
}
impl OwnedSemaphorePermit {
pub fn forget(mut self) {
self.permits = 0;
}
#[track_caller]
pub fn merge(&mut self, mut other: Self) {
assert!(
Arc::ptr_eq(&self.sem, &other.sem),
"merging permits from different semaphore instances"
);
self.permits = self
.permits
.checked_add(other.permits)
.expect("merged permit count would overflow usize::MAX");
other.permits = 0;
}
pub fn split(&mut self, n: usize) -> Option<Self> {
if n > self.permits {
return None;
}
self.permits -= n;
Some(Self {
sem: self.sem.clone(),
permits: n,
})
}
pub fn permits(&self) -> usize {
self.permits
}
}
impl Drop for OwnedSemaphorePermit {
fn drop(&mut self) {
self.sem.release(self.permits);
}
}