use super::*; use tokio::sync::{ Semaphore, SemaphorePermit }; use futures::Future; use futures::future::OptionFuture; use data::Cache; use config::Config; /// Program state #[derive(Debug, Clone)] pub struct State { config: Arc, cache: Cache, depth: usize, throttle: Option>, } #[derive(Debug)] pub struct TaskLock<'a>(&'a Option>); impl<'a> TaskLock<'a> { /// Enter this lock section. pub fn enter(self) -> OptionFuture> + 'a> { self.0.as_ref().map(|x| x.acquire()).into() } } impl State { /// Create a new state pub fn new(cfg: Config) -> Self { Self { throttle: cfg.max_tasks.map(|max| Arc::new(Semaphore::new(max.get()))), cache: Cache::new(), depth: 1, config: Arc::new(cfg), } } /// Get the semaphore for this state pub fn lock(&self) -> TaskLock<'_> { TaskLock(&self.throttle) } /// Current depth of this tree pub fn depth(&self) -> usize { self.depth } /// Clone into increased depth, if config allows a deeper run. pub fn deeper(&self) -> Option { if self.config.recursive.can_run(self.depth+1) { Some(Self{ depth: self.depth + 1, ..self.clone() }) } else { None } } /// The configuration for this run pub fn config(&self) -> &Config { &self.config } /// A reference to the cache of this run pub fn cache(&self) -> &Cache { &self.cache } /// Subscribe to this state's cache pub fn cache_sub(&self) -> Cache { self.cache.clone() } /// Try to consume the state into the cache. /// /// Fails if there are other references of this state alive. pub fn try_into_cache(self) -> Result<(Cache, Config), Self> { match Arc::try_unwrap(self.config) { Ok(cfg) => Ok((self.cache, cfg)), Err(config) => Err(Self{config, ..self}), } } }