aboutsummaryrefslogtreecommitdiff
path: root/mingling_pathf
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_pathf')
-rw-r--r--mingling_pathf/src/config.rs27
-rw-r--r--mingling_pathf/src/lib.rs1
-rw-r--r--mingling_pathf/src/pattern_analyzer.rs13
-rw-r--r--mingling_pathf/src/patterns/dispatcher.rs37
-rw-r--r--mingling_pathf/src/patterns/dispatcher_clap.rs32
-rw-r--r--mingling_pathf/src/type_mapping_builder.rs7
-rw-r--r--mingling_pathf/test/src/lib.rs82
7 files changed, 68 insertions, 131 deletions
diff --git a/mingling_pathf/src/config.rs b/mingling_pathf/src/config.rs
deleted file mode 100644
index 10ef002..0000000
--- a/mingling_pathf/src/config.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Doc Not Optimize
-//! Configuration for the module pathfinder analysis.
-//!
-//! This module defines [`PathfinderConfig`], which controls behavior such as
-//! whether dispatch-tree related types (`__internal_dispatcher_*`) should be
-//! extracted.
-
-/// Configuration for the module pathfinder analysis.
-///
-/// Controls behavior such as whether dispatch-tree related types
-/// (`__internal_dispatcher_*`) should be extracted.
-#[derive(Debug, Clone, Default)]
-pub struct PathfinderConfig {
- /// Whether to also extract `__internal_dispatcher_*` static types
- /// generated by the `dispatch_tree` feature in Mingling.
- pub use_dispatch_tree: bool,
-}
-
-impl PathfinderConfig {
- /// Create a config with `use_dispatch_tree` enabled.
- #[must_use]
- pub const fn with_dispatch_tree() -> Self {
- Self {
- use_dispatch_tree: true,
- }
- }
-}
diff --git a/mingling_pathf/src/lib.rs b/mingling_pathf/src/lib.rs
index 93a80a3..492bfc7 100644
--- a/mingling_pathf/src/lib.rs
+++ b/mingling_pathf/src/lib.rs
@@ -5,7 +5,6 @@
#![deny(clippy::pedantic)]
#![deny(clippy::nursery)]
-pub mod config;
pub mod error;
pub mod module_pathf;
pub mod pattern_analyzer;
diff --git a/mingling_pathf/src/pattern_analyzer.rs b/mingling_pathf/src/pattern_analyzer.rs
index c2dd25f..b7f923c 100644
--- a/mingling_pathf/src/pattern_analyzer.rs
+++ b/mingling_pathf/src/pattern_analyzer.rs
@@ -9,14 +9,12 @@
//!
//! The entry points are:
//! - [`init()`] — creates a default `PatternAnalyzer` with all built-in patterns.
-//! - [`init_with_config()`] — creates a `PatternAnalyzer` with a given `PathfinderConfig`.
//! - [`PatternAnalyzer::analyze_file()`] / [`PatternAnalyzer::analyze_file_items()`] — run
//! analysis on a single file.
use std::collections::HashSet;
use std::path::Path;
-use crate::config::PathfinderConfig;
use crate::error::MinglingPathfinderError;
use crate::patterns::{
ChainPattern, CommandPattern, CompletionPattern, DispatcherClapPattern, DispatcherPattern,
@@ -26,13 +24,6 @@ use crate::patterns::{
/// Creates a default `PatternAnalyzer` with all built-in patterns pre-registered.
#[must_use]
pub fn init() -> PatternAnalyzer {
- init_with_config(&PathfinderConfig::default())
-}
-
-/// Creates a `PatternAnalyzer` with the given config, used by `mingling_core`'s pathf wrapper
-/// to inject feature-dependent settings (e.g., `dispatch_tree`).
-#[must_use]
-pub fn init_with_config(config: &PathfinderConfig) -> PatternAnalyzer {
let mut analyzer = PatternAnalyzer::new();
analyzer.add_pattern(PackPattern);
analyzer.add_pattern(GroupPattern);
@@ -43,8 +34,8 @@ pub fn init_with_config(config: &PathfinderConfig) -> PatternAnalyzer {
analyzer.add_pattern(HelpPattern);
analyzer.add_pattern(MetadataPattern);
analyzer.add_pattern(CompletionPattern);
- analyzer.add_pattern(DispatcherPattern::new(config.use_dispatch_tree));
- analyzer.add_pattern(DispatcherClapPattern::new(config.use_dispatch_tree));
+ analyzer.add_pattern(DispatcherPattern::new());
+ analyzer.add_pattern(DispatcherClapPattern::new());
analyzer
}
diff --git a/mingling_pathf/src/patterns/dispatcher.rs b/mingling_pathf/src/patterns/dispatcher.rs
index 56d2b97..5090052 100644
--- a/mingling_pathf/src/patterns/dispatcher.rs
+++ b/mingling_pathf/src/patterns/dispatcher.rs
@@ -3,7 +3,7 @@
//! extracts the generated type names from its arguments. It supports:
//! - `Entry*` — the entry type (always generated)
//! - `CMD*` — the dispatcher struct (always generated)
-//! - `__internal_dispatcher_*` — the dispatch tree static (when `use_dispatch_tree` is `true`)
+//! - `__internal_dispatcher_*` — the compile-time collected static (always generated)
//!
//! Supported forms:
//! - Explicit: `dispatcher!("greet", CMDGreet => EntryGreet)`
@@ -19,23 +19,15 @@ use crate::pattern_analyzer::{AnalyzeItem, AnalyzePattern};
/// Matches the `dispatcher!` macro, extracts:
/// - `Entry*` — the entry type (always)
/// - `CMD*` — the dispatcher struct (always)
-/// - `__internal_dispatcher_*` — dispatch tree static (when `use_dispatch_tree` is true)
-pub struct DispatcherPattern {
- /// Whether the dispatcher generates a dispatch tree static (`__internal_dispatcher_*`).
- pub use_dispatch_tree: bool,
-}
+/// - `__internal_dispatcher_*` — the compile-time collected static (always)
+#[derive(Default)]
+pub struct DispatcherPattern;
impl DispatcherPattern {
/// Creates a new `DispatcherPattern`.
- ///
- /// # Arguments
- ///
- /// * `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.
#[must_use]
- pub const fn new(use_dispatch_tree: bool) -> Self {
- Self { use_dispatch_tree }
+ pub const fn new() -> Self {
+ Self
}
}
@@ -62,7 +54,7 @@ impl AnalyzePattern for DispatcherPattern {
if macro_name != "dispatcher" {
continue;
}
- items.extend(extract_all_types(&m.mac.tokens, "", self.use_dispatch_tree));
+ items.extend(extract_all_types(&m.mac.tokens, ""));
}
Item::Mod(item_mod) => {
if let Some((_, nested)) = &item_mod.content {
@@ -74,7 +66,6 @@ impl AnalyzePattern for DispatcherPattern {
items.extend(extract_all_types(
&m.mac.tokens,
&item_mod.ident.to_string(),
- self.use_dispatch_tree,
));
}
}
@@ -98,11 +89,7 @@ fn macro_simple_name(m: &syn::ItemMacro) -> String {
}
/// Extracts all types generated by a `dispatcher!` call.
-fn extract_all_types(
- tokens: &proc_macro2::TokenStream,
- module: &str,
- use_dispatch_tree: bool,
-) -> Vec<AnalyzeItem> {
+fn extract_all_types(tokens: &proc_macro2::TokenStream, module: &str) -> Vec<AnalyzeItem> {
let (cmd_name, cmd_struct, entry_struct) = parse_dispatcher_args(tokens);
let Some(cmd_name) = cmd_name else {
return Vec::new();
@@ -120,11 +107,9 @@ fn extract_all_types(
items.push(AnalyzeItem::local(module.to_string(), cmd.clone()));
}
- // __internal_dispatcher_* — when configured
- if use_dispatch_tree {
- let internal_name = format!("__internal_dispatcher_{}", snake_case(&cmd_name));
- items.push(AnalyzeItem::local(module.to_string(), internal_name));
- }
+ // __internal_dispatcher_* — the compile-time collected static
+ let internal_name = format!("__internal_dispatcher_{}", snake_case(&cmd_name));
+ items.push(AnalyzeItem::local(module.to_string(), internal_name));
items
}
diff --git a/mingling_pathf/src/patterns/dispatcher_clap.rs b/mingling_pathf/src/patterns/dispatcher_clap.rs
index 55001a6..da9da3e 100644
--- a/mingling_pathf/src/patterns/dispatcher_clap.rs
+++ b/mingling_pathf/src/patterns/dispatcher_clap.rs
@@ -5,7 +5,7 @@
//! - The dispatcher command struct (`CMD*`, always)
//! - The error type, if `error = ErrorType` is specified
//! - The help internal struct, if `help = true` is specified
-//! - The `__internal_dispatcher_*` dispatch tree static, if `use_dispatch_tree` is enabled
+//! - The `__internal_dispatcher_*` compile-time collected static (always)
//!
//! Supported forms:
//! - `#[dispatcher_clap("greet", CMDGreet)] struct EntryGreet { ... }`
@@ -22,27 +22,21 @@ use crate::pattern_analyzer::{AnalyzeItem, AnalyzePattern};
/// - The dispatcher struct (`CMD*`, always)
/// - The error type, if `error = ErrorType` is specified
/// - The help internal struct, if `help = true` is specified
-/// - `__internal_dispatcher_*` — dispatch tree static (when `use_dispatch_tree` is true)
+/// - `__internal_dispatcher_*` — compile-time collected static (always)
///
/// Covers forms:
/// - `#[dispatcher_clap("greet", CMDGreet)] struct EntryGreet { ... }`
/// - `#[dispatcher_clap("greet", CMDGreet, error = ErrorGreet)] struct EntryGreet { ... }`
/// - `#[dispatcher_clap("greet", CMDGreet, help = true)] struct EntryGreet { ... }`
/// - `#[dispatcher_clap("greet", CMDGreet, error = ErrorGreet, help = true)] struct EntryGreet { ... }`
-pub struct DispatcherClapPattern {
- /// Whether to include the `__internal_dispatcher_*` dispatch tree static in the analysis.
- pub use_dispatch_tree: bool,
-}
+#[derive(Default)]
+pub struct DispatcherClapPattern;
impl DispatcherClapPattern {
- /// Creates a new `DispatcherClapPattern` with the given configuration.
- ///
- /// # Parameters
- /// - `use_dispatch_tree`: When `true`, enables analysis of the `__internal_dispatcher_*`
- /// static dispatch tree for each matched command.
+ /// Creates a new `DispatcherClapPattern`.
#[must_use]
- pub const fn new(use_dispatch_tree: bool) -> Self {
- Self { use_dispatch_tree }
+ pub const fn new() -> Self {
+ Self
}
}
@@ -61,7 +55,7 @@ impl AnalyzePattern for DispatcherClapPattern {
for item in &syntax.items {
match item {
Item::Struct(s) if has_attr(&s.attrs, "dispatcher_clap") => {
- items.extend(self.analyze_struct(s, ""));
+ items.extend(Self::analyze_struct(s, ""));
}
Item::Mod(item_mod) => {
if let Some((_, nested)) = &item_mod.content {
@@ -69,7 +63,7 @@ impl AnalyzePattern for DispatcherClapPattern {
if let Item::Struct(s) = n
&& has_attr(&s.attrs, "dispatcher_clap")
{
- items.extend(self.analyze_struct(s, &item_mod.ident.to_string()));
+ items.extend(Self::analyze_struct(s, &item_mod.ident.to_string()));
}
}
}
@@ -83,7 +77,7 @@ impl AnalyzePattern for DispatcherClapPattern {
}
impl DispatcherClapPattern {
- fn analyze_struct(&self, s: &syn::ItemStruct, module: &str) -> Vec<AnalyzeItem> {
+ fn analyze_struct(s: &syn::ItemStruct, module: &str) -> Vec<AnalyzeItem> {
let mut items = Vec::new();
// Entry type (struct name) — always
@@ -120,10 +114,8 @@ impl DispatcherClapPattern {
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
- {
+ // __internal_dispatcher_* — the compile-time collected static
+ if 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));
diff --git a/mingling_pathf/src/type_mapping_builder.rs b/mingling_pathf/src/type_mapping_builder.rs
index 5341578..1ccd267 100644
--- a/mingling_pathf/src/type_mapping_builder.rs
+++ b/mingling_pathf/src/type_mapping_builder.rs
@@ -7,7 +7,6 @@ use std::collections::HashSet;
use std::fmt::Write as FmtWrite;
use std::path::Path;
-use crate::config::PathfinderConfig;
use crate::error::MinglingPathfinderError;
use crate::module_pathf;
use crate::pattern_analyzer;
@@ -16,7 +15,6 @@ use crate::pattern_analyzer;
///
/// `crate_dir` — crate root directory (i.e., the directory containing Cargo.toml)
/// `output_dir` — directory where mapping files will be written
-/// `config` — pathfinder configuration (e.g., [`dispatch_tree`] detection)
///
/// Mapping file format per line: `TypeName = crate::module::path::TypeName`
///
@@ -27,10 +25,9 @@ use crate::pattern_analyzer;
pub fn analyze_and_build_type_mapping_for(
crate_dir: &Path,
output_dir: &Path,
- config: &PathfinderConfig,
) -> Result<(), MinglingPathfinderError> {
let module_mapping = module_pathf::analyze(crate_dir)?;
- let analyzer = pattern_analyzer::init_with_config(config);
+ let analyzer = pattern_analyzer::init();
let mut type_mappings: Vec<(String, String, bool)> = Vec::new();
@@ -118,7 +115,7 @@ pub fn analyze_and_build_type_mapping() -> Result<(), MinglingPathfinderError> {
let crate_dir = std::env::current_dir()?;
let output_dir = Path::new(&out_dir).join(&crate_name);
- analyze_and_build_type_mapping_for(&crate_dir, &output_dir, &PathfinderConfig::default())?;
+ analyze_and_build_type_mapping_for(&crate_dir, &output_dir)?;
// Notify Cargo to re-run build.rs when source files change
println!("cargo:rerun-if-changed=src/");
diff --git a/mingling_pathf/test/src/lib.rs b/mingling_pathf/test/src/lib.rs
index 95d7410..81f3b3f 100644
--- a/mingling_pathf/test/src/lib.rs
+++ b/mingling_pathf/test/src/lib.rs
@@ -269,6 +269,13 @@ fn test_dispatcher_analyze() {
"::sub::CMDGreet",
"::sub::EntryDelete",
"::sub::CMDDelete",
+ // Dispatchers are always collected at compile time:
+ "::__internal_dispatcher_greet",
+ "::__internal_dispatcher_remote_add",
+ "::__internal_dispatcher_delete",
+ "::__internal_dispatcher_remote_rm",
+ "::sub::__internal_dispatcher_greet",
+ "::sub::__internal_dispatcher_delete",
];
assert_eq!(r.len(), required.len());
@@ -279,36 +286,27 @@ fn test_dispatcher_analyze() {
#[test]
fn test_dispatcher_dispatch_tree() {
- use mingling_pathf::config::PathfinderConfig;
use mingling_pathf::pattern_analyzer;
let file = current_dir()
.unwrap()
.join("src/test_files/test_dispatcher_dispatch_tree.rs");
- // Without dispatch_tree: only Entry + CMD types
- let r1 = pattern_analyzer::init().analyze_file(&file).unwrap();
- // 4 root (EntryGreet, CMDGreet, EntryDelete, CMDDelete)
- // + 4 sub (sub::EntryGreet, sub::CMDGreet, sub::EntryDelete, sub::CMDDelete)
- // = 8
- assert_eq!(r1.len(), 8);
- assert!(r1.contains("::EntryGreet"));
- assert!(r1.contains("::CMDGreet"));
- assert!(r1.contains("::EntryDelete"));
- assert!(r1.contains("::CMDDelete"));
- assert!(r1.contains("::sub::EntryGreet"));
- assert!(r1.contains("::sub::CMDGreet"));
-
- // With dispatch_tree: Entry + CMD + __internal_dispatcher
- let r2 = pattern_analyzer::init_with_config(&PathfinderConfig::with_dispatch_tree())
- .analyze_file(&file)
- .unwrap();
- // 8 (from above) + 2 __internal (root) + 2 __internal (sub) = 12
- assert_eq!(r2.len(), 12);
- assert!(r2.contains("::__internal_dispatcher_greet"));
- assert!(r2.contains("::__internal_dispatcher_delete"));
- assert!(r2.contains("::sub::__internal_dispatcher_greet"));
- assert!(r2.contains("::sub::__internal_dispatcher_delete"));
+ // Dispatchers are always collected at compile time, so the analyzer
+ // always extracts the `__internal_dispatcher_*` statics too:
+ // 8 (Entry + CMD, root + sub) + 4 __internal (root + sub) = 12
+ let r = pattern_analyzer::init().analyze_file(&file).unwrap();
+ assert_eq!(r.len(), 12);
+ assert!(r.contains("::EntryGreet"));
+ assert!(r.contains("::CMDGreet"));
+ assert!(r.contains("::EntryDelete"));
+ assert!(r.contains("::CMDDelete"));
+ assert!(r.contains("::sub::EntryGreet"));
+ assert!(r.contains("::sub::CMDGreet"));
+ assert!(r.contains("::__internal_dispatcher_greet"));
+ assert!(r.contains("::__internal_dispatcher_delete"));
+ assert!(r.contains("::sub::__internal_dispatcher_greet"));
+ assert!(r.contains("::sub::__internal_dispatcher_delete"));
}
#[test]
@@ -355,6 +353,14 @@ fn test_dispatcher_clap_analyze() {
"::sub::EntryWithHelp",
"::sub::CMDHelp",
"::sub::__internal_help_cmdhelp_help",
+ // Dispatchers are always collected at compile time:
+ "::__internal_dispatcher_greet",
+ "::__internal_dispatcher_delete",
+ "::__internal_dispatcher_helpcmd",
+ "::__internal_dispatcher_full",
+ "::sub::__internal_dispatcher_greet",
+ "::sub::__internal_dispatcher_delete",
+ "::sub::__internal_dispatcher_helpcmd",
];
assert_eq!(r.len(), required.len());
@@ -365,29 +371,23 @@ fn test_dispatcher_clap_analyze() {
#[test]
fn test_dispatcher_clap_dispatch_tree() {
- use mingling_pathf::config::PathfinderConfig;
use mingling_pathf::pattern_analyzer;
let file = current_dir()
.unwrap()
.join("src/test_files/test_dispatcher_clap.rs");
- // Without dispatch_tree: 26 items (same set as test_dispatcher_clap_analyze)
- let r1 = pattern_analyzer::init().analyze_file(&file).unwrap();
- assert_eq!(r1.len(), 26);
-
- // With dispatch_tree: 26 + 4 __internal (root) + 3 __internal (sub, no "full") = 33
- let r2 = pattern_analyzer::init_with_config(&PathfinderConfig::with_dispatch_tree())
- .analyze_file(&file)
- .unwrap();
- assert_eq!(r2.len(), 33);
- assert!(r2.contains("::__internal_dispatcher_greet"));
- assert!(r2.contains("::__internal_dispatcher_delete"));
- assert!(r2.contains("::__internal_dispatcher_helpcmd"));
- assert!(r2.contains("::__internal_dispatcher_full"));
- assert!(r2.contains("::sub::__internal_dispatcher_greet"));
- assert!(r2.contains("::sub::__internal_dispatcher_delete"));
- assert!(r2.contains("::sub::__internal_dispatcher_helpcmd"));
+ // Dispatchers are always collected at compile time:
+ // 26 (Entry/CMD/error/help items) + 4 __internal (root) + 3 __internal (sub, no "full") = 33
+ let r = pattern_analyzer::init().analyze_file(&file).unwrap();
+ assert_eq!(r.len(), 33);
+ assert!(r.contains("::__internal_dispatcher_greet"));
+ assert!(r.contains("::__internal_dispatcher_delete"));
+ assert!(r.contains("::__internal_dispatcher_helpcmd"));
+ assert!(r.contains("::__internal_dispatcher_full"));
+ assert!(r.contains("::sub::__internal_dispatcher_greet"));
+ assert!(r.contains("::sub::__internal_dispatcher_delete"));
+ assert!(r.contains("::sub::__internal_dispatcher_helpcmd"));
}
#[test]