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
#[derive(Debug)] pub enum DecorationError { Unknown(Option<String>), StringEmpty, } pub trait StringDecorator { fn decorate(&self, text: &String) -> Result<String, DecorationError>; } pub trait ForcedStringDecorator { fn force_decorate(&self, text: &String) -> String; } impl<T> ForcedStringDecorator for T where T: StringDecorator { fn force_decorate(&self, text: &String) -> String { match self.decorate(text) { Ok(s) => s, Err(e) => panic!("Error decorating text: {:?}", e), } } } pub trait Decoratable { fn decorate(&self, decorators: &Vec<Box<dyn StringDecorator>>) -> Result<String, DecorationError>; } impl<T> Decoratable for T where T: ToString { fn decorate(&self, decorators: &Vec<Box<dyn StringDecorator>>) -> Result<String, DecorationError> { let mut s = self.to_string(); for decorator in decorators { match decorator.decorate(&s) { Ok(decorated) => s = decorated, error => return error, } } Ok(s) } } #[cfg(test)] mod decoratable_tests { use crate::{Decoratable, StringDecorator}; use crate::decorators::{Alternate, VaporWave}; #[test] fn test_decorate() { let text = "Hello, World"; let decorators: Vec<Box<dyn StringDecorator>> = vec![ Box::new(VaporWave), Box::new(Alternate), ]; assert_eq!("H e L l O , w O r L d".to_string(), text.decorate(&decorators).unwrap()); } }