You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
videl/src/state.rs

67 lines
1.6 KiB

//! Keeping state
use super::*;
use tokio::{
sync::{
Semaphore,
SemaphorePermit,
RwLock,
RwLockReadGuard,
RwLockWriteGuard,
},
};
use futures::{
future::OptionFuture,
};
/// Contains state for a set of operations
#[derive(Debug)]
pub struct State
{
cfg: config::Config,
mtx: Option<Semaphore>,
stop: RwLock<()>,
progress: progress::Handle,
}
/// Guard for operations inside state
#[derive(Debug)]
pub struct Permit<'a>(RwLockReadGuard<'a, ()>, Option<SemaphorePermit<'a>>);
impl State
{
/// Create a new state
pub fn new(cfg: config::Config, progress: progress::Handle) -> Self
{
Self {
mtx: cfg.limit.map(|x| Semaphore::new(x.into())),
cfg,
stop: RwLock::new(()),
progress,
}
}
/// Acquire exclusive lock, preventing other tasks from acquiring through either `lock` or `lockout`.
///
/// This function will yield until all other `lock` or `lockout` guards currently acquired (if any) are released.
pub async fn lockout(&self) -> RwLockWriteGuard<'_, ()>
{
self.stop.write().await
}
/// Acquire a permit for concurrent work, yielding the task if needed.
///
/// If there are currently `config().limit` premits acquired, this will yield until at least one if released.
/// If there is a `lockout` guard acquired, this will yield until it is released too.
pub async fn lock(&self) -> Permit<'_>
{
Permit(self.stop.read().await, OptionFuture::from(self.mtx.as_ref().map(Semaphore::acquire)).await)
}
/// The config object
#[inline] pub fn config(&self) -> &config::Config
{
&self.cfg
}
}