use crate::{Event, EventListener};
use core::cell::Cell;
use core::pin::Pin;
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
pub struct Semaphore {
event: Event<()>,
permits: Cell<usize>,
}
pub struct SemaphoreGuard<'a> {
semaphore: &'a Semaphore,
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub struct SemaphoreGuardRc {
semaphore: Rc<Semaphore>,
}
impl Semaphore {
pub fn new(permits: usize) -> Semaphore {
Semaphore {
event: Event::new(),
permits: Cell::new(permits),
}
}
pub fn try_acquire(&self) -> Option<SemaphoreGuard<'_>> {
let permits = self.permits.get();
if permits > 0 {
self.permits.set(permits - 1);
Some(SemaphoreGuard { semaphore: self })
} else {
None
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn try_acquire_rc(self: Rc<Self>) -> Option<SemaphoreGuardRc> {
let permits = self.permits.get();
if permits > 0 {
self.permits.set(permits - 1);
Some(SemaphoreGuardRc { semaphore: self })
} else {
None
}
}
pub async fn acquire(&self) -> SemaphoreGuard<'_> {
let mut listener = EventListener::new(&self.event);
{
let mut listener = unsafe { Pin::new_unchecked(&mut listener) };
loop {
if let Some(guard) = self.try_acquire() {
return guard;
}
listener.as_mut().await;
}
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub async fn acquire_rc(self: Rc<Self>) -> SemaphoreGuardRc {
let mut listener = EventListener::new(&self.event);
{
let mut listener = unsafe { Pin::new_unchecked(&mut listener) };
loop {
if let Some(guard) = self.clone().try_acquire_rc() {
return guard;
}
listener.as_mut().await;
}
}
}
}
impl Drop for SemaphoreGuard<'_> {
fn drop(&mut self) {
self.semaphore.permits.set(self.semaphore.permits.get() + 1);
self.semaphore.event.notify(1);
}
}
#[cfg(feature = "alloc")]
impl Drop for SemaphoreGuardRc {
fn drop(&mut self) {
self.semaphore.permits.set(self.semaphore.permits.get() + 1);
self.semaphore.event.notify(1);
}
}