|
|
@ -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<Rs, As> = HashMap<Rs, Shared<Pin<Box<dyn Future<Output = (As, bool)>>>>>;
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct SetupInner<CORE, LOG, Rs, As> {
|
|
|
|
struct SetupInner<CORE, Rs, As> {
|
|
|
|
core: CORE,
|
|
|
|
logger: LOG,
|
|
|
|
resources: RefCell<Cache<Rs, As>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Setup<
|
|
|
|
SR,
|
|
|
|
LOG,
|
|
|
|
L = DefaultLocator,
|
|
|
|
B = DefaultBuilder,
|
|
|
|
Rs = DefaultResources<'static, &'static str>,
|
|
|
|
As = DefaultArtifacts<'static, &'static str>,
|
|
|
|
>(Rc<SetupInner<RegularSetupCore<SR, L, B>, LOG, Rs, As>>);
|
|
|
|
|
|
|
|
// https://github.com/rust-lang/rust/issues/27336
|
|
|
|
impl<SR, LOG> Setup<SR, LOG> {
|
|
|
|
pub fn new(symbol_runner: SR, logger: LOG) -> Self {
|
|
|
|
Self::new_with(symbol_runner, logger)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pub struct Setup<SR, L, B, Rs, As>(Rc<SetupInner<RegularSetupCore<SR, L, B>, Rs, As>>);
|
|
|
|
|
|
|
|
impl<L, B, As, SR, LOG, Rs: Hash + Eq> Setup<SR, LOG, L, B, Rs, As> {
|
|
|
|
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<SR, LOG, L, B, Rs, As>
|
|
|
|
impl<L: 'static, B: 'static, SR: 'static, Rs: Hash + Eq + 'static, As: 'static>
|
|
|
|
Setup<SR, L, B, Rs, As>
|
|
|
|
{
|
|
|
|
fn borrow_resources(&self) -> RefMut<'_, Cache<Rs, As>> {
|
|
|
|
self.0.resources.borrow_mut()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn add_force<R: AddableResource>(&self, resource: R, force_run: bool) -> AddResult<R>
|
|
|
|
pub async fn add<R: AddableResource>(&self, resource: R, force_run: bool) -> InternalAddResult<R>
|
|
|
|
where
|
|
|
|
Rs: FromResource<R>,
|
|
|
|
As: FromArtifact<R> + 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<Error> 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<dyn Future<Output = (As, bool)>>>)
|
|
|
|
(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<Box<dyn Future<Output = (As, bool)>>>)
|
|
|
|
.shared(),
|
|
|
|
);
|
|
|
|
drop(resources);
|
|
|
|
future.await.map_err(|e| e.into())
|
|
|
|
let result = future.await;
|
|
|
|
result.map_err(|(logger, e)| (logger, e.into()))
|
|
|
|
};
|
|
|
|
result.map(|(logger, t, did_run)| (logger, t.into_artifact(), did_run))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct SetupFacade<
|
|
|
|
SR,
|
|
|
|
LOG,
|
|
|
|
L = DefaultLocator,
|
|
|
|
B = DefaultBuilder,
|
|
|
|
Rs = DefaultResources<'static, &'static str>,
|
|
|
|
As = DefaultArtifacts<'static, &'static str>,
|
|
|
|
>(LOG, Setup<SR, L, B, Rs, As>);
|
|
|
|
|
|
|
|
impl<SR, LOG> SetupFacade<SR, LOG> {
|
|
|
|
pub fn new(symbol_runner: SR, logger: LOG) -> Self {
|
|
|
|
Self::new_with(symbol_runner, logger)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<L, B, As, SR, LOG, Rs: Hash + Eq> SetupFacade<SR, LOG, L, B, Rs, As> {
|
|
|
|
pub fn new_with(symbol_runner: SR, logger: LOG) -> Self {
|
|
|
|
Self(
|
|
|
|
logger,
|
|
|
|
Setup(Rc::new(SetupInner {
|
|
|
|
core: RegularSetupCore::new(symbol_runner),
|
|
|
|
resources: RefCell::default(),
|
|
|
|
})),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
.map(|(t, did_run)| (t.into_artifact(), did_run))
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Legacy
|
|
|
|
//
|
|
|
|
impl<
|
|
|
|
SR: 'static,
|
|
|
|
LOG: 'static + Logger,
|
|
|
|
L: 'static,
|
|
|
|
B: 'static,
|
|
|
|
Rs: 'static + Eq + Hash,
|
|
|
|
As: 'static,
|
|
|
|
> SetupFacade<SR, LOG, L, B, Rs, As>
|
|
|
|
{
|
|
|
|
pub async fn add_force<R: AddableResource>(&self, resource: R, force_run: bool) -> AddResult<R>
|
|
|
|
where
|
|
|
|
Rs: FromResource<R>,
|
|
|
|
As: FromArtifact<R> + Clone,
|
|
|
|
R::Artifact: Clone,
|
|
|
|
RegularSetupCore<SR, L, B>: SetupCore<R, Setup<SR, L, B, Rs, As>>,
|
|
|
|
{
|
|
|
|
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<R: AddableResource>(&self, resource: R) -> AddResult<R>
|
|
|
|
where
|
|
|
|
RegularSetupCore<SR, L, B>: SetupCore<R, Self>,
|
|
|
|
RegularSetupCore<SR, L, B>: SetupCore<R, Setup<SR, L, B, Rs, As>>,
|
|
|
|
Rs: FromResource<R>,
|
|
|
|
As: FromArtifact<R> + Clone,
|
|
|
|
R::Artifact: Clone,
|
|
|
|
SR: SymbolRunner,
|
|
|
|
{
|
|
|
|
self.add_force(resource, false).await
|
|
|
|
}
|
|
|
@ -130,7 +173,7 @@ impl< |
|
|
|
where
|
|
|
|
RegularSetupCore<SR, L, B>: SymbolRunner,
|
|
|
|
{
|
|
|
|
symbol.run(&self.0.core, &self.0.logger, force).await
|
|
|
|
symbol.run(&(self.1).0.core, &self.0, force).await
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|