diff --git a/src/loggers.rs b/src/loggers.rs index 3758a81..e5c8573 100644 --- a/src/loggers.rs +++ b/src/loggers.rs @@ -7,7 +7,7 @@ use std::io::Write; // 1 - Error, 2 - Warn, 3 - Info, 4 - Debug, 5 - Trace pub type Level = usize; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Entry(pub Level, pub S); pub trait Logger { @@ -67,7 +67,7 @@ impl Logger for StdErrLogger { } impl Drop for StdErrLogger { fn drop(&mut self) { - if *self.line_started.borrow() == true { + if *self.line_started.borrow() { writeln!(&mut stderr()).unwrap(); } } @@ -98,7 +98,7 @@ impl<'a, L: Logger> Logger for FilteringLogger<'a, L> { } } -#[derive(Debug, Default)] +#[derive(Clone, Debug, Default)] pub struct StoringLogger { log: RefCell<(bool, Vec>)>, } @@ -125,6 +125,7 @@ impl Logger for StoringLogger { None } .unwrap_or_else(|| Entry(level, line.into())); + log.0 = true; log.1.push(entry); } fn writeln + Into>(&self, level: Level, line: S) { diff --git a/src/setup/core.rs b/src/setup/core.rs index 5a6852c..1e4df8f 100644 --- a/src/setup/core.rs +++ b/src/setup/core.rs @@ -1,6 +1,6 @@ use super::runnable::Runnable; -use super::util::{AddResult, AddableResource}; -use super::Setup; +use super::setup::Setup; +use super::util::{AddableResource, InternalAddResult}; use super::SymbolRunner; use crate::async_utils::try_join; use crate::loggers::{Logger, StoringLogger}; @@ -16,15 +16,15 @@ use std::marker::PhantomData; #[async_trait(?Send)] pub trait AddGeneric { - async fn add_generic(&self, x: X) -> AddResult; + async fn add_generic(&self, x: X) -> InternalAddResult; } macro_rules! add_generic { ( $($name:ident)* ) => ( #[async_trait(?Send)] #[allow(non_snake_case)] - impl - AddGeneric<($($name,)*)> for Setup + impl + AddGeneric<($($name,)*)> for Setup where $( RegularSetupCore: SetupCore<$name, Self>, @@ -34,11 +34,13 @@ macro_rules! add_generic { ),* { #[allow(unused)] - async fn add_generic(&self, ($($name,)*): ($($name,)*)) -> Result<(($($name::Artifact,)*), bool), Box> + async fn add_generic(&self, ($($name,)*): ($($name,)*)) -> Result<(StoringLogger, ($($name::Artifact,)*), bool), (StoringLogger, Box)> { - let x: Result<_, Box> = try_join!($(self.add_force($name, false),)*); + let x: Result<_, _> = try_join!($(self.add($name, false),)*); let ($($name,)*) = x?; - Ok((($($name.0,)*), false $(|| $name.1)*)) + let logger = StoringLogger::default(); + $(logger.put($name.0.release());)* + Ok((logger, ($($name.1,)*), false $(|| $name.2)*)) } } ); @@ -51,57 +53,54 @@ for_each_tuple!(add_generic); #[async_trait(?Send)] impl< SR: 'static + SymbolRunner, - LOG: 'static + Logger, T: AddableResource, Rs: 'static + Hash + Eq + FromResource, As: 'static + FromArtifact + Clone, L: 'static + ResourceLocator>, B: 'static + ImplementationBuilder, - > AddGeneric> for Setup + > AddGeneric> for Setup where >::Implementation: Runnable + Debug, Self: AddGeneric, T::Artifact: Clone, { - async fn add_generic(&self, r: Option) -> AddResult> { + async fn add_generic(&self, r: Option) -> InternalAddResult> { Ok(match r { Some(r) => { - let (result, did_run) = self.add_force(r, false).await?; - (Some(result), did_run) + let (logger, result, did_run) = self.add(r, false).await?; + (logger, Some(result), did_run) } - None => (None, false), + None => (StoringLogger::default(), None, false), }) } } #[async_trait(?Send)] impl< - LOG: 'static + Logger, T: AddableResource, Rs: 'static + Hash + Eq + FromResource, As: 'static + FromArtifact + Clone, SR: 'static, L: 'static, B: 'static, - > AddGeneric for Setup + > AddGeneric for Setup where T::Artifact: Clone, RegularSetupCore: 'static + SetupCore, { - async fn add_generic(&self, r: T) -> AddResult { - self.add_force(r, false).await + async fn add_generic(&self, r: T) -> InternalAddResult { + self.add(r, false).await } } #[async_trait(?Send)] pub trait SetupCore { - async fn add>( + async fn add>( &self, setup: &S, - parent_logger: &LOG, resource: RR, force_run: bool, - ) -> AddResult; + ) -> InternalAddResult; } #[derive(Debug)] @@ -127,49 +126,57 @@ where L: ResourceLocator, S: AddGeneric + AddGeneric<>::Prerequisites>, { - async fn add>( + async fn add>( &self, setup: &S, - parent_logger: &LOG, resource: RR, force_run: bool, - ) -> AddResult { + ) -> InternalAddResult { let resource = resource.as_ref(); let logger = StoringLogger::new(); logger.write(4, format!("Adding {:?} ... ", resource)); - let result = async { - logger.trace(format!(" (force_run is {})", force_run)); - let (location, location_prereqs) = L::locate(resource); - logger.trace(format!("Adding location prereqs for {:?}", resource)); - let (_, location_prereqs_did_run) = setup.add_generic(location_prereqs).await?; - logger.trace(format!( - "Location prereqs for {:?} did_run: {}", - resource, location_prereqs_did_run - )); - logger.trace(format!("Adding implementation prereqs for {:?}", resource)); - let (prereqs, prereqs_did_run) = setup.add_generic(B::prerequisites(resource)).await?; - logger.trace(format!( - "Implementation prereqs for {:?} did_run: {}", - resource, prereqs_did_run - )); - logger.trace(format!("Running implementation for {:?}", resource)); - let implementation = B::create(resource, &location, prereqs); - let did_run = implementation - .run( - &self.symbol_runner, - &logger, - force_run || location_prereqs_did_run || prereqs_did_run, - ) - .await?; - Ok((location, did_run)) + logger.write(4, format!("(force_run is {})", force_run)); + let (location, location_prereqs) = L::locate(resource); + logger.trace(format!("Adding location prereqs for {:?}", resource)); + let result = setup.add_generic(location_prereqs).await; + if let Err((log, e)) = result { + logger.put(log.release()); + return Err((logger, e)); } - .await; - logger.write(4, "done."); - let max_level = if result.is_err() { 5 } else { 3 }; - if parent_logger.put(logger.release().into_iter().filter(|e| e.0 <= max_level)) == 0 { - parent_logger.write(3, "."); + let (location_prereq_logger, _, location_prereqs_did_run) = result.unwrap(); + logger.put(location_prereq_logger.release()); + logger.trace(format!( + "Location prereqs for {:?} did_run: {}", + resource, location_prereqs_did_run + )); + logger.trace(format!("Adding implementation prereqs for {:?}", resource)); + let result = setup.add_generic(B::prerequisites(resource)).await; + if let Err((log, e)) = result { + logger.put(log.release()); + return Err((logger, e)); + } + let (impl_prereq_logger, prereqs, prereqs_did_run) = result.unwrap(); + logger.put(impl_prereq_logger.release()); + logger.trace(format!( + "Implementation prereqs for {:?} did_run: {}", + resource, prereqs_did_run + )); + logger.trace(format!("Running implementation for {:?}", resource)); + let implementation = B::create(resource, &location, prereqs); + let did_run_result = implementation + .run( + &self.symbol_runner, + &logger, + force_run || location_prereqs_did_run || prereqs_did_run, + ) + .await; + match did_run_result { + Ok(did_run) => { + logger.write(4, "done."); + Ok((logger, location, did_run)) + } + Err(e) => Err((logger, e)), } - result } } diff --git a/src/setup/mod.rs b/src/setup/mod.rs index 7032339..cca4db8 100644 --- a/src/setup/mod.rs +++ b/src/setup/mod.rs @@ -8,4 +8,4 @@ pub use symbol_runner::{ }; mod runnable; mod setup; -pub use setup::Setup; +pub use setup::SetupFacade as Setup; diff --git a/src/setup/setup.rs b/src/setup/setup.rs index 748f427..4efd0ab 100644 --- a/src/setup/setup.rs +++ b/src/setup/setup.rs @@ -1,8 +1,9 @@ use super::core::{RegularSetupCore, SetupCore}; use super::runnable::Runnable; -use super::util::{AddResult, AddableResource}; +use super::util::{AddResult, AddableResource, InternalAddResult}; use super::SymbolRunner; -use crate::loggers::Logger; +use crate::async_utils::sleep; +use crate::loggers::{Logger, StoringLogger}; use crate::resources::{DefaultArtifacts, DefaultResources, FromArtifact, FromResource}; use crate::{DefaultBuilder, DefaultLocator}; use futures::future::FutureExt; @@ -14,57 +15,27 @@ use std::future::Future; use std::hash::Hash; use std::pin::Pin; use std::rc::Rc; +use std::time::Duration; type Cache = HashMap>>>>; #[derive(Debug)] -struct SetupInner { +struct SetupInner { core: CORE, - logger: LOG, resources: RefCell>, } #[derive(Debug)] -pub struct Setup< - SR, - LOG, - L = DefaultLocator, - B = DefaultBuilder, - Rs = DefaultResources<'static, &'static str>, - As = DefaultArtifacts<'static, &'static str>, ->(Rc, LOG, Rs, As>>); +pub struct Setup(Rc, Rs, As>>); -// https://github.com/rust-lang/rust/issues/27336 -impl Setup { - pub fn new(symbol_runner: SR, logger: LOG) -> Self { - Self::new_with(symbol_runner, logger) - } -} - -impl Setup { - pub fn new_with(symbol_runner: SR, logger: LOG) -> Self { - Self(Rc::new(SetupInner { - core: RegularSetupCore::new(symbol_runner), - logger, - resources: RefCell::default(), - })) - } -} - -impl< - L: 'static, - B: 'static, - SR: 'static, - LOG: 'static + Logger, - Rs: Hash + Eq + 'static, - As: 'static, - > Setup +impl + Setup { fn borrow_resources(&self) -> RefMut<'_, Cache> { self.0.resources.borrow_mut() } - pub async fn add_force(&self, resource: R, force_run: bool) -> AddResult + pub async fn add(&self, resource: R, force_run: bool) -> InternalAddResult where Rs: FromResource, As: FromArtifact + Clone, @@ -73,51 +44,123 @@ impl< { let (storable_resource, weak_resource) = Rs::from_resource(resource); let mut resources = self.borrow_resources(); - if let Some(future) = resources.remove(&storable_resource) { + let result = if let Some(future) = resources.remove(&storable_resource) { assert!( !force_run, "Forcing to run an already-added resource is a logical error" ); resources.insert(storable_resource, future.clone()); drop(resources); - Ok(future.await) + let logger = StoringLogger::default(); + logger.trace(format!( + "{:?} already added", + weak_resource.upgrade().expect("Dangling!") + )); + let (t, did_run) = future.await; + Ok((logger, t, did_run)) } else { let inner_weak = Rc::downgrade(&self.0); let future = Box::pin(async move { let this = Self(inner_weak.upgrade().expect("Dangling!")); let resource = weak_resource.upgrade().expect("Dangling!"); // Need to convert Box to String for Clone for Shared - this - .0 - .core - .add(&this, &this.0.logger, resource, force_run) - .await - .map(|(t, did_run)| (As::from_artifact(t), did_run)) - .map_err(|e| e.to_string()) + let result = this.0.core.add(&this, resource, force_run).await; + + result + .map(|(logger, t, did_run)| (logger, As::from_artifact(t), did_run)) + .map_err(|(logger, e)| (logger, e.to_string())) }) .shared(); let future_clone = future.clone(); resources.insert( storable_resource, - (Box::pin(async move { future_clone.await.unwrap() }) - as Pin>>) + (Box::pin(async move { + let result = future_clone.await; + if result.is_err() { + // Step back to give the initial caller time to handle the error before unwrapping + sleep(Duration::from_millis(0)).await; + } + result.map(|(_, t, did_run)| (t, did_run)).unwrap() + }) as Pin>>) .shared(), ); drop(resources); - future.await.map_err(|e| e.into()) - } - .map(|(t, did_run)| (t.into_artifact(), did_run)) + let result = future.await; + result.map_err(|(logger, e)| (logger, e.into())) + }; + result.map(|(logger, t, did_run)| (logger, t.into_artifact(), did_run)) } +} - // - // Legacy - // +#[derive(Debug)] +pub struct SetupFacade< + SR, + LOG, + L = DefaultLocator, + B = DefaultBuilder, + Rs = DefaultResources<'static, &'static str>, + As = DefaultArtifacts<'static, &'static str>, +>(LOG, Setup); + +impl SetupFacade { + pub fn new(symbol_runner: SR, logger: LOG) -> Self { + Self::new_with(symbol_runner, logger) + } +} + +impl SetupFacade { + pub fn new_with(symbol_runner: SR, logger: LOG) -> Self { + Self( + logger, + Setup(Rc::new(SetupInner { + core: RegularSetupCore::new(symbol_runner), + resources: RefCell::default(), + })), + ) + } +} + +impl< + SR: 'static, + LOG: 'static + Logger, + L: 'static, + B: 'static, + Rs: 'static + Eq + Hash, + As: 'static, + > SetupFacade +{ + pub async fn add_force(&self, resource: R, force_run: bool) -> AddResult + where + Rs: FromResource, + As: FromArtifact + Clone, + R::Artifact: Clone, + RegularSetupCore: SetupCore>, + { + let result = self.1.add(resource, force_run).await; + match result { + Ok((logger, t, did_run)) => { + if self + .0 + .put(logger.release().into_iter().filter(|e| e.0 <= 3)) + == 0 + { + self.0.write(3, "."); + } + Ok((t, did_run)) + } + Err((logger, e)) => { + self.0.put(logger.release()); + Err(e) + } + } + } pub async fn add(&self, resource: R) -> AddResult where - RegularSetupCore: SetupCore, + RegularSetupCore: SetupCore>, Rs: FromResource, As: FromArtifact + Clone, R::Artifact: Clone, + SR: SymbolRunner, { self.add_force(resource, false).await } @@ -130,7 +173,7 @@ impl< where RegularSetupCore: SymbolRunner, { - symbol.run(&self.0.core, &self.0.logger, force).await + symbol.run(&(self.1).0.core, &self.0, force).await } } diff --git a/src/setup/util.rs b/src/setup/util.rs index ad9dbff..542482f 100644 --- a/src/setup/util.rs +++ b/src/setup/util.rs @@ -1,3 +1,4 @@ +use crate::loggers::StoringLogger; use crate::resources::Resource; use crate::to_artifact::ToArtifact; use std::error::Error; @@ -7,3 +8,5 @@ pub trait AddableResource: 'static + Resource + Debug {} impl AddableResource for R where R: 'static + Resource + Debug {} pub type AddResult = Result<(::Artifact, bool), Box>; +pub type InternalAddResult = + Result<(StoringLogger, ::Artifact, bool), (StoringLogger, Box)>;