crate::ix!();
#[derive(Clone)]
pub struct SemaphoreGrant {
sem: Arc<Semaphore>,
have_grant: bool,
}
impl Drop for SemaphoreGrant {
fn drop(&mut self) {
self.release();
}
}
impl From<&SemaphoreGrant> for bool {
#[inline]
fn from(sg: &SemaphoreGrant) -> Self {
sg.have_grant
}
}
impl SemaphoreGrant {
pub fn acquire(&mut self) {
trace!("SemaphoreGrant::acquire");
if self.have_grant {
return;
}
self.sem.wait();
self.have_grant = true;
}
pub fn release(&mut self) {
trace!("SemaphoreGrant::release");
if !self.have_grant {
return;
}
self.sem.post();
self.have_grant = false;
}
pub fn try_acquire(&mut self) -> bool {
trace!("SemaphoreGrant::try_acquire");
if !self.have_grant && self.sem.try_wait() {
self.have_grant = true;
}
self.have_grant
}
pub fn move_to(&mut self, target: &mut SemaphoreGrant) {
trace!("SemaphoreGrant::move_to");
target.release();
target.sem = Arc::clone(&self.sem);
target.have_grant = self.have_grant;
self.have_grant = false;
}
pub fn new(sema: Arc<Semaphore>, try_: Option<bool>) -> Self {
let mut grant = Self {
sem: sema,
have_grant: false,
};
if try_.unwrap_or(false) {
grant.try_acquire();
} else {
grant.acquire();
}
grant
}
}
#[cfg(test)]
mod semaphore_grant_tests {
use super::*;
use std::thread;
use std::time::{Duration as StdDuration, Instant};
#[traced_test]
fn basic_acquire_release_cycle() {
let sem = Arc::new(Semaphore::new(1));
let mut g1 = SemaphoreGrant::new(Arc::clone(&sem), Some(true));
assert!(bool::from(&g1), "g1 should have the permit");
let mut g2 = SemaphoreGrant::new(Arc::clone(&sem), Some(true));
assert!(!bool::from(&g2), "g2 should not have acquired yet");
g1.release();
assert!(!bool::from(&g1), "g1 released");
assert!(g2.try_acquire(), "g2 now acquires after g1 release");
}
#[traced_test]
fn move_transfers_ownership() {
let sem = Arc::new(Semaphore::new(1));
let mut a = SemaphoreGrant::new(Arc::clone(&sem), None);
let mut b = SemaphoreGrant::new(Arc::clone(&sem), Some(true));
assert!(bool::from(&a));
assert!(!bool::from(&b));
a.move_to(&mut b);
assert!(!bool::from(&a));
assert!(bool::from(&b));
}
#[traced_test]
fn drop_returns_permit() {
let sem = Arc::new(Semaphore::new(1));
{
let _g = SemaphoreGrant::new(Arc::clone(&sem), None);
assert!(!sem.try_wait(), "semaphore exhausted while _g alive");
}
assert!(sem.try_wait(), "permit returned after drop");
}
}