diff options
Diffstat (limited to 'mingling_pathf/src/patterns/chain.rs')
| -rw-r--r-- | mingling_pathf/src/patterns/chain.rs | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/mingling_pathf/src/patterns/chain.rs b/mingling_pathf/src/patterns/chain.rs new file mode 100644 index 0000000..10d698e --- /dev/null +++ b/mingling_pathf/src/patterns/chain.rs @@ -0,0 +1,72 @@ +use syn::Item; + +use crate::pattern_analyzer::{AnalyzeItem, AnalyzePattern}; + +/// Match `#[chain]` functions, extract the generated internal struct name. +/// +/// `#[chain] fn handle_greet(...)` → `__internal_chain_handle_greet` +/// +/// Covered forms: +/// - `#[chain] fn handle(args: EntryType) -> Next { ... }` +/// - `#[chain] fn handle(args: EntryType, res: &mut Res) -> Next { ... }` +/// - async version +pub struct ChainPattern; + +impl AnalyzePattern for ChainPattern { + fn contains(&self, content: &str) -> bool { + content.contains("chain]") + } + + fn analyze(&self, content: &str) -> Vec<AnalyzeItem> { + let Ok(syntax) = syn::parse_file(content) else { + return Vec::new(); + }; + + let mut items = Vec::new(); + + for item in &syntax.items { + collect_from_item(item, "", &mut items); + } + + items + } +} + +fn internal_name(fn_name: &str) -> String { + format!("__internal_chain_{fn_name}") +} + +fn collect_from_item(item: &Item, current_mod: &str, items: &mut Vec<AnalyzeItem>) { + match item { + Item::Fn(f) if has_attr(&f.attrs, "chain") => { + let fn_name = f.sig.ident.to_string(); + items.push(AnalyzeItem { + module: current_mod.to_string(), + item_name: internal_name(&fn_name), + }); + } + Item::Mod(item_mod) => { + if let Some((_, nested)) = &item_mod.content { + let mod_name = &item_mod.ident.to_string(); + let nested_mod = if current_mod.is_empty() { + mod_name.clone() + } else { + format!("{current_mod}::{mod_name}") + }; + for n in nested { + collect_from_item(n, &nested_mod, items); + } + } + } + _ => {} + } +} + +fn has_attr(attrs: &[syn::Attribute], name: &str) -> bool { + attrs.iter().any(|a| { + a.path() + .segments + .last() + .is_some_and(|s| s.ident == name) + }) +} |
