type Func<S, T, E> = dyn Fn(&mut S, E) -> T + Sync;

pub struct Processor<S: 'static, T: 'static, E: Clone + 'static> {
    processors: Vec<Box<Func<S, Option<T>, E>>>,
    default: &'static Func<S, T, E>,
}

impl<S: 'static, T: 'static, E: Clone + 'static> Processor<S, T, E> {
    pub fn new<F>(f: &'static F) -> Processor<S, T, E>
    where
        F: Fn(&mut S, E) -> T + Sync + 'static,
    {
        Processor {
            processors: vec![],
            default: f,
        }
    }

    pub fn register<F, A>(&mut self, f: &'static F)
    where
        F: Fn(&mut S, A) -> T + Sync + 'static,
        A: std::convert::TryFrom<E>,
    {
        self.processors.push(Box::new(move |s, e: E| {
            (e.try_into().ok() as Option<A>).map(|a| f(s, a))
        }));
    }

    pub fn process(&self, s: &mut S, e: E) -> T {
        for processor in self.processors.iter() {
            match processor(s, e.clone()) {
                Some(t) => return t,
                None => continue,
            }
        }
        (*self.default)(s, e)
    }
}