From 0617ce6a527567f4545558fda632dd8d7e06606d Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 29 May 2026 20:56:19 +0800 Subject: Add auto-generated feature flags module and tooling --- Cargo.toml | 1 + dev_tools/src/bin/ci.rs | 1 + dev_tools/src/bin/refresh-feature-mod.rs | 97 +++++++++++++ examples/example-repl-advanced/Cargo.lock | 84 +++++++++++ examples/example-repl-advanced/Cargo.toml | 11 ++ examples/example-repl-advanced/src/main.rs | 3 + mingling/Cargo.toml | 1 + mingling/src/example_docs.rs | 24 +++ mingling/src/features.rs | 225 +++++++++++++++++++++++------ mingling/src/features.rs.tmpl | 15 ++ mingling/src/lib.rs | 39 +---- 11 files changed, 422 insertions(+), 79 deletions(-) create mode 100644 dev_tools/src/bin/refresh-feature-mod.rs create mode 100644 examples/example-repl-advanced/Cargo.lock create mode 100644 examples/example-repl-advanced/Cargo.toml create mode 100644 examples/example-repl-advanced/src/main.rs create mode 100644 mingling/src/features.rs.tmpl diff --git a/Cargo.toml b/Cargo.toml index fcddfc6..f5b9a3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ exclude = [ "examples/example-hook", "examples/example-implicit-dispatcher", "examples/example-panic-unwind", + "examples/example-repl-advanced", "examples/example-repl-basic", "examples/example-resources", "examples/example-setup", diff --git a/dev_tools/src/bin/ci.rs b/dev_tools/src/bin/ci.rs index 554425e..0547c34 100644 --- a/dev_tools/src/bin/ci.rs +++ b/dev_tools/src/bin/ci.rs @@ -102,6 +102,7 @@ fn docs_refresh() -> Result<(), i32> { run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin docs-code-box-fix")?; run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin docsify-sidebar-gen")?; run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin refresh-docs")?; + run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin refresh-feature-mod")?; Ok(()) } diff --git a/dev_tools/src/bin/refresh-feature-mod.rs b/dev_tools/src/bin/refresh-feature-mod.rs new file mode 100644 index 0000000..6265e15 --- /dev/null +++ b/dev_tools/src/bin/refresh-feature-mod.rs @@ -0,0 +1,97 @@ +use std::collections::BTreeSet; +use std::path::Path; + +use just_fmt::snake_case; +use just_template::{tmpl, Template}; +use tools::println_cargo_style; + +const CARGO_TOML_PATH: &str = "./mingling/Cargo.toml"; +const OUTPUT_PATH: &str = "./mingling/src/features.rs"; + +const TEMPLATE_CONTENT: &str = include_str!("../../../mingling/src/features.rs.tmpl"); + +fn main() { + gen_feature_module(); +} + +fn gen_feature_module() { + let repo_root = find_git_repo().unwrap(); + + let cargo_toml_path = repo_root.join(CARGO_TOML_PATH); + let output_path = repo_root.join(OUTPUT_PATH); + + let features = parse_features(&cargo_toml_path); + + let mut template = Template::from(TEMPLATE_CONTENT); + + for feat_name in &features { + let feat_const_name = snake_case!(feat_name).to_uppercase(); + + tmpl!(template += { + features { + ( + feat_name = feat_name, + feat_const_name = feat_const_name + ) + } + }); + println_cargo_style!("Refresh: feature `{}`", feat_name); + } + + let template_str = template.to_string(); + let template_str = template_str + .lines() + .map(|line| line.trim_end()) + .collect::>() + .join("\n") + + "\n"; + std::fs::write(&output_path, template_str).unwrap(); + + println_cargo_style!("Written: features module to {}", OUTPUT_PATH); +} + +/// Parse all feature names from the `[features]` section of a Cargo.toml. +fn parse_features(cargo_toml_path: &Path) -> Vec { + let content = std::fs::read_to_string(cargo_toml_path) + .unwrap_or_else(|e| panic!("Failed to read {}: {}", cargo_toml_path.display(), e)); + + let cargo_toml: toml::Value = content + .parse() + .unwrap_or_else(|e| panic!("Failed to parse {}: {}", cargo_toml_path.display(), e)); + + let features_table = cargo_toml + .get("features") + .and_then(|v| v.as_table()) + .unwrap_or_else(|| { + panic!( + "No [features] section found in {}", + cargo_toml_path.display() + ) + }); + + let mut feature_names: BTreeSet = BTreeSet::new(); + for key in features_table.keys() { + feature_names.insert(key.clone()); + } + + let mut result: Vec = feature_names.into_iter().collect(); + result.sort(); + result +} + +fn find_git_repo() -> Option { + let mut current_dir = std::env::current_dir().ok()?; + + loop { + let git_dir = current_dir.join(".git"); + if git_dir.exists() && git_dir.is_dir() { + return Some(current_dir); + } + + if !current_dir.pop() { + break; + } + } + + None +} diff --git a/examples/example-repl-advanced/Cargo.lock b/examples/example-repl-advanced/Cargo.lock new file mode 100644 index 0000000..b18899b --- /dev/null +++ b/examples/example-repl-advanced/Cargo.lock @@ -0,0 +1,84 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "example-repl-advanced" +version = "0.1.0" +dependencies = [ + "just_fmt", + "mingling", +] + +[[package]] +name = "just_fmt" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5454cda0d57db59778608d7a47bff5b16c6705598265869fb052b657f66cf05e" + +[[package]] +name = "mingling" +version = "0.1.9" +dependencies = [ + "mingling_core", + "mingling_macros", + "size", +] + +[[package]] +name = "mingling_core" +version = "0.1.9" +dependencies = [ + "just_fmt", +] + +[[package]] +name = "mingling_macros" +version = "0.1.9" +dependencies = [ + "just_fmt", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "size" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6709c7b6754dca1311b3c73e79fcce40dd414c782c66d88e8823030093b02b" + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" diff --git a/examples/example-repl-advanced/Cargo.toml b/examples/example-repl-advanced/Cargo.toml new file mode 100644 index 0000000..7f89773 --- /dev/null +++ b/examples/example-repl-advanced/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "example-repl-advanced" +version = "0.1.0" +edition = "2024" + +[dependencies.mingling] +path = "../../mingling" +features = ["repl", "repl_extra", "parser", "extra_macros"] + +[dependencies] +just_fmt = "0.1.2" diff --git a/examples/example-repl-advanced/src/main.rs b/examples/example-repl-advanced/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/examples/example-repl-advanced/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/mingling/Cargo.toml b/mingling/Cargo.toml index 68a26d4..e0d2f4a 100644 --- a/mingling/Cargo.toml +++ b/mingling/Cargo.toml @@ -51,6 +51,7 @@ default = ["mingling_core/default", "mingling_macros/default"] clap = ["mingling_core/clap", "mingling_macros/clap"] dispatch_tree = ["mingling_core/dispatch_tree", "mingling_macros/dispatch_tree"] repl = ["mingling_core/repl", "mingling_macros/repl"] +repl_extra = ["repl"] comp = ["mingling_core/comp", "mingling_macros/comp"] parser = ["dep:size"] diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs index b665485..b46041f 100644 --- a/mingling/src/example_docs.rs +++ b/mingling/src/example_docs.rs @@ -1473,6 +1473,30 @@ pub mod example_implicit_dispatcher {} /// gen_program!(); /// ``` pub mod example_panic_unwind {} + +/// +/// Source code (./Cargo.toml) +/// ```toml +/// [package] +/// name = "example-repl-advanced" +/// version = "0.1.0" +/// edition = "2024" +/// +/// [dependencies.mingling] +/// path = "../../mingling" +/// features = ["repl", "repl_extra", "parser", "extra_macros"] +/// +/// [dependencies] +/// just_fmt = "0.1.2" +/// ``` +/// +/// Source code (./src/main.rs) +/// ```ignore +/// fn main() { +/// println!("Hello, world!"); +/// } +/// ``` +pub mod example_repl_advanced {} /// Example REPL Basic /// /// > This example demonstrates how to develop a REPL program using the `repl` feature diff --git a/mingling/src/features.rs b/mingling/src/features.rs index 7d78012..365724c 100644 --- a/mingling/src/features.rs +++ b/mingling/src/features.rs @@ -1,77 +1,220 @@ -#[cfg(not(feature = "nightly"))] -pub const MINGLING_NIGHTLY: bool = false; - -#[cfg(feature = "nightly")] -pub const MINGLING_NIGHTLY: bool = true; - -#[cfg(not(feature = "debug"))] -pub const MINGLING_DEBUG: bool = false; - -#[cfg(feature = "debug")] -pub const MINGLING_DEBUG: bool = true; - +/// Whether the `all_serde_fmt` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "all_serde_fmt"))] +#[allow(unused)] +pub const MINGLING_ALL_SERDE_FMT: bool = false; + +/// Whether the `all_serde_fmt` feature is enabled +/// Current: `enabled` +#[cfg(feature = "all_serde_fmt")] +#[allow(unused)] +pub const MINGLING_ALL_SERDE_FMT: bool = true; +/// Whether the `async` feature is enabled +/// Current: `disabled` #[cfg(not(feature = "async"))] +#[allow(unused)] pub const MINGLING_ASYNC: bool = false; +/// Whether the `async` feature is enabled +/// Current: `enabled` #[cfg(feature = "async")] +#[allow(unused)] pub const MINGLING_ASYNC: bool = true; - +/// Whether the `builds` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "builds"))] +#[allow(unused)] +pub const MINGLING_BUILDS: bool = false; + +/// Whether the `builds` feature is enabled +/// Current: `enabled` +#[cfg(feature = "builds")] +#[allow(unused)] +pub const MINGLING_BUILDS: bool = true; +/// Whether the `clap` feature is enabled +/// Current: `disabled` #[cfg(not(feature = "clap"))] +#[allow(unused)] pub const MINGLING_CLAP: bool = false; +/// Whether the `clap` feature is enabled +/// Current: `enabled` #[cfg(feature = "clap")] +#[allow(unused)] pub const MINGLING_CLAP: bool = true; +/// Whether the `comp` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "comp"))] +#[allow(unused)] +pub const MINGLING_COMP: bool = false; +/// Whether the `comp` feature is enabled +/// Current: `enabled` +#[cfg(feature = "comp")] +#[allow(unused)] +pub const MINGLING_COMP: bool = true; +/// Whether the `debug` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "debug"))] +#[allow(unused)] +pub const MINGLING_DEBUG: bool = false; + +/// Whether the `debug` feature is enabled +/// Current: `enabled` +#[cfg(feature = "debug")] +#[allow(unused)] +pub const MINGLING_DEBUG: bool = true; +/// Whether the `default` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "default"))] +#[allow(unused)] +pub const MINGLING_DEFAULT: bool = false; + +/// Whether the `default` feature is enabled +/// Current: `enabled` +#[cfg(feature = "default")] +#[allow(unused)] +pub const MINGLING_DEFAULT: bool = true; +/// Whether the `dispatch_tree` feature is enabled +/// Current: `disabled` #[cfg(not(feature = "dispatch_tree"))] +#[allow(unused)] pub const MINGLING_DISPATCH_TREE: bool = false; +/// Whether the `dispatch_tree` feature is enabled +/// Current: `enabled` #[cfg(feature = "dispatch_tree")] +#[allow(unused)] pub const MINGLING_DISPATCH_TREE: bool = true; - +/// Whether the `extra_macros` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "extra_macros"))] +#[allow(unused)] +pub const MINGLING_EXTRA_MACROS: bool = false; + +/// Whether the `extra_macros` feature is enabled +/// Current: `enabled` +#[cfg(feature = "extra_macros")] +#[allow(unused)] +pub const MINGLING_EXTRA_MACROS: bool = true; +/// Whether the `general_renderer` feature is enabled +/// Current: `disabled` #[cfg(not(feature = "general_renderer"))] +#[allow(unused)] pub const MINGLING_GENERAL_RENDERER: bool = false; +/// Whether the `general_renderer` feature is enabled +/// Current: `enabled` #[cfg(feature = "general_renderer")] +#[allow(unused)] pub const MINGLING_GENERAL_RENDERER: bool = true; +/// Whether the `general_renderer_empty` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "general_renderer_empty"))] +#[allow(unused)] +pub const MINGLING_GENERAL_RENDERER_EMPTY: bool = false; + +/// Whether the `general_renderer_empty` feature is enabled +/// Current: `enabled` +#[cfg(feature = "general_renderer_empty")] +#[allow(unused)] +pub const MINGLING_GENERAL_RENDERER_EMPTY: bool = true; +/// Whether the `general_renderer_full` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "general_renderer_full"))] +#[allow(unused)] +pub const MINGLING_GENERAL_RENDERER_FULL: bool = false; + +/// Whether the `general_renderer_full` feature is enabled +/// Current: `enabled` +#[cfg(feature = "general_renderer_full")] +#[allow(unused)] +pub const MINGLING_GENERAL_RENDERER_FULL: bool = true; +/// Whether the `json_serde_fmt` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "json_serde_fmt"))] +#[allow(unused)] +pub const MINGLING_JSON_SERDE_FMT: bool = false; -#[cfg(not(feature = "repl"))] -pub const MINGLING_REPL: bool = false; - -#[cfg(feature = "repl")] -pub const MINGLING_REPL: bool = true; - -#[cfg(not(feature = "comp"))] -pub const MINGLING_COMP: bool = false; - -#[cfg(feature = "comp")] -pub const MINGLING_COMP: bool = true; +/// Whether the `json_serde_fmt` feature is enabled +/// Current: `enabled` +#[cfg(feature = "json_serde_fmt")] +#[allow(unused)] +pub const MINGLING_JSON_SERDE_FMT: bool = true; +/// Whether the `nightly` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "nightly"))] +#[allow(unused)] +pub const MINGLING_NIGHTLY: bool = false; +/// Whether the `nightly` feature is enabled +/// Current: `enabled` +#[cfg(feature = "nightly")] +#[allow(unused)] +pub const MINGLING_NIGHTLY: bool = true; +/// Whether the `parser` feature is enabled +/// Current: `disabled` #[cfg(not(feature = "parser"))] +#[allow(unused)] pub const MINGLING_PARSER: bool = false; +/// Whether the `parser` feature is enabled +/// Current: `enabled` #[cfg(feature = "parser")] +#[allow(unused)] pub const MINGLING_PARSER: bool = true; +/// Whether the `repl` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "repl"))] +#[allow(unused)] +pub const MINGLING_REPL: bool = false; -#[cfg(not(feature = "json_serde_fmt"))] -pub const MINGLING_JSON_SERDE_FMT: bool = false; - -#[cfg(feature = "json_serde_fmt")] -pub const MINGLING_JSON_SERDE_FMT: bool = true; - -#[cfg(not(feature = "yaml_serde_fmt"))] -pub const MINGLING_YAML_SERDE_FMT: bool = false; - -#[cfg(feature = "yaml_serde_fmt")] -pub const MINGLING_YAML_SERDE_FMT: bool = true; +/// Whether the `repl` feature is enabled +/// Current: `enabled` +#[cfg(feature = "repl")] +#[allow(unused)] +pub const MINGLING_REPL: bool = true; +/// Whether the `repl_extra` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "repl_extra"))] +#[allow(unused)] +pub const MINGLING_REPL_EXTRA: bool = false; + +/// Whether the `repl_extra` feature is enabled +/// Current: `enabled` +#[cfg(feature = "repl_extra")] +#[allow(unused)] +pub const MINGLING_REPL_EXTRA: bool = true; +/// Whether the `ron_serde_fmt` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "ron_serde_fmt"))] +#[allow(unused)] +pub const MINGLING_RON_SERDE_FMT: bool = false; +/// Whether the `ron_serde_fmt` feature is enabled +/// Current: `enabled` +#[cfg(feature = "ron_serde_fmt")] +#[allow(unused)] +pub const MINGLING_RON_SERDE_FMT: bool = true; +/// Whether the `toml_serde_fmt` feature is enabled +/// Current: `disabled` #[cfg(not(feature = "toml_serde_fmt"))] +#[allow(unused)] pub const MINGLING_TOML_SERDE_FMT: bool = false; +/// Whether the `toml_serde_fmt` feature is enabled +/// Current: `enabled` #[cfg(feature = "toml_serde_fmt")] +#[allow(unused)] pub const MINGLING_TOML_SERDE_FMT: bool = true; +/// Whether the `yaml_serde_fmt` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "yaml_serde_fmt"))] +#[allow(unused)] +pub const MINGLING_YAML_SERDE_FMT: bool = false; -#[cfg(not(feature = "ron_serde_fmt"))] -pub const MINGLING_RON_SERDE_FMT: bool = false; - -#[cfg(feature = "ron_serde_fmt")] -pub const MINGLING_RON_SERDE_FMT: bool = true; +/// Whether the `yaml_serde_fmt` feature is enabled +/// Current: `enabled` +#[cfg(feature = "yaml_serde_fmt")] +#[allow(unused)] +pub const MINGLING_YAML_SERDE_FMT: bool = true; diff --git a/mingling/src/features.rs.tmpl b/mingling/src/features.rs.tmpl new file mode 100644 index 0000000..3447041 --- /dev/null +++ b/mingling/src/features.rs.tmpl @@ -0,0 +1,15 @@ +>>>>>>>>>> features + +@@@ >>> features +/// Whether the `<<>>` feature is enabled +/// Current: `disabled` +#[cfg(not(feature = "<<>>"))] +#[allow(unused)] +pub const MINGLING_<<>>: bool = false; + +/// Whether the `<<>>` feature is enabled +/// Current: `enabled` +#[cfg(feature = "<<>>")] +#[allow(unused)] +pub const MINGLING_<<>>: bool = true; +@@@ <<< diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs index 83fd64e..ee01fb7 100644 --- a/mingling/src/lib.rs +++ b/mingling/src/lib.rs @@ -155,44 +155,7 @@ mod features; /// They can be used for conditional compilation or runtime branching based on /// feature availability. pub mod feature { - /// Whether the `async` feature is enabled - pub use crate::features::MINGLING_ASYNC; - - /// Whether the `clap` feature is enabled - pub use crate::features::MINGLING_CLAP; - - /// Whether the `comp` feature is enabled - pub use crate::features::MINGLING_COMP; - - /// Whether the `debug` feature is enabled - pub use crate::features::MINGLING_DEBUG; - - /// Whether the `dispatch_tree` feature is enabled - pub use crate::features::MINGLING_DISPATCH_TREE; - - /// Whether the `general_renderer` feature is enabled - pub use crate::features::MINGLING_GENERAL_RENDERER; - - /// Whether the `nightly` feature is enabled - pub use crate::features::MINGLING_NIGHTLY; - - /// Whether the `parser` feature is enabled - pub use crate::features::MINGLING_PARSER; - - /// Whether the `repl` feature is enabled - pub use crate::features::MINGLING_REPL; - - /// Whether the `json_serde_fmt` feature is enabled - pub use crate::features::MINGLING_JSON_SERDE_FMT; - - /// Whether the `ron_serde_fmt` feature is enabled - pub use crate::features::MINGLING_RON_SERDE_FMT; - - /// Whether the `toml_serde_fmt` feature is enabled - pub use crate::features::MINGLING_TOML_SERDE_FMT; - - /// Whether the `yaml_serde_fmt` feature is enabled - pub use crate::features::MINGLING_YAML_SERDE_FMT; + include!("./features.rs"); } mod setups; -- cgit