use std::error::Error; use std::fmt; use resources::Resource; use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; pub struct Hook where A: Symbol, B: Symbol { a: A, b: B } // A and B are executed if either A or B are not reached impl Hook where A: Symbol, B: Symbol { pub fn new(a: A, b: B) -> Self { Hook { a, b } } } impl Symbol for Hook where A: Symbol, B: Symbol { fn target_reached(&self) -> Result> { self.a.target_reached().and_then(|reached| if reached { self.b.target_reached() } else { Ok(reached) }) } fn execute(&self) -> Result<(), Box> { try!(self.a.execute()); self.b.execute() } fn get_prerequisites(&self) -> Vec { let mut r = vec![]; r.extend(self.a.get_prerequisites().into_iter()); r.extend(self.b.get_prerequisites().into_iter()); r } fn provides(&self) -> Option> { let mut r = vec![]; if let Some(provides) = self.a.provides() { r.extend(provides.into_iter()); } if let Some(provides) = self.b.provides() { r.extend(provides.into_iter()); } if r.is_empty() { None } else { Some(r) } } fn as_action<'a>(&'a self, runner: &'a SymbolRunner) -> Box { Box::new(SymbolAction::new(runner, self)) } fn into_action<'a>(self: Box, runner: &'a SymbolRunner) -> Box where Self: 'a { Box::new(OwnedSymbolAction::new(runner, *self)) } } impl fmt::Display for Hook where A: Symbol, B: Symbol { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>{ write!(f, "Hook {} and then {}", self.a, self.b) } } #[cfg(test)] mod test { use std::error::Error; use std::fmt; use symbols::{Action, OwnedSymbolAction, Symbol, SymbolAction, SymbolRunner}; use symbols::hook::Hook; 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()) } fn as_action<'a>(&'a self, runner: &'a SymbolRunner) -> Box { Box::new(SymbolAction::new(runner, self)) } fn into_action<'a>(self: Box, runner: &'a SymbolRunner) -> Box where Self: 'a { Box::new(OwnedSymbolAction::new(runner, *self)) } } 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(()) } fn as_action<'a>(&'a self, runner: &'a SymbolRunner) -> Box { Box::new(SymbolAction::new(runner, self)) } fn into_action<'a>(self: Box, runner: &'a SymbolRunner) -> Box where Self: 'a { Box::new(OwnedSymbolAction::new(runner, *self)) } } 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 = Hook::new(ErrSymbol("first".into()), ErrSymbol("second".into())).target_reached(); assert_eq!(res.unwrap_err().description(), "first"); } #[test] fn first_target_not_reached() { let res = Hook::new(OkSymbol(false), ErrSymbol("second".into())).target_reached(); assert_eq!(res.unwrap(), false); } #[test] fn second_target_reached_fails() { let res = Hook::new(OkSymbol(true), ErrSymbol("second".into())).target_reached(); assert_eq!(res.unwrap_err().description(), "second"); } #[test] fn second_target_not_reached() { let res = Hook::new(OkSymbol(true), OkSymbol(false)).target_reached(); assert_eq!(res.unwrap(), false); } #[test] fn everything_reached() { let res = Hook::new(OkSymbol(true), OkSymbol(true)).target_reached(); assert_eq!(res.unwrap(), true); } #[test] fn first_execute_fails() { let res = Hook::new(ErrSymbol("first".into()), ErrSymbol("second".into())).execute(); assert_eq!(res.unwrap_err().description(), "first"); } #[test] fn second_execute_fails() { let res = Hook::new(OkSymbol(true), ErrSymbol("second".into())).execute(); assert_eq!(res.unwrap_err().description(), "second"); } #[test] fn everything_executes() { let res = Hook::new(OkSymbol(true), OkSymbol(true)).execute(); assert_eq!(res.unwrap(), ()); } }