use proc_macro2::TokenStream;
use quote::{ToTokens, quote_spanned};
use syn::Ident;
use crate::parse::{context::Context, pattern::PatternDefinition};
use crate::traits::Pattern;
pub struct KeyExtractionCompiler;
impl KeyExtractionCompiler {
pub fn generate(
pattern: &PatternDefinition,
uniting_vars: &Vec<String>,
key_fn_ident: &Ident,
context: Context,
) -> TokenStream {
let sub_patterns = pattern
.sub_patterns()
.into_iter()
.map(|sp| sp.get().to_syn_pattern().to_token_stream())
.collect::<Vec<_>>();
let uniting_var_idents = uniting_vars
.iter()
.map(|var| Ident::new(var, pattern.span()))
.collect::<Vec<_>>();
let key = quote_spanned!(pattern.span() => (#(#uniting_var_idents.clone()),*));
let message_type = context.message_type;
quote_spanned! {
pattern.span() =>
fn #key_fn_ident(message: &#message_type) -> Option<fairjax_core::AnyKeyBox> {
#[allow(unused_variables, unreachable_patterns)]
match message {
#(#sub_patterns => Some(fairjax_core::AnyKeyBox::new(#key)),)*
_ => None,
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use proc_macro_utils::assert_tokens;
use proc_macro2::Span;
use syn::{Pat, parse_quote};
#[test]
fn test_generate_key_extraction_compiler() {
let match_arm_pattern: Pat = parse_quote!((
A(id, 42, id2),
B {
a,
b: id,
c: "hello",
d: id2
}
));
let pattern = PatternDefinition::parse(match_arm_pattern).unwrap();
let uniting_vars = vec!["id".to_string(), "id2".to_string()];
let key_fn_ident = Ident::new("fn_ident", Span::call_site());
let context = Context {
incoming_message: parse_quote!(unused),
mailbox: parse_quote!(unused),
message_type: parse_quote!(MsgType),
};
let key_code =
KeyExtractionCompiler::generate(&pattern, &uniting_vars, &key_fn_ident, context);
#[rustfmt::skip]
assert_tokens!(key_code, {
fn fn_ident(message: &MsgType) -> Option<fairjax_core::AnyKeyBox> {
#[allow(unused_variables, unreachable_patterns)]
match message {
A(id, 42, id2) => Some( fairjax_core::AnyKeyBox::new(( id.clone(), id2.clone() )) ),
B { a, b: id, c: "hello" , d: id2} => Some( fairjax_core::AnyKeyBox::new(( id.clone(), id2.clone())) ),
_ => None,
}
}
});
}
}