use std::fmt;
use std::sync::atomic::Ordering;
use std::sync::Arc;
pub struct RankedSemaphorePermit<'a> {
pub(crate) sem: &'a super::RankedSemaphore,
pub(crate) permits: u32,
}
pub struct OwnedRankedSemaphorePermit {
pub(crate) sem: Arc<super::RankedSemaphore>,
pub(crate) permits: u32,
}
impl<'a> RankedSemaphorePermit<'a> {
pub fn forget(mut self) {
self.permits = 0;
}
pub fn num_permits(&self) -> usize {
self.permits as usize
}
pub fn merge(&mut self, mut other: Self) {
if !std::ptr::eq(self.sem, other.sem) {
panic!("Cannot merge permits from different semaphores");
}
self.permits += other.permits;
other.permits = 0;
}
pub fn split(&mut self, n: u32) -> Option<Self> {
if n > self.permits {
return None;
}
self.permits -= n;
Some(Self {
sem: self.sem,
permits: n,
})
}
}
impl<'a> Drop for RankedSemaphorePermit<'a> {
fn drop(&mut self) {
if self.permits == 0 {
return;
}
let permits_to_add = (self.permits as usize) << super::RankedSemaphore::PERMIT_SHIFT;
let waiters = self.sem.waiters.lock().unwrap();
if waiters.is_empty() {
drop(waiters);
self.sem
.permits
.fetch_add(permits_to_add, Ordering::Release);
return;
}
self.sem.add_permits_locked(self.permits as usize, waiters);
}
}
impl OwnedRankedSemaphorePermit {
pub fn forget(mut self) {
self.permits = 0;
}
pub fn num_permits(&self) -> usize {
self.permits as usize
}
pub fn merge(&mut self, mut other: Self) {
if !Arc::ptr_eq(&self.sem, &other.sem) {
panic!("Cannot merge permits from different semaphores");
}
self.permits += other.permits;
other.permits = 0;
}
pub fn split(&mut self, n: usize) -> Option<Self> {
let n = u32::try_from(n).ok()?;
if n > self.permits {
return None;
}
self.permits -= n;
Some(Self {
sem: self.sem.clone(),
permits: n,
})
}
pub fn semaphore(&self) -> &Arc<super::RankedSemaphore> {
&self.sem
}
}
impl Drop for OwnedRankedSemaphorePermit {
fn drop(&mut self) {
if self.permits == 0 {
return;
}
let permits_to_add = (self.permits as usize) << super::RankedSemaphore::PERMIT_SHIFT;
let waiters = self.sem.waiters.lock().unwrap();
if waiters.is_empty() {
drop(waiters);
self.sem
.permits
.fetch_add(permits_to_add, Ordering::Release);
return;
}
self.sem.add_permits_locked(self.permits as usize, waiters);
}
}
impl<'a> fmt::Debug for RankedSemaphorePermit<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RankedSemaphorePermit")
.field("permits", &self.permits)
.finish()
}
}
impl fmt::Debug for OwnedRankedSemaphorePermit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OwnedRankedSemaphorePermit")
.field("permits", &self.permits)
.finish()
}
}