extern crate parking_lot;
use std::sync::Arc;
use parking_lot::RwLock;
mod raw;
use raw::RawSemaphore;
mod guard;
pub use guard::SemaphoreGuard;
mod shutdown;
pub use shutdown::ShutdownHandle;
#[cfg(test)]
mod tests;
pub type TryAccessResult<T> = Result<SemaphoreGuard<T>, TryAccessError>;
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum TryAccessError {
Shutdown,
NoCapacity
}
pub struct Semaphore<T> {
raw: Arc<RawSemaphore>,
resource: Arc<RwLock<Option<Arc<T>>>>
}
impl<T> Clone for Semaphore<T> {
fn clone(&self) -> Semaphore<T> {
Semaphore {
raw: self.raw.clone(),
resource: self.resource.clone()
}
}
}
impl<T> Semaphore<T> {
pub fn new(capacity: usize, resource: T) -> Self {
Semaphore {
raw: Arc::new(RawSemaphore::new(capacity)),
resource: Arc::new(RwLock::new(Some(Arc::new(resource))))
}
}
#[inline]
pub fn try_access(&self) -> TryAccessResult<T> {
if let Some(ref resource) = *self.resource.read() {
if self.raw.try_acquire() {
Ok(guard::new(&self.raw, resource))
} else {
Err(TryAccessError::NoCapacity)
}
} else {
Err(TryAccessError::Shutdown)
}
}
pub fn shutdown(&self) -> ShutdownHandle<T> {
shutdown::new(&self.raw, self.resource.write().take())
}
}