use std::error::Error; use std::fmt; use resources::Resource; use symbols::{Action, Symbol, SymbolRunner}; pub struct List<'a> { symbols: Vec>, } impl<'a> List<'a> { pub fn new(symbols: Vec>) -> Self { List { symbols } } } impl<'a> Symbol for List<'a> { fn target_reached(&self) -> Result> { for symbol in &self.symbols { if !symbol.target_reached()? { return Ok(false); } } Ok(true) } fn execute(&self) -> Result<(), Box> { for symbol in &self.symbols { symbol.execute()?; } Ok(()) } fn get_prerequisites(&self) -> Vec { let mut r = vec![]; for symbol in &self.symbols { for req in symbol.get_prerequisites() { if self.provides().map_or(true, |p| !p.contains(&req)) { r.push(req) } } } r } fn provides(&self) -> Option> { let mut r = vec![]; for symbol in &self.symbols { if let Some(provides) = symbol.provides() { r.extend(provides.into_iter()); } } if r.is_empty() { None } else { Some(r) } } fn as_action<'b>(&'b self, runner: &'b dyn SymbolRunner) -> Box { Box::new(SymbolListAction::new(runner, &self.symbols)) } fn into_action<'b>(self: Box, runner: &'b dyn SymbolRunner) -> Box where Self: 'b, { Box::new(ListAction::new( self .symbols .into_iter() .map(|s| s.into_action(runner)) .collect(), )) } } macro_rules! from_tuple { ( $($name:ident)* ) => ( #[allow(non_snake_case)] impl<'a, $($name: 'a + Symbol,)*> From<($($name,)*)> for List<'a> { fn from(($($name,)*): ($($name,)*)) -> Self { Self::new(vec![$(Box::new($name),)*]) } } ); } for_each_tuple!(from_tuple); struct SymbolListAction<'a> { runner: &'a dyn SymbolRunner, symbols: &'a [Box], } impl<'a> SymbolListAction<'a> { fn new(runner: &'a dyn SymbolRunner, symbols: &'a [Box]) -> Self { Self { runner, symbols } } } impl<'a> Action for SymbolListAction<'a> { fn run(&self) -> Result<(), Box> { for symbol in self.symbols { symbol.as_action(self.runner).run()?; } Ok(()) } } pub struct ListAction<'a> { actions: Vec>, } impl<'a> ListAction<'a> { pub fn new(actions: Vec>) -> Self { Self { actions } } } impl<'a> Action for ListAction<'a> { fn run(&self) -> Result<(), Box> { for action in &self.actions { action.run()?; } Ok(()) } } impl<'a> fmt::Display for List<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { write!(f, "List [ ")?; for symbol in &self.symbols { write!(f, "{} ", symbol)?; } write!(f, "]") } } /* #[cfg(test)] mod test { use std::error::Error; use std::fmt; use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; use symbols::hook::List; struct ErrSymbol(String); impl Symbol for ErrSymbol { fn target_reached(&self) -> Result> { Err(self.0.clone().into()) } fn execute(&self) -> Result<(), Box> { Err(self.0.clone().into()) } } impl fmt::Display for ErrSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } } struct OkSymbol(bool); impl Symbol for OkSymbol { fn target_reached(&self) -> Result> { Ok(self.0) } fn execute(&self) -> Result<(), Box> { Ok(()) } } impl fmt::Display for OkSymbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "") } } #[test] fn first_target_reached_fails() { let res = List::new(ErrSymbol("first".into()), ErrSymbol("second".into())).target_reached(); assert_eq!(res.unwrap_err().description(), "first"); } #[test] fn first_target_not_reached() { let res = List::new(OkSymbol(false), ErrSymbol("second".into())).target_reached(); assert_eq!(res.unwrap(), false); } #[test] fn second_target_reached_fails() { let res = List::new(OkSymbol(true), ErrSymbol("second".into())).target_reached(); assert_eq!(res.unwrap_err().description(), "second"); } #[test] fn second_target_not_reached() { let res = List::new(OkSymbol(true), OkSymbol(false)).target_reached(); assert_eq!(res.unwrap(), false); } #[test] fn everything_reached() { let res = List::new(OkSymbol(true), OkSymbol(true)).target_reached(); assert_eq!(res.unwrap(), true); } #[test] fn first_execute_fails() { let res = List::new(ErrSymbol("first".into()), ErrSymbol("second".into())).execute(); assert_eq!(res.unwrap_err().description(), "first"); } #[test] fn second_execute_fails() { let res = List::new(OkSymbol(true), ErrSymbol("second".into())).execute(); assert_eq!(res.unwrap_err().description(), "second"); } #[test] fn everything_executes() { let res = List::new(OkSymbol(true), OkSymbol(true)).execute(); assert_eq!(res.unwrap(), ()); } } */