use crate::*; /** Implement `EdnCommand` for given `State` and `Command` */ #[macro_export] macro_rules! edn_command { ($Command:ty : |$state:ident:$State:ty| { $(( // identifier $key:literal [ // named parameters $( // argument name $arg:ident // if type is not provided defaults to EdnItem $( // type:name separator : // argument type $type:ty )? ),* // rest of parameters $(, ..$rest:ident)? ] // bound command: $command:expr ))* }) => { impl EdnCommand<$State> for $Command { fn from_edn <'a> ($state: &$State, head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self { $(if let (EdnItem::Key($key), [ // if the identifier matches // bind argument ids $($arg),* // bind rest parameters $(, $rest @ ..)? ]) = (head, tail) { $( $(let $arg: Option<$type> = EdnProvide::<$type>::get($state, $arg);)? )* //$(edn_command!(@bind $state => $arg $(?)? : $type);)* return $command })* panic!("no such command") } } }; (@bind $state:ident =>$arg:ident ? : $type:ty) => { let $arg: Option<$type> = EdnProvide::<$type>::get($state, $arg); }; (@bind $state:ident => $arg:ident : $type:ty) => { let $arg: $type = EdnProvide::<$type>::get_or_fail($state, $arg); }; } /// Turns an EDN symbol sequence into a command enum variant. pub trait EdnCommand: Command { fn from_edn <'a> (state: &C, head: &EdnItem<&str>, tail: &'a [EdnItem]) -> Self; fn get_isize (state: &C, item: &EdnItem<&str>) -> Option { None } fn get_usize (state: &C, item: &EdnItem<&str>) -> Option { None } fn get_bool (state: &C, item: &EdnItem<&str>) -> Option { None } }