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

87 lines
2.0 KiB

//! Keeping state
use super::*;
use tokio::{
sync::{
Semaphore,
SemaphorePermit,
RwLock,
RwLockReadGuard,
RwLockWriteGuard,
},
};
use futures::{
future::OptionFuture,
};
use progress::logging::Logger;
/// Contains state for a set of operations
#[derive(Debug)]
pub struct State
{
cfg: config::Config,
mtx: Option<Semaphore>,
stop: RwLock<()>,
logger: Logger,
}
/// Guard for operations inside state
#[derive(Debug)]
pub struct Permit<'a>(RwLockReadGuard<'a, ()>, Option<SemaphorePermit<'a>>);
impl State
{
/// Get the logger object for this state
pub fn logger(&self) -> &Logger
{
&self.logger
}
/// Clone the logger into a new mutable one
pub fn logger_output(&self) -> Logger
{
self.logger.clone() //TODO: Eeeehhhhh this is really inefficient
}
/// A reference to the progress counter
pub fn progress(&self) -> &progress::Handle
{
self.logger.progress()
}
/// Create a new state
pub fn new(cfg: config::Config, logger: progress::logging::Logger) -> Self
{
Self {
mtx: cfg.limit.map(|x| Semaphore::new(x.into())),
cfg,
stop: RwLock::new(()),
logger,
}
}
/// 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
}
}