Experiment with futures
This commit is contained in:
parent
907fbf95db
commit
2d3e3688fa
44 changed files with 2081 additions and 1242 deletions
193
src/setup/runnable.rs
Normal file
193
src/setup/runnable.rs
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
use super::SymbolRunner;
|
||||
use crate::loggers::Logger;
|
||||
use crate::symbols::Symbol;
|
||||
use async_trait::async_trait;
|
||||
use std::error::Error;
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[async_trait(?Send)]
|
||||
pub trait Runnable {
|
||||
async fn run<R: SymbolRunner, L: Logger>(
|
||||
&self,
|
||||
runner: &R,
|
||||
logger: &L,
|
||||
force: bool,
|
||||
) -> Result<bool, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<S> Runnable for S
|
||||
where
|
||||
Self: Symbol + Debug,
|
||||
{
|
||||
async fn run<R: SymbolRunner, L: Logger>(
|
||||
&self,
|
||||
runner: &R,
|
||||
logger: &L,
|
||||
force: bool,
|
||||
) -> Result<bool, Box<dyn Error>> {
|
||||
runner.run_symbol(self, logger, force).await
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! runnable_for_tuple {
|
||||
( $($name:ident)* ) => (
|
||||
#[async_trait(?Send)]
|
||||
#[allow(non_snake_case)]
|
||||
impl<$($name: Symbol + Debug,)*> Runnable for ($($name,)*) {
|
||||
#[allow(unused)]
|
||||
async fn run<_R: SymbolRunner, _L: Logger>(&self, runner: &_R, logger: &_L, force: bool) -> Result<bool, Box<dyn Error>> {
|
||||
let ($($name,)*) = self;
|
||||
let mut result = false;
|
||||
$(result = runner.run_symbol($name, logger, force || result).await? || result;)*
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
for_each_tuple!(runnable_for_tuple);
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Runnable;
|
||||
use crate::async_utils::run;
|
||||
use crate::loggers::{Logger, StoringLogger};
|
||||
use crate::symbols::Symbol;
|
||||
use crate::SymbolRunner;
|
||||
use async_trait::async_trait;
|
||||
use std::cell::RefCell;
|
||||
use std::error::Error;
|
||||
use std::fmt::Debug;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DummySymbol<T, E> {
|
||||
_target_reached: RefCell<T>,
|
||||
_execute: RefCell<E>,
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl<
|
||||
E: Iterator<Item = Result<(), Box<dyn Error>>>,
|
||||
T: Iterator<Item = Result<bool, Box<dyn Error>>>,
|
||||
> Symbol for DummySymbol<T, E>
|
||||
{
|
||||
async fn target_reached(&self) -> Result<bool, Box<dyn Error>> {
|
||||
self._target_reached.borrow_mut().next().unwrap()
|
||||
}
|
||||
async fn execute(&self) -> Result<(), Box<dyn Error>> {
|
||||
self._execute.borrow_mut().next().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
E: Iterator<Item = Result<(), Box<dyn Error>>>,
|
||||
T: Iterator<Item = Result<bool, Box<dyn Error>>>,
|
||||
> DummySymbol<T, E>
|
||||
{
|
||||
fn new<
|
||||
IE: IntoIterator<IntoIter = E, Item = Result<(), Box<dyn Error>>>,
|
||||
IT: IntoIterator<IntoIter = T, Item = Result<bool, Box<dyn Error>>>,
|
||||
>(
|
||||
target_reached: IT,
|
||||
execute: IE,
|
||||
) -> Self {
|
||||
Self {
|
||||
_target_reached: RefCell::new(target_reached.into_iter()),
|
||||
_execute: RefCell::new(execute.into_iter()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TestSymbolRunner {
|
||||
count: Rc<RefCell<usize>>,
|
||||
}
|
||||
|
||||
fn get_runner() -> (Rc<RefCell<usize>>, TestSymbolRunner) {
|
||||
let count = Rc::new(RefCell::new(0));
|
||||
let runner = TestSymbolRunner {
|
||||
count: Rc::clone(&count),
|
||||
};
|
||||
(count, runner)
|
||||
}
|
||||
|
||||
#[async_trait(?Send)]
|
||||
impl SymbolRunner for TestSymbolRunner {
|
||||
async fn run_symbol<S: Symbol + Debug, L: Logger>(
|
||||
&self,
|
||||
symbol: &S,
|
||||
logger: &L,
|
||||
force: bool,
|
||||
) -> Result<bool, Box<dyn Error>> {
|
||||
let run = force || !symbol.target_reached().await?;
|
||||
if run {
|
||||
*self.count.borrow_mut() += 1;
|
||||
}
|
||||
Ok(run)
|
||||
}
|
||||
}
|
||||
|
||||
fn run_symbol(
|
||||
runnable: impl Runnable,
|
||||
force: bool,
|
||||
) -> (Rc<RefCell<usize>>, Result<bool, Box<dyn Error>>) {
|
||||
let (count, runner) = get_runner();
|
||||
let res = run(runnable.run(&runner, &StoringLogger::new(), force));
|
||||
(count, res)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn correctly_handles_symbol_tuples() {
|
||||
let (count, res) = run_symbol(
|
||||
(
|
||||
DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
|
||||
DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
|
||||
),
|
||||
false,
|
||||
);
|
||||
res.unwrap();
|
||||
assert_eq!(*count.borrow(), 2);
|
||||
|
||||
let (count, res) = run_symbol(
|
||||
(
|
||||
DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
|
||||
DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
|
||||
),
|
||||
false,
|
||||
);
|
||||
res.unwrap();
|
||||
assert_eq!(*count.borrow(), 1);
|
||||
|
||||
// An unreached symbol forces all further symbols
|
||||
let (count, res) = run_symbol(
|
||||
(
|
||||
DummySymbol::new(vec![Ok(false)], vec![Ok(())]),
|
||||
DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
|
||||
),
|
||||
false,
|
||||
);
|
||||
res.unwrap();
|
||||
assert_eq!(*count.borrow(), 2);
|
||||
|
||||
let (count, res) = run_symbol(
|
||||
(
|
||||
DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
|
||||
DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
|
||||
),
|
||||
false,
|
||||
);
|
||||
res.unwrap();
|
||||
assert_eq!(*count.borrow(), 0);
|
||||
|
||||
let (count, res) = run_symbol(
|
||||
(
|
||||
DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
|
||||
DummySymbol::new(vec![Ok(true)], vec![Ok(())]),
|
||||
),
|
||||
true,
|
||||
);
|
||||
res.unwrap();
|
||||
assert_eq!(*count.borrow(), 2);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue