From 0f7b2a50b05f38d886234ff6b031766c7af1dabb Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Thu, 18 Jun 2026 22:48:16 +0800 Subject: Add `pack_err!` macro for error structs with automatic name field --- mingling/src/example_docs.rs | 125 +++++++++++++++++++++++++++++++++++++++++++ mingling/src/lib.rs | 6 +++ 2 files changed, 131 insertions(+) (limited to 'mingling') diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs index f4a27bd..b1d693b 100644 --- a/mingling/src/example_docs.rs +++ b/mingling/src/example_docs.rs @@ -1550,6 +1550,131 @@ pub mod example_implicit_dispatcher {} /// gen_program!(); /// ``` pub mod example_lazy_resources {} +/// Example `pack_err!` +/// +/// > This example demonstrates how to use the `pack_err!` macro to define error types +/// > with automatic `name` field (set to snake_case at compile time) and optional `info` field. +/// > Also demonstrates `--json` serialization when `general_renderer` is enabled. +/// +/// Run: +/// ```bash +/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find +/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find --json +/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find Cargo.toml +/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find Cargo.toml --json +/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find src +/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find src --json +/// ``` +/// +/// Output: +/// ```plaintext +/// Search path not provided +/// {"name":"error_not_found"} +/// Not a directory: Cargo.toml +/// {"name":"error_not_dir","info":"Cargo.toml"} +/// Found directory: src +/// {"inner":"src"} +/// ``` +/// +/// Source code (./Cargo.toml) +/// ```toml +/// [package] +/// name = "example-pack-err" +/// version = "0.1.0" +/// edition = "2024" +/// +/// [dependencies] +/// serde = { version = "1.0.228", features = ["derive"] } +/// +/// [dependencies.mingling] +/// path = "../../mingling" +/// features = [ +/// "general_renderer", +/// "extra_macros", +/// ] +/// +/// [workspace] +/// ``` +/// +/// Source code (./src/main.rs) +/// ```ignore +/// use mingling::prelude::*; +/// use mingling::setup::GeneralRendererSetup; +/// use std::path::PathBuf; +/// +/// dispatcher!("find", CMDFind => EntryFind); +/// +/// // --------- IMPORTANT --------- +/// // `pack_err!` is a convenient macro for defining error types. +/// // +/// // Simple form: pack_err!(ErrorNotFound); +/// // Typed form: pack_err!(ErrorNotDir = PathBuf); +/// // +/// // The simple form generates a struct with `name: String` and `impl Default`. +/// // name = "error_not_found" (automatically snake_cased at compile time) +/// // +/// // The typed form additionally generates `pub fn new(info)`. +/// // name = "error_not_dir" +/// // +/// // When `general_renderer` is enabled, the struct also gets +/// // `#[derive(serde::Serialize)]` for --json / --yaml output. +/// // --------- IMPORTANT --------- +/// +/// // Simple form — name = "error_not_found" +/// pack_err!(ErrorNotFound); +/// +/// // Typed form — name = "error_not_dir" +/// pack_err!(ErrorNotDir = PathBuf); +/// +/// // Success type using traditional pack! +/// pack!(ResultPath = PathBuf); +/// +/// #[chain] +/// fn handle_find(args: EntryFind) -> Next { +/// let Some(path_str) = args.inner.first().cloned() else { +/// // No path provided → use the simple error form (Default) +/// return ErrorNotFound::default().to_render(); +/// }; +/// +/// let path = PathBuf::from(&path_str); +/// if path.is_dir() { +/// // Is a directory → success +/// ResultPath::new(path).to_render() +/// } else { +/// // Not a directory (or doesn't exist) → use the typed error form +/// ErrorNotDir::new(path).to_render() +/// } +/// } +/// +/// /// Renders the successful result with the found directory path. +/// #[renderer] +/// fn render_result_path(path: ResultPath) { +/// r_println!("Found directory: {}", path.display()); +/// } +/// +/// /// Renders the error when no search path is provided. +/// #[renderer] +/// fn render_error_not_found(_: ErrorNotFound) { +/// r_println!("Search path not provided"); +/// } +/// +/// /// Renders the error when the given path is not a directory. +/// #[renderer] +/// fn render_error_not_dir(err: ErrorNotDir) { +/// r_println!("Not a directory: {}", err.info.display()); +/// } +/// +/// gen_program!(); +/// +/// fn main() { +/// let mut program = ThisProgram::new(); +/// // Add GeneralRendererSetup to support --json / --yaml flags +/// program.with_setup(GeneralRendererSetup); +/// program.with_dispatcher(CMDFind); +/// let _ = program.exec(); +/// } +/// ``` +pub mod example_pack_err {} /// Example Panic Unwind /// /// > This example introduces how to catch Panic in the Mingling program loop diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs index 7b96d34..f1232d3 100644 --- a/mingling/src/lib.rs +++ b/mingling/src/lib.rs @@ -99,6 +99,9 @@ pub mod macros { pub use mingling_macros::node; /// Used to create a wrapper type for use with `Chain` and `Renderer` pub use mingling_macros::pack; + /// Used to create an error struct with automatic `name` field + #[cfg(feature = "extra_macros")] + pub use mingling_macros::pack_err; #[cfg(feature = "comp")] /// Internal macro for '`gen_program`' used to finally generate the completion structure pub use mingling_macros::program_comp_gen; @@ -192,6 +195,9 @@ pub mod prelude { pub use crate::macros::gen_program; /// Re-export of the `pack` macro for creating wrapper types. pub use crate::macros::pack; + /// Re-export of the `pack_err` macro for creating error types. + #[cfg(feature = "extra_macros")] + pub use crate::macros::pack_err; /// Re-export of the `r_print` macro for printing within a renderer context. pub use crate::macros::r_print; /// Re-export of the `r_println` macro for printing with a newline within a renderer -- cgit