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.
230 lines
6.5 KiB
230 lines
6.5 KiB
use super::runnable::Runnable;
|
|
use super::setup::Setup;
|
|
use super::util::{AddableResource, InternalAddResult};
|
|
use super::SymbolRunner;
|
|
use crate::async_utils::join;
|
|
use crate::resources::{FromArtifact, FromResource};
|
|
use crate::symbols::Symbol;
|
|
use crate::to_artifact::ToArtifact;
|
|
use crate::{ImplementationBuilder, ResourceLocator};
|
|
use async_trait::async_trait;
|
|
use slog::{debug, o, trace, Logger};
|
|
use std::error::Error;
|
|
use std::fmt::Debug;
|
|
use std::hash::Hash;
|
|
use std::marker::PhantomData;
|
|
use std::rc::Rc;
|
|
|
|
#[async_trait(?Send)]
|
|
pub trait AddGeneric<X: ToArtifact> {
|
|
async fn add_generic(&self, logger: &Rc<Logger>, x: X) -> InternalAddResult<X>;
|
|
}
|
|
|
|
macro_rules! add_generic {
|
|
// Workaround for https://github.com/tokio-rs/tokio/issues/5502
|
|
() => (
|
|
#[async_trait(?Send)]
|
|
impl<SR, L, B, Rs, As> AddGeneric<()> for Setup<SR, L, B, Rs, As>
|
|
{
|
|
async fn add_generic(&self, _: &Rc<Logger>, (): ()) -> Result<((), bool), Box<dyn Error>>
|
|
{
|
|
Ok(((), false))
|
|
}
|
|
}
|
|
);
|
|
( $($name:ident)* ) => (
|
|
#[async_trait(?Send)]
|
|
#[allow(non_snake_case)]
|
|
impl<SR: 'static, _L: 'static, _B: 'static, Rs: 'static + Hash + Eq, As: 'static + Clone, $($name: AddableResource,)*>
|
|
AddGeneric<($($name,)*)> for Setup<SR, _L, _B, Rs, As>
|
|
where
|
|
$(
|
|
RegularSetupCore<SR, _L, _B>: SetupCore<$name, Self>,
|
|
As: FromArtifact<$name>,
|
|
Rs: FromResource<$name>,
|
|
$name::Artifact: Clone
|
|
),*
|
|
{
|
|
#[allow(unused, clippy::shadow_unrelated)]
|
|
async fn add_generic(&self, logger: &Rc<Logger>, ($($name,)*): ($($name,)*)) -> Result<(($($name::Artifact,)*), bool), Box<dyn Error>>
|
|
{
|
|
let ($($name,)*) = join!($(self.add(logger, $name, false),)*);
|
|
let mut did_run_any = false;
|
|
$(
|
|
let (artifact, did_run) = $name?;
|
|
did_run_any = did_run_any || did_run;
|
|
let $name = artifact;
|
|
)*
|
|
Ok((($($name,)*), did_run_any))
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
for_each_tuple!(add_generic);
|
|
|
|
// This is for self-referential T
|
|
// FIXME: Wait for specialization
|
|
#[async_trait(?Send)]
|
|
impl<
|
|
SR: 'static + SymbolRunner,
|
|
T: AddableResource,
|
|
Rs: 'static + Hash + Eq + FromResource<T>,
|
|
As: 'static + FromArtifact<T> + Clone,
|
|
L: 'static + ResourceLocator<T, Prerequisites = Option<T>>,
|
|
B: 'static + ImplementationBuilder<T>,
|
|
> AddGeneric<Option<T>> for Setup<SR, L, B, Rs, As>
|
|
where
|
|
<B as ImplementationBuilder<T>>::Implementation: Runnable + Debug,
|
|
Self: AddGeneric<B::Prerequisites>,
|
|
T::Artifact: Clone,
|
|
{
|
|
async fn add_generic(&self, logger: &Rc<Logger>, r: Option<T>) -> InternalAddResult<Option<T>> {
|
|
Ok(match r {
|
|
Some(r) => {
|
|
let (result, did_run) = self.add(logger, r, false).await?;
|
|
(Some(result), did_run)
|
|
}
|
|
None => (None, false),
|
|
})
|
|
}
|
|
}
|
|
|
|
#[async_trait(?Send)]
|
|
impl<
|
|
T: AddableResource,
|
|
Rs: 'static + Hash + Eq + FromResource<T>,
|
|
As: 'static + FromArtifact<T> + Clone,
|
|
SR: 'static,
|
|
L: 'static,
|
|
B: 'static,
|
|
> AddGeneric<T> for Setup<SR, L, B, Rs, As>
|
|
where
|
|
T::Artifact: Clone,
|
|
RegularSetupCore<SR, L, B>: 'static + SetupCore<T, Self>,
|
|
{
|
|
async fn add_generic(&self, logger: &Rc<Logger>, r: T) -> InternalAddResult<T> {
|
|
self.add(logger, r, false).await
|
|
}
|
|
}
|
|
|
|
#[async_trait(?Send)]
|
|
pub trait SetupCore<R: AddableResource, S> {
|
|
async fn add<RR: AsRef<R>>(
|
|
&self,
|
|
setup: &S,
|
|
logger: &Rc<Logger>,
|
|
resource: RR,
|
|
force_run: bool,
|
|
) -> InternalAddResult<R>;
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct RegularSetupCore<SR, L, B> {
|
|
symbol_runner: SR,
|
|
phantom: PhantomData<(L, B)>,
|
|
}
|
|
|
|
impl<SR, L, B> RegularSetupCore<SR, L, B> {
|
|
pub fn new(symbol_runner: SR) -> Self {
|
|
Self {
|
|
symbol_runner,
|
|
phantom: PhantomData::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait(?Send)]
|
|
impl<SR: SymbolRunner, L, B, R: AddableResource, S> SetupCore<R, S> for RegularSetupCore<SR, L, B>
|
|
where
|
|
B: ImplementationBuilder<R>,
|
|
<B as ImplementationBuilder<R>>::Implementation: Runnable + Debug,
|
|
L: ResourceLocator<R>,
|
|
S: AddGeneric<B::Prerequisites> + AddGeneric<<L as ResourceLocator<R>>::Prerequisites>,
|
|
{
|
|
async fn add<RR: AsRef<R>>(
|
|
&self,
|
|
setup: &S,
|
|
logger: &Rc<Logger>,
|
|
resource: RR,
|
|
force_run: bool,
|
|
) -> InternalAddResult<R> {
|
|
let resource = resource.as_ref();
|
|
debug!(logger, "Adding {:?} ... ", resource);
|
|
debug!(logger, "(force_run is {})", force_run);
|
|
let (location, location_prereqs) = L::locate(resource);
|
|
trace!(logger, "Adding location prereqs for {:?}", resource);
|
|
let location_prereq_logger = Rc::new(logger.new(o!("prereq" => "location")));
|
|
let (_, location_prereqs_did_run) = setup
|
|
.add_generic(&location_prereq_logger, location_prereqs)
|
|
.await?;
|
|
trace!(
|
|
logger,
|
|
"Location prereqs for {:?} did_run: {}",
|
|
resource,
|
|
location_prereqs_did_run
|
|
);
|
|
trace!(logger, "Adding implementation prereqs for {:?}", resource);
|
|
let impl_prereq_logger = Rc::new(logger.new(o!("prereq" => "implementation")));
|
|
let (prereqs, prereqs_did_run) = setup
|
|
.add_generic(&impl_prereq_logger, B::prerequisites(resource))
|
|
.await?;
|
|
trace!(
|
|
logger,
|
|
"Implementation prereqs for {:?} did_run: {}",
|
|
resource,
|
|
prereqs_did_run
|
|
);
|
|
trace!(logger, "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) => {
|
|
debug!(logger, "done.");
|
|
Ok((location, did_run))
|
|
}
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[async_trait(?Send)]
|
|
impl<SR: SymbolRunner, L, B> SymbolRunner for RegularSetupCore<SR, L, B> {
|
|
async fn run_symbol<S: Symbol + Debug>(
|
|
&self,
|
|
symbol: &S,
|
|
logger: &Logger,
|
|
force: bool,
|
|
) -> Result<bool, Box<dyn Error>> {
|
|
debug!(logger, "Directly running {:?} ...", symbol);
|
|
let result = self.symbol_runner.run_symbol(symbol, logger, force).await;
|
|
debug!(logger, "done.");
|
|
result
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::super::setup::Setup;
|
|
use super::AddGeneric;
|
|
use crate::async_utils::run;
|
|
use crate::DrySymbolRunner;
|
|
use std::rc::Rc;
|
|
|
|
#[test]
|
|
fn empty() {
|
|
let setup: Setup<_, (), (), (), ()> = Setup::new(DrySymbolRunner);
|
|
run(async {
|
|
assert!(setup
|
|
.add_generic(&Rc::new(slog::Logger::root(slog::Discard, slog::o!())), ())
|
|
.await
|
|
.is_ok());
|
|
})
|
|
}
|
|
}
|