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.
67 lines
1.6 KiB
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
|
|
}
|
|
}
|