aboutsummaryrefslogtreecommitdiff
path: root/mingling_pathf/src/patterns
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_pathf/src/patterns')
-rw-r--r--mingling_pathf/src/patterns/dispatcher.rs24
-rw-r--r--mingling_pathf/src/patterns/dispatcher_clap.rs176
-rw-r--r--mingling_pathf/src/patterns/group.rs34
-rw-r--r--mingling_pathf/src/patterns/metadata.rs7
-rw-r--r--mingling_pathf/src/patterns/pack.rs27
5 files changed, 103 insertions, 165 deletions
diff --git a/mingling_pathf/src/patterns/dispatcher.rs b/mingling_pathf/src/patterns/dispatcher.rs
index cedad9f..85220b5 100644
--- a/mingling_pathf/src/patterns/dispatcher.rs
+++ b/mingling_pathf/src/patterns/dispatcher.rs
@@ -32,7 +32,8 @@ impl DispatcherPattern {
/// * `use_dispatch_tree` — when `true`, the generated dispatcher also produces a
/// `__internal_dispatcher_*` static dispatch tree item. Set this based on whether
/// your macro invocation includes the `use_dispatch_tree` configuration.
- pub fn new(use_dispatch_tree: bool) -> Self {
+ #[must_use]
+ pub const fn new(use_dispatch_tree: bool) -> Self {
Self { use_dispatch_tree }
}
}
@@ -102,9 +103,8 @@ fn extract_all_types(
use_dispatch_tree: bool,
) -> Vec<AnalyzeItem> {
let (cmd_name, cmd_struct, entry_struct) = parse_dispatcher_args(tokens);
- let cmd_name = match cmd_name {
- Some(n) => n,
- None => return Vec::new(),
+ let Some(cmd_name) = cmd_name else {
+ return Vec::new();
};
let mut items = Vec::new();
@@ -128,7 +128,7 @@ fn extract_all_types(
items
}
-/// Parses dispatcher arguments and returns (command_name, cmd_struct, entry_struct).
+/// Parses dispatcher arguments and returns (`command_name`, `cmd_struct`, `entry_struct`).
fn parse_dispatcher_args(
tokens: &proc_macro2::TokenStream,
) -> (Option<String>, Option<String>, Option<String>) {
@@ -166,9 +166,8 @@ fn parse_dispatcher_args(
}
// Implicit form: "name"
- let cmd_name = match extract_string_literal(&stream) {
- Some(n) => n,
- None => return (None, None, None),
+ let Some(cmd_name) = extract_string_literal(&stream) else {
+ return (None, None, None);
};
let pascal = to_pascal_case(&cmd_name);
(
@@ -192,15 +191,14 @@ fn to_pascal_case(s: &str) -> String {
.filter(|s| !s.is_empty())
.map(|s| {
let mut c = s.chars();
- match c.next() {
- None => String::new(),
- Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
- }
+ c.next().map_or_else(String::new, |f| {
+ f.to_uppercase().collect::<String>() + c.as_str()
+ })
})
.collect()
}
-/// Simple snake_case conversion (replaces `.`, `-` with `_`).
+/// Simple `snake_case` conversion (replaces `.`, `-` with `_`).
fn snake_case(s: &str) -> String {
s.replace(['.', '-'], "_").to_lowercase()
}
diff --git a/mingling_pathf/src/patterns/dispatcher_clap.rs b/mingling_pathf/src/patterns/dispatcher_clap.rs
index 25a7093..ca2ce9e 100644
--- a/mingling_pathf/src/patterns/dispatcher_clap.rs
+++ b/mingling_pathf/src/patterns/dispatcher_clap.rs
@@ -39,7 +39,8 @@ impl DispatcherClapPattern {
/// # Parameters
/// - `use_dispatch_tree`: When `true`, enables analysis of the `__internal_dispatcher_*`
/// static dispatch tree for each matched command.
- pub fn new(use_dispatch_tree: bool) -> Self {
+ #[must_use]
+ pub const fn new(use_dispatch_tree: bool) -> Self {
Self { use_dispatch_tree }
}
}
@@ -59,52 +60,7 @@ impl AnalyzePattern for DispatcherClapPattern {
for item in &syntax.items {
match item {
Item::Struct(s) if has_attr(&s.attrs, "dispatcher_clap") => {
- // Entry type (struct name) — always
- let entry_name = s.ident.to_string();
- items.push(AnalyzeItem::local(String::new(), entry_name.clone()));
-
- // Parse the attribute to extract CMD, error, and help info
- if let Some(attr) = s.attrs.iter().find(|a| {
- a.path()
- .segments
- .last()
- .is_some_and(|seg| seg.ident == "dispatcher_clap")
- }) {
- let args = attr.meta.require_list().ok();
- let args_str = args.map(|l| l.tokens.to_string()).unwrap_or_default();
- let parsed = parse_dispatcher_clap_args(&args_str);
-
- // CMD type — always
- if let Some(ref cmd) = parsed.cmd_type {
- items.push(AnalyzeItem::local(String::new(), cmd.clone()));
- }
-
- // Error type — if error = TypeName
- if let Some(ref err) = parsed.error_type {
- items.push(AnalyzeItem::local(String::new(), err.clone()));
- }
-
- // Help internal struct — if help = true
- if parsed.help_enabled
- && let Some(ref cmd) = parsed.cmd_type
- {
- let help_fn = format!("__{}_help", just_fmt::snake_case!(cmd));
- let help_struct =
- format!("__internal_help_{}", just_fmt::snake_case!(&help_fn));
- items.push(AnalyzeItem::local(String::new(), help_struct));
- }
-
- // __internal_dispatcher_* — when configured
- if self.use_dispatch_tree
- && let Some(ref cmd_name) = parsed.cmd_name
- {
- let internal_name = format!(
- "__internal_dispatcher_{}",
- just_fmt::snake_case!(cmd_name)
- );
- items.push(AnalyzeItem::local(String::new(), internal_name));
- }
- }
+ items.extend(self.analyze_struct(s, ""));
}
Item::Mod(item_mod) => {
if let Some((_, nested)) = &item_mod.content {
@@ -112,67 +68,7 @@ impl AnalyzePattern for DispatcherClapPattern {
if let Item::Struct(s) = n
&& has_attr(&s.attrs, "dispatcher_clap")
{
- let entry_name = s.ident.to_string();
- items.push(AnalyzeItem::local(
- item_mod.ident.to_string(),
- entry_name.clone(),
- ));
-
- if let Some(attr) = s.attrs.iter().find(|a| {
- a.path()
- .segments
- .last()
- .is_some_and(|seg| seg.ident == "dispatcher_clap")
- }) {
- let args = attr.meta.require_list().ok();
- let args_str =
- args.map(|l| l.tokens.to_string()).unwrap_or_default();
- let parsed = parse_dispatcher_clap_args(&args_str);
-
- if let Some(ref cmd) = parsed.cmd_type {
- items.push(AnalyzeItem::local(
- item_mod.ident.to_string(),
- cmd.clone(),
- ));
- }
-
- if let Some(ref err) = parsed.error_type {
- items.push(AnalyzeItem::local(
- item_mod.ident.to_string(),
- err.clone(),
- ));
- }
-
- // Help internal struct — same naming rule as root level
- if parsed.help_enabled
- && let Some(ref cmd) = parsed.cmd_type
- {
- let help_fn =
- format!("__{}_help", just_fmt::snake_case!(cmd));
- let help_struct = format!(
- "__internal_help_{}",
- just_fmt::snake_case!(&help_fn)
- );
- items.push(AnalyzeItem::local(
- item_mod.ident.to_string(),
- help_struct,
- ));
- }
-
- // __internal_dispatcher_* — when configured
- if self.use_dispatch_tree
- && let Some(ref cmd_name) = parsed.cmd_name
- {
- let internal_name = format!(
- "__internal_dispatcher_{}",
- just_fmt::snake_case!(cmd_name)
- );
- items.push(AnalyzeItem::local(
- item_mod.ident.to_string(),
- internal_name,
- ));
- }
- }
+ items.extend(self.analyze_struct(s, &item_mod.ident.to_string()));
}
}
}
@@ -185,6 +81,58 @@ impl AnalyzePattern for DispatcherClapPattern {
}
}
+impl DispatcherClapPattern {
+ fn analyze_struct(&self, s: &syn::ItemStruct, module: &str) -> Vec<AnalyzeItem> {
+ let mut items = Vec::new();
+
+ // Entry type (struct name) — always
+ let entry_name = s.ident.to_string();
+ items.push(AnalyzeItem::local(module.to_string(), entry_name));
+
+ // Parse the attribute to extract CMD, error, and help info
+ if let Some(attr) = s.attrs.iter().find(|a| {
+ a.path()
+ .segments
+ .last()
+ .is_some_and(|seg| seg.ident == "dispatcher_clap")
+ }) {
+ let args = attr.meta.require_list().ok();
+ let args_str = args.map(|l| l.tokens.to_string()).unwrap_or_default();
+ let parsed = parse_dispatcher_clap_args(&args_str);
+
+ // CMD type — always
+ if let Some(ref cmd) = parsed.cmd_type {
+ items.push(AnalyzeItem::local(module.to_string(), cmd.clone()));
+ }
+
+ // Error type — if error = TypeName
+ if let Some(ref err) = parsed.error_type {
+ items.push(AnalyzeItem::local(module.to_string(), err.clone()));
+ }
+
+ // Help internal struct — if help = true
+ if parsed.help_enabled
+ && let Some(ref cmd) = parsed.cmd_type
+ {
+ let help_fn = format!("__{}_help", just_fmt::snake_case!(cmd));
+ let help_struct = format!("__internal_help_{}", just_fmt::snake_case!(&help_fn));
+ items.push(AnalyzeItem::local(module.to_string(), help_struct));
+ }
+
+ // __internal_dispatcher_* — when configured
+ if self.use_dispatch_tree
+ && let Some(ref cmd_name) = parsed.cmd_name
+ {
+ let internal_name =
+ format!("__internal_dispatcher_{}", just_fmt::snake_case!(cmd_name));
+ items.push(AnalyzeItem::local(module.to_string(), internal_name));
+ }
+ }
+
+ items
+ }
+}
+
struct ParsedClapArgs {
cmd_name: Option<String>,
cmd_type: Option<String>,
@@ -202,17 +150,13 @@ fn parse_dispatcher_clap_args(args: &str) -> ParsedClapArgs {
let args = args.trim();
// Extract the first quoted string (the command name)
- let after_cmd = if let Some(start) = args.find('"') {
+ let after_cmd = args.find('"').map_or(args, |start| {
let after_open = &args[start + 1..];
- if let Some(end) = after_open.find('"') {
+ after_open.find('"').map_or(args, |end| {
cmd_name = Some(after_open[..end].to_string());
after_open[end + 1..].trim()
- } else {
- args
- }
- } else {
- args
- };
+ })
+ });
// Split by commas and parse each part
for part in after_cmd.split(',') {
diff --git a/mingling_pathf/src/patterns/group.rs b/mingling_pathf/src/patterns/group.rs
index 0f9ecff..905afa9 100644
--- a/mingling_pathf/src/patterns/group.rs
+++ b/mingling_pathf/src/patterns/group.rs
@@ -129,7 +129,8 @@ fn collect_from_use_tree(
UseTree::Name(name) => {
let module = prefix.to_string();
let alias = name.ident.to_string();
- map.entry(alias).or_insert((module, name.ident.to_string()));
+ map.entry(alias)
+ .or_insert_with(|| (module, name.ident.to_string()));
}
UseTree::Path(use_path) => {
let new_prefix = if prefix.is_empty() {
@@ -143,7 +144,7 @@ fn collect_from_use_tree(
let module = prefix.to_string();
let alias = rename.ident.to_string();
map.entry(alias)
- .or_insert((module, rename.ident.to_string()));
+ .or_insert_with(|| (module, rename.ident.to_string()));
}
UseTree::Glob(_) => {
// `use path::*;` — skip glob imports
@@ -178,24 +179,21 @@ fn extract_group_name(tokens: &proc_macro2::TokenStream) -> Option<String> {
let mut iter = stream.into_iter();
loop {
- match iter.next()? {
- proc_macro2::TokenTree::Ident(ident) => {
- let name = ident.to_string();
-
- // Check if there is a `=` following
- let next = iter.next();
- match next {
- Some(proc_macro2::TokenTree::Punct(p)) if p.as_char() == '=' => {
- // group!(Alias = path::Type)
- return Some(name);
- }
- _ => {
- // group!(TypeName)
- return Some(name);
- }
+ if let proc_macro2::TokenTree::Ident(ident) = iter.next()? {
+ let name = ident.to_string();
+
+ // Check if there is a `=` following
+ let next = iter.next();
+ match next {
+ Some(proc_macro2::TokenTree::Punct(p)) if p.as_char() == '=' => {
+ // group!(Alias = path::Type)
+ return Some(name);
+ }
+ _ => {
+ // group!(TypeName)
+ return Some(name);
}
}
- _ => continue,
}
}
}
diff --git a/mingling_pathf/src/patterns/metadata.rs b/mingling_pathf/src/patterns/metadata.rs
index 24243bf..32a283a 100644
--- a/mingling_pathf/src/patterns/metadata.rs
+++ b/mingling_pathf/src/patterns/metadata.rs
@@ -95,7 +95,7 @@ fn extract_bind_type(attrs: &[syn::Attribute]) -> Option<String> {
continue;
}
if let syn::Meta::List(meta_list) = &attr.meta {
- for token in meta_list.tokens.clone().into_iter() {
+ for token in meta_list.tokens.clone() {
if let proc_macro2::TokenTree::Ident(ident) = token {
return Some(ident.to_string());
}
@@ -139,7 +139,8 @@ fn collect_from_use_tree(
UseTree::Name(name) => {
let module = prefix.to_string();
let alias = name.ident.to_string();
- map.entry(alias).or_insert((module, name.ident.to_string()));
+ map.entry(alias)
+ .or_insert_with(|| (module, name.ident.to_string()));
}
UseTree::Path(use_path) => {
let new_prefix = if prefix.is_empty() {
@@ -153,7 +154,7 @@ fn collect_from_use_tree(
let module = prefix.to_string();
let alias = rename.ident.to_string();
map.entry(alias)
- .or_insert((module, rename.ident.to_string()));
+ .or_insert_with(|| (module, rename.ident.to_string()));
}
UseTree::Glob(_) => {}
UseTree::Group(group) => {
diff --git a/mingling_pathf/src/patterns/pack.rs b/mingling_pathf/src/patterns/pack.rs
index 76597ba..e5e14e6 100644
--- a/mingling_pathf/src/patterns/pack.rs
+++ b/mingling_pathf/src/patterns/pack.rs
@@ -84,23 +84,20 @@ fn try_extract_pack_name(m: &syn::ItemMacro) -> Option<String> {
// Skip leading attributes/doc comments
loop {
- match iter.next()? {
- proc_macro2::TokenTree::Ident(ident) => {
- // Found the first ident, this is the type name
- let type_name = ident.to_string();
-
- // Check if `=` follows
- if let Some(proc_macro2::TokenTree::Punct(p)) = iter.next()
- && p.as_char() == '='
- {
- // pack!(TypeName = InnerType)
- return Some(type_name);
- }
-
- // pack_err!(TypeName) — only a single ident
+ if let proc_macro2::TokenTree::Ident(ident) = iter.next()? {
+ // Found the first ident, this is the type name
+ let type_name = ident.to_string();
+
+ // Check if `=` follows
+ if let Some(proc_macro2::TokenTree::Punct(p)) = iter.next()
+ && p.as_char() == '='
+ {
+ // pack!(TypeName = InnerType)
return Some(type_name);
}
- _ => continue,
+
+ // pack_err!(TypeName) — only a single ident
+ return Some(type_name);
}
}
}