use crate::parse::{pattern::PatternDefinition, strategy::InputStrategy};
use proc_macro2::Span;
use syn::{Arm, Expr, Result, spanned::Spanned};
#[derive(Clone)]
pub struct CaseDefinition {
pub index: usize,
pub strategy: InputStrategy,
pub pattern: PatternDefinition,
pub guard: Option<Expr>,
pub body: Expr,
pub span: Span,
}
impl CaseDefinition {
pub fn parse(input: Arm, index: usize) -> Result<Self> {
let span = input.span();
let Arm {
attrs,
pat,
guard,
body,
..
} = input;
let strategy = InputStrategy::parse(attrs)?;
let pattern = PatternDefinition::parse(pat)?;
let guard_option = match guard {
Some((_, expr)) => Some(*expr),
_ => None,
};
Ok(CaseDefinition {
index,
strategy,
pattern,
guard: guard_option,
body: *body,
span,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use proc_macro_utils::assert_tokens;
use quote::ToTokens;
use syn::{Arm, parse_quote};
#[test]
fn test_parse_simple_case() {
let input: Arm = parse_quote! {
(A(x), B(y)) if x == y => println!("Success!")
};
let expected_strategy = InputStrategy::Auto;
let result = CaseDefinition::parse(input, 0).unwrap();
assert_eq!(expected_strategy, result.strategy);
assert_tokens!(result.guard.unwrap().to_token_stream(), { x == y });
assert_tokens!(result.body.to_token_stream(), { println!("Success!") });
}
#[test]
fn test_parse_case_without_guard() {
let input: Arm = parse_quote! {
(A(x), B(y)) => println!("No guard!")
};
let expected_strategy = InputStrategy::Auto;
let result = CaseDefinition::parse(input, 0).unwrap();
assert_eq!(expected_strategy, result.strategy);
assert!(result.guard.is_none());
assert_tokens!(result.body.to_token_stream(), { println!("No guard!") });
}
#[test]
fn test_parse_case_with_strategy_attribute() {
let input: Arm = parse_quote! {
#[BruteForce]
(A(x), B(y)) => x + y
};
let expected_strategy = InputStrategy::BruteForce;
let result = CaseDefinition::parse(input, 0).unwrap();
assert_eq!(expected_strategy, result.strategy);
assert!(result.guard.is_none());
assert_tokens!(result.body.to_token_stream(), { x + y });
}
#[test]
fn test_parse_case_with_complex_guard() {
let input: Arm = parse_quote! {
(A(x), B(y)) if x > 0 && y < 10 => x * y
};
let expected_strategy = InputStrategy::Auto;
let result = CaseDefinition::parse(input, 0).unwrap();
assert_eq!(expected_strategy, result.strategy);
assert_tokens!(result.guard.unwrap().to_token_stream(), { x > 0 && y < 10 });
assert_tokens!(result.body.to_token_stream(), { x * y });
}
#[test]
fn test_parse_case_with_block_body() {
let input: Arm = parse_quote! {
(A(x), B(y)) => {
let sum = x + y;
println!("Sum: {}", sum);
sum
}
};
let expected_strategy = InputStrategy::Auto;
let result = CaseDefinition::parse(input, 0).unwrap();
assert_eq!(expected_strategy, result.strategy);
assert!(result.guard.is_none());
assert_tokens!(result.body.to_token_stream(), {
{
let sum = x + y;
println!("Sum: {}", sum);
sum
}
});
}
}