1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
use err_derive::Error; use log::info; #[derive(Error, Debug)] pub enum ModuleError { #[error(display = "ModuleBuilderError: [{}]", message)] ModuleBuilderError { message: String }, #[error(display = "ModuleStartError: [{}]", message)] ModuleStartError { message: String }, } pub trait ModuleBuilder<T: Module> { fn build(&self) -> Result<T, ModuleError>; } pub trait Module { fn start(&mut self) -> Result<(), ModuleError>; } pub fn start(modules: &mut [&mut dyn Module]) -> Result<(), ModuleError> { info!("Begin modules 'start' phase"); for module in modules.iter_mut() { module.start()?; } Ok(()) } #[cfg(test)] mod test { use std::sync::Mutex; use crate::ModuleError; use std::rc::Rc; #[test] fn should_start_all() { let output = Rc::new(Mutex::new(vec![])); let mut mod1 = SimpleModOne { output: output.clone(), name: "one".to_string(), }; let mut mod2 = SimpleModTwo { output: output.clone(), name: "two".to_string(), fail: false }; let mut modules: Vec<&mut dyn super::Module> = vec![&mut mod1, &mut mod2]; let result = super::start(modules.as_mut()); assert!(result.is_ok()); assert_eq!(2, output.lock().unwrap().len()); assert_eq!( &"one-start".to_string(), output.lock().unwrap().get(0).unwrap() ); assert_eq!( &"two-start".to_string(), output.lock().unwrap().get(1).unwrap() ); } #[test] fn should_fail_on_start() { let output = Rc::new(Mutex::new(vec![])); let mut mod1 = SimpleModOne { output: output.clone(), name: "one".to_string(), }; let mut mod2 = SimpleModTwo { output: output.clone(), name: "two".to_string(), fail: true }; let mut modules: Vec<&mut dyn super::Module> = vec![&mut mod1, &mut mod2]; let result = super::start(&mut modules); assert!(result.is_err()); match result { Err(err) => match err { ModuleError::ModuleStartError {message} => assert_eq!("test_failure", message), _ => assert!(false) }, _ => assert!(false) } assert_eq!(1, output.lock().unwrap().len()); assert_eq!( &"one-start".to_string(), output.lock().unwrap().get(0).unwrap() ); } #[derive(Clone)] struct SimpleModOne { output: Rc<Mutex<Vec<String>>>, name: String, } impl super::Module for SimpleModOne { fn start(&mut self) -> Result<(), ModuleError> { let mut owned = self.name.to_owned(); owned.push_str(&"-start"); self.output.lock().unwrap().push(owned); Ok(()) } } #[derive(Clone)] struct SimpleModTwo { output: Rc<Mutex<Vec<String>>>, name: String, fail: bool, } impl super::Module for SimpleModTwo { fn start(&mut self) -> Result<(), ModuleError> { if self.fail { return Err(ModuleError::ModuleStartError {message: "test_failure".to_owned()}) } let mut owned = self.name.to_owned(); owned.push_str(&"-start"); self.output.lock().unwrap().push(owned); Ok(()) } } }