use crate::*; /// Implement `EdnProvide` for a type and context #[macro_export] macro_rules! edn_provide { ($lt:lifetime: $type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { impl<$lt> EdnProvide<$lt, $type> for $State { fn get > (&$lt $self, edn: &$lt EdnItem) -> Option<$type> { Some(match edn.to_ref() { $(EdnItem::Sym($pat) => $expr,)* _ => return None }) } } }; ($type:ty:|$self:ident:$State:ty|{ $($pat:pat => $expr:expr),* $(,)? }) => { impl<'a> EdnProvide<'a, $type> for $State { fn get > (&'a $self, edn: &'a EdnItem) -> Option<$type> { Some(match edn.to_ref() { $(EdnItem::Sym($pat) => $expr,)* _ => return None }) } } }; } /// Map EDN tokens to parameters of a given type for a given context pub trait EdnProvide<'a, U>: Sized { fn get > (&'a self, _edn: &'a EdnItem) -> Option { None } fn get_or_fail > (&'a self, edn: &'a EdnItem) -> U { self.get(edn).expect("no value") } } impl<'a, T: EdnProvide<'a, U>, U> EdnProvide<'a, U> for &T { fn get > (&'a self, edn: &'a EdnItem) -> Option { (*self).get(edn) } fn get_or_fail > (&'a self, edn: &'a EdnItem) -> U { (*self).get_or_fail(edn) } } impl<'a, T: EdnProvide<'a, U>, U> EdnProvide<'a, U> for Option { fn get > (&'a self, edn: &'a EdnItem) -> Option { self.as_ref().map(|s|s.get(edn)).flatten() } fn get_or_fail > (&'a self, edn: &'a EdnItem) -> U { self.as_ref().map(|s|s.get_or_fail(edn)).expect("no provider") } }