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<Arm>,
pub default_arm: Expr,
}
enum MatchArm {
Wild(Expr),
Pat(Arm),
}
impl Parse for MatchArm {
fn parse(input: ParseStream) -> syn::Result<Self> {
let key = if input.peek(Token![_]) {
input.parse::<Token![_]>().unwrap();
None
} else {
Some(input.parse::<Expr>()?)
};
input.parse::<Token![=>]>()?;
let value = input.parse::<Expr>()?;
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<Self> {
input.parse::<Token![match]>()?;
let function = input.parse::<ExprCall>()?;
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,
})
}
}