use syn::{Expr, parse::{Parse, ParseStream}, Token, ExprCall}; pub struct Arm { pub key: Expr, pub value: Expr, } pub struct Input { pub hash_function: Expr, pub target: Expr, pub arms: Vec, pub default_arm: Expr, } enum MatchArm { Wild(Expr), Pat(Arm), } impl Parse for MatchArm { fn parse(input: ParseStream) -> syn::Result { let key = if input.peek(Token![_]) { input.parse::().unwrap(); None } else { Some(input.parse::()?) }; input.parse::]>()?; let value = input.parse::()?; let result = match key { Some(key) => MatchArm::Pat(Arm { key, value }), None => MatchArm::Wild(value), }; Ok(result) } } impl Parse for Input { fn parse(input: ParseStream) -> syn::Result { input.parse::()?; let function = input.parse::()?; if function.args.len() != 1 { return Err(input.error("Expected a function call with 1 argument")); } let target = function.args.into_iter().next().unwrap(); let hash_function = *function.func; let match_inner; let _ = syn::braced!(match_inner in input); let match_arms = match_inner.parse_terminated(MatchArm::parse, Token![,])?; let mut arms = Vec::new(); let mut default_arm = None; for i in match_arms { match i { MatchArm::Wild(expr) => { if default_arm.replace(expr).is_some() { return Err(input.error("Wild pattern provided twice")); } }, MatchArm::Pat(arm) => { arms.push(arm); }, } } let default_arm = default_arm .ok_or_else(|| input.error("Wild pattern (_) wasn't provided"))?; Ok(Self { hash_function, target, arms, default_arm, }) } }