aboutsummaryrefslogtreecommitdiff
path: root/mingling/src
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-08-17 05:49:19 +0800
committer魏曹先生 <1992414357@qq.com>2026-08-17 05:49:19 +0800
commit57c53affe3542cb6bd4e79ee4c18f20a1bd76b2d (patch)
tree1cd4aef44cb7a45a8cd9d520b598f5f181e24c76 /mingling/src
parentef23cd944402939605c78a4a853ef6e33af02c21 (diff)
refactor!: replace pack! macros with derive-based pipeline types
Remove the `pack!`, `pack_err!`, `pack_structural!`, and `pack_err_structural!` macros, replacing all pipeline type definitions with `#[derive(Grouped)]` and `#[derive(Grouped, Wrap)]` attributes. This changes the generated struct shape from named-field structs with an `inner` field to tuple structs accessed via `.0`, and removes the auto-generated `name` and `info` fields from error types.
Diffstat (limited to 'mingling/src')
-rw-r--r--mingling/src/docs/lib.md5
-rw-r--r--mingling/src/example_docs.rs447
-rw-r--r--mingling/src/gen_program.rs12
-rw-r--r--mingling/src/lib.rs21
4 files changed, 162 insertions, 323 deletions
diff --git a/mingling/src/docs/lib.md b/mingling/src/docs/lib.md
index 91858d0..3b1f328 100644
--- a/mingling/src/docs/lib.md
+++ b/mingling/src/docs/lib.md
@@ -29,12 +29,13 @@ fn main() {
program.exec_and_exit();
}
-pack!(ResultName = String);
+#[derive(Grouped, Wrap)]
+pub struct ResultName(String);
#[chain]
fn handle_greet(args: EntryGreet) -> Next {
let name: ResultName = args
- .inner
+ .0
.first()
.cloned()
.unwrap_or_else(|| "World".to_string())
diff --git a/mingling/src/example_docs.rs b/mingling/src/example_docs.rs
index 9406ddc..d37e762 100644
--- a/mingling/src/example_docs.rs
+++ b/mingling/src/example_docs.rs
@@ -64,17 +64,32 @@
///
/// dispatcher!("calc", EntryCalculate);
///
-/// pack_err!(ErrorNumberANotProvided);
-/// pack_err!(ErrorNumberBNotProvided);
-/// pack_err!(ErrorNumberOperatorNotProvided);
-/// pack_err!(ErrorDivisionByZero);
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorNumberANotProvided;
///
-/// pack!(StateAdd = (f32, f32));
-/// pack!(StateSubtract = (f32, f32));
-/// pack!(StateMultiply = (f32, f32));
-/// pack!(StateDivide = (f32, f32));
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorNumberBNotProvided;
///
-/// pack!(ResultNumber = f32);
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorNumberOperatorNotProvided;
+///
+/// #[derive(Grouped, Default)]
+/// pub struct ErrorDivisionByZero;
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateAdd((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateSubtract((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateMultiply((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateDivide((f32, f32));
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultNumber(f32);
///
/// #[derive(Grouped)]
/// struct StateCalculate {
@@ -155,13 +170,13 @@
/// // Use the arg! macro to define a positional argument of type f32
/// // |
/// // vvvvvvvvvv
-/// args.pick_or_route(&arg![f32], || ErrorNumberANotProvided::default().to_chain())
+/// args.pick_or_route(&arg![f32], || ErrorNumberANotProvided.to_chain())
/// .pick_or_route(&arg![Operator], || {
-/// ErrorNumberOperatorNotProvided::default().to_chain()
+/// ErrorNumberOperatorNotProvided.to_chain()
/// }) // Returns a routable type when not found or fails to parse
/// // |
-/// // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
-/// .pick_or_route(&arg![f32], || ErrorNumberBNotProvided::default().to_chain())
+/// // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+/// .pick_or_route(&arg![f32], || ErrorNumberBNotProvided.to_chain())
/// // Use `to_result` to parse arguments
/// // and convert to Result<(Tuple, ...), Route> type
/// .to_result()
@@ -169,7 +184,7 @@
/// // --------- IMPORTANT ---------
///
/// if operator == Operator::Slash && number_b == 0. {
-/// return ErrorDivisionByZero::default().to_chain();
+/// return ErrorDivisionByZero.to_chain();
/// }
///
/// StateCalculate {
@@ -183,41 +198,41 @@
/// #[chain]
/// fn handle_state_calculate(state: StateCalculate) -> Next {
/// match (state.operator, state.number_a, state.number_b) {
-/// (Operator::Plus, a, b) => StateAdd::new((a, b)).to_chain(),
-/// (Operator::Dash, a, b) => StateSubtract::new((a, b)).to_chain(),
-/// (Operator::Slash, a, b) => StateDivide::new((a, b)).to_chain(),
-/// (Operator::Star, a, b) => StateMultiply::new((a, b)).to_chain(),
+/// (Operator::Plus, a, b) => StateAdd((a, b)).to_chain(),
+/// (Operator::Dash, a, b) => StateSubtract((a, b)).to_chain(),
+/// (Operator::Slash, a, b) => StateDivide((a, b)).to_chain(),
+/// (Operator::Star, a, b) => StateMultiply((a, b)).to_chain(),
/// }
/// }
///
/// #[chain]
/// fn handle_state_add(state_add: StateAdd) -> ResultNumber {
-/// let (a, b) = state_add.inner;
-/// ResultNumber::new(a + b)
+/// let (a, b) = state_add.0;
+/// ResultNumber(a + b)
/// }
///
/// #[chain]
/// fn handle_state_subtract(state_subtract: StateSubtract) -> ResultNumber {
-/// let (a, b) = state_subtract.inner;
-/// ResultNumber::new(a - b)
+/// let (a, b) = state_subtract.0;
+/// ResultNumber(a - b)
/// }
///
/// #[chain]
/// fn handle_state_multiply(state_multiply: StateMultiply) -> ResultNumber {
-/// let (a, b) = state_multiply.inner;
-/// ResultNumber::new(a * b)
+/// let (a, b) = state_multiply.0;
+/// ResultNumber(a * b)
/// }
///
/// #[chain]
/// fn handle_state_divide(state_divide: StateDivide) -> ResultNumber {
-/// let (a, b) = state_divide.inner;
-/// ResultNumber::new(a / b)
+/// let (a, b) = state_divide.0;
+/// ResultNumber(a / b)
/// }
///
/// #[renderer]
/// fn render_result_number(result: ResultNumber, setting: &ResNumberDisplaySetting) -> String {
/// let round = setting.round;
-/// let result = if round { result.round() } else { result.inner };
+/// let result = if round { result.round() } else { result.0 };
/// format!("Result: {}", result)
/// }
///
@@ -310,7 +325,8 @@ pub mod example_argument_picker {}
///
/// dispatcher!("download", EntryDownload);
///
-/// pack!(ResultDownloaded = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultDownloaded(String);
///
/// // --------- IMPORTANT ---------
/// #[chain]
@@ -334,7 +350,7 @@ pub mod example_argument_picker {}
///
/// async fn fake_download(file_name: String) -> ResultDownloaded {
/// tokio::time::sleep(std::time::Duration::from_secs(1)).await;
-/// ResultDownloaded::new(file_name)
+/// ResultDownloaded(file_name)
/// }
/// ```
pub mod example_async_support {}
@@ -372,11 +388,11 @@ pub mod example_async_support {}
/// use std::io::Write;
///
/// // Define the `greet` subcommand
-/// // _____________________________ subcmd name, can be nested (e.g. "remote.add" "remote.rm")
-/// // / _____________________ dispatcher name
-/// // | / _________ entry, records raw arguments
-/// // | | / ^^^^^^^^^^^^^
-/// // vvvvv vvvvvvvv vvvvvvvvvv \_ equivalent to pack!(EntryGreet = Vec<String>)
+/// // _________________ subcmd name, can be nested (e.g. "remote.add" "remote.rm")
+/// // /
+/// // | _________ entry, records raw arguments
+/// // | / ^^^^^^^^^^^^^
+/// // vvvvv vvvvvvvvvv \_ a newtype wrapper around Vec<String>
/// dispatcher!("greet", EntryGreet);
///
/// fn main() {
@@ -388,21 +404,22 @@ pub mod example_async_support {}
/// }
///
/// // Quickly wrap a type into a type recognizable by the current program
-/// // ____________________ Wrapped type name
-/// // / _______ Wrapped type inner value
-/// // | /
-/// // vvvvvvvvvv vvvvvv
-/// pack!(ResultName = String);
+/// // ___________________ Registers this type into ThisProgram
+/// // / _______ Adds DerefMut, Deref, Into, From wrappers
+/// // | /
+/// // vvvvvvvvvv vvvvv
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// // Define the `handle_greet` chain for parsing input text
/// // ____________________ Previous type:
/// // / Mingling deduces types at runtime and routes them to this function
/// // | _____ will be expanded to:
-/// // | / impl Into<mingling::ChainProcess<ThisProgram>>
+/// // | / ChainProcess<ThisProgram>
/// #[chain] // vvvvvvvvvv vvvv
/// fn handle_greet(args: EntryGreet) -> Next {
/// let name: ResultName = args
-/// .inner
+/// .0
/// .first()
/// .cloned()
/// .unwrap_or_else(|| "World".to_string())
@@ -745,27 +762,30 @@ pub mod example_combine_pathf_metadata {}
/// ThisProgram::new().exec_and_exit();
/// }
///
-/// pack!(ResultGreeting = String);
-/// pack!(ResultGoodbye = ());
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultGreeting(String);
+///
+/// #[derive(Grouped)]
+/// pub struct ResultGoodbye;
///
/// // --------- IMPORTANT ---------
/// // Auto-generates dispatcher!("hello.world", EntryHelloWorld);
/// #[command]
/// fn hello_world() -> ResultGreeting {
-/// ResultGreeting::new("World".to_string())
+/// ResultGreeting("World".to_string())
/// }
///
/// // Auto-generates dispatcher!("hello-world", EntryGreetSomeone);
/// #[command(node = "greet-someone")]
/// fn greet_someone(args: Vec<String>) -> ResultGreeting {
/// let name = args.pick_or(&arg![String], || "World".to_string()).unwrap();
-/// ResultGreeting::new(name)
+/// ResultGreeting(name)
/// }
///
/// // Auto-generates dispatcher!("goodbye", EntryGoodBye);
/// #[command(entry = EntryGoodBye)]
/// fn goodbye() -> ResultGoodbye {
-/// ResultGoodbye::default()
+/// ResultGoodbye
/// }
/// // --------- IMPORTANT ---------
///
@@ -918,7 +938,8 @@ pub mod example_command_macro {}
/// // --------- IMPORTANT ---------
///
/// dispatcher!("greet", EntryGreet);
-/// pack!(ResultName = (u8, String));
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName((u8, String));
///
/// #[chain]
/// fn handle_greet(args: EntryGreet) -> Next {
@@ -933,7 +954,7 @@ pub mod example_command_macro {}
/// /// Renders the greeting with the result name and repeat count.
/// #[renderer]
/// fn render_name(result: ResultName) -> RenderResult {
-/// let (repeat, name) = result.inner;
+/// let (repeat, name) = result.0;
/// let mut render_result = RenderResult::new();
/// let mut parts = Vec::with_capacity(repeat as usize);
/// for _ in 0..repeat {
@@ -1215,35 +1236,41 @@ pub mod example_enum_tag {}
/// dispatcher!("hello", EntryHello);
///
/// // Define error types
-/// pack!(ErrorNoNameProvided = ());
-/// pack!(ErrorNameTooLong = u16);
-/// pack!(ErrorNameNotAvailable = ());
+/// #[derive(Grouped)]
+/// pub struct ErrorNoNameProvided;
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ErrorNameTooLong(u16);
+///
+/// #[derive(Grouped)]
+/// pub struct ErrorNameNotAvailable;
///
/// // Define success type
-/// pack!(ResultName = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// // Pre-registered names
/// static VEC_REGISTERED_NAMES: &[&str] = &["Alice", "Bob", "Charlie", "David", "Eve"];
///
/// #[chain]
/// fn handle_hello(args: EntryHello) -> Next {
-/// let Some(name) = args.inner.first().cloned() else {
+/// let Some(name) = args.0.first().cloned() else {
/// // If no name is provided, pass ErrorNoNameProvided
-/// return ErrorNoNameProvided::default().to_render();
+/// return ErrorNoNameProvided.to_render();
/// };
///
/// if name.len() > 10 {
/// // If the name is too long, pass ErrorNameTooLong
-/// return ErrorNameTooLong::new(name.len() as u16).to_render();
+/// return ErrorNameTooLong(name.len() as u16).to_render();
/// }
///
/// if VEC_REGISTERED_NAMES.contains(&name.as_str()) {
/// // If the name already exists, pass ErrorNameNotAvailable
-/// return ErrorNameNotAvailable::default().to_render();
+/// return ErrorNameNotAvailable.to_render();
/// }
///
/// // If the name is valid, pass ResultName
-/// ResultName::new(name).to_render()
+/// ResultName(name).to_render()
/// }
///
/// /// Renders a successful greeting with the given name.
@@ -1282,12 +1309,7 @@ pub mod example_enum_tag {}
/// #[renderer]
/// fn render_entry_fallback(err: EntryFallback) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// writeln!(
-/// render_result,
-/// "Command not found: \"{}\"",
-/// err.inner.join(" ")
-/// )
-/// .ok();
+/// writeln!(render_result, "Command not found: \"{}\"", err.0.join(" ")).ok();
/// render_result
/// }
///
@@ -1351,18 +1373,21 @@ pub mod example_error_handling {}
///
/// dispatcher!("hello", EntryHello);
///
-/// pack!(ErrorNoNameProvided = ());
-/// pack!(ResultName = String);
+/// #[derive(Grouped)]
+/// pub struct ErrorNoNameProvided;
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// #[chain]
/// fn handle_hello(args: EntryHello) -> Next {
-/// let Some(name) = args.inner.first().cloned() else {
+/// let Some(name) = args.0.first().cloned() else {
/// // If no name is provided, pass ErrorNoNameProvided
-/// return ErrorNoNameProvided::default().to_render();
+/// return ErrorNoNameProvided.to_render();
/// };
///
/// // If the name is valid, pass ResultName
-/// ResultName::new(name).to_render()
+/// ResultName(name).to_render()
/// }
///
/// /// Renders a successful greeting with the given name.
@@ -1527,12 +1552,13 @@ pub mod example_help {}
/// program.exec_and_exit();
/// }
///
-/// pack!(ResultName = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// #[chain]
/// fn handle_greet(args: EntryGreet) -> Next {
/// let name: ResultName = args
-/// .inner
+/// .0
/// .first()
/// .cloned()
/// .unwrap_or_else(|| "World".to_string())
@@ -1656,7 +1682,8 @@ pub mod example_implicit_dispatcher {}
/// dispatcher!("show", EntryShow);
/// dispatcher!("none", EntryNone);
///
-/// pack!(ResultShow = BTreeMap<Key, Value>);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultShow(BTreeMap<Key, Value>);
///
/// fn main() {
/// let mut program = ThisProgram::new();
@@ -1774,14 +1801,17 @@ pub mod example_lazy_resources {}
/// }
/// // --------- IMPORTANT ---------
///
-/// pack!(ResultName = String);
-/// pack!(DescResult = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct DescResult(String);
///
/// /// Chain for `greet` — reads the name and produces a `ResultName`.
/// #[chain]
/// fn handle_greet(args: EntryGreet) -> Next {
/// let name: ResultName = args
-/// .inner
+/// .0
/// .first()
/// .cloned()
/// .unwrap_or_else(|| "World".to_string())
@@ -1799,7 +1829,7 @@ pub mod example_lazy_resources {}
/// None => "EntryGreet has no description".to_string(),
/// };
/// // --------- IMPORTANT ---------
-/// DescResult::new(msg).to_render()
+/// DescResult(msg).to_render()
/// }
///
/// /// Chain for `nodoc` — asks for metadata on an entry that has none.
@@ -1812,7 +1842,7 @@ pub mod example_lazy_resources {}
/// None => "EntryDescription has no description".to_string(),
/// };
/// // --------- IMPORTANT ---------
-/// DescResult::new(msg).to_render()
+/// DescResult(msg).to_render()
/// }
///
/// /// Renders the greeting message with the provided name.
@@ -1897,7 +1927,8 @@ pub mod example_metadata {}
/// // you can use this syntax to create an alias simultaneously
/// // --------- IMPORTANT ---------
///
-/// pack!(ParsedNumber = i32);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ParsedNumber(i32);
///
/// /// Parse the first argument as an `i32`
/// ///
@@ -1905,9 +1936,9 @@ pub mod example_metadata {}
/// /// On failure, routes to `render_parse_error` via the registered outside type.
/// #[chain]
/// fn parse_number(args: EntryParse) -> Next {
-/// let input = args.inner.first().cloned().unwrap_or_default();
+/// let input = args.0.first().cloned().unwrap_or_default();
/// match input.parse::<i32>() {
-/// Ok(num) => ParsedNumber::new(num).to_chain(),
+/// Ok(num) => ParsedNumber(num).to_chain(),
/// Err(e) => e.to_chain(),
/// }
/// }
@@ -1950,181 +1981,6 @@ pub mod example_metadata {}
/// gen_program!();
/// ```
pub mod example_outside_type {}
-/// 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 `structural_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 Cargo.toml
-/// 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-structural --json
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural Cargo.toml --json
-/// cargo run --manifest-path examples/example-pack-err/Cargo.toml --quiet -- find-structural src --json
-/// ```
-///
-/// Output:
-/// ```plaintext
-/// Search path not provided
-/// Not a directory: Cargo.toml
-/// Found directory: src
-/// {"name":"error_not_found"}
-/// {"name":"error_not_dir","info":"Cargo.toml"}
-/// {"inner":"src"}
-/// {"name":"error_not_found_structural"}
-/// {"name":"error_not_dir_structural","info":"Cargo.toml"}
-/// ```
-///
-/// 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 = [
-/// "structural_renderer",
-/// "extras",
-/// ]
-///
-/// [workspace]
-/// ```
-///
-/// Source code (./src/main.rs)
-/// ```ignore
-/// use mingling::prelude::*;
-/// use mingling::setup::StructuralRendererSetup;
-/// use std::io::Write;
-/// use std::path::PathBuf;
-///
-/// dispatcher!("find", EntryFind);
-/// dispatcher!("find-structural", EntryFindStructural);
-///
-/// // --------- 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 `structural_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);
-///
-/// // Simple form — with StructuralData support for --json / --yaml
-/// pack_err_structural!(ErrorNotFoundStructural);
-///
-/// // Typed form — with StructuralData support for --json / --yaml
-/// pack_err_structural!(ErrorNotDirStructural = PathBuf);
-///
-/// // Success type with StructuralData support
-/// pack_structural!(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()
-/// }
-/// }
-///
-/// #[chain]
-/// fn handle_find_structural(args: EntryFindStructural) -> Next {
-/// let Some(path_str) = args.inner.first().cloned() else {
-/// // No path provided → use the simple error form (Default)
-/// return ErrorNotFoundStructural::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
-/// ErrorNotDirStructural::new(path).to_render()
-/// }
-/// }
-///
-/// /// Renders the successful result with the found directory path.
-/// #[renderer]
-/// fn render_result_path(path: ResultPath) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Found directory: {}", path.display()).ok();
-/// render_result
-/// }
-///
-/// /// Renders the error when no search path is provided.
-/// #[renderer]
-/// fn render_error_not_found(_: ErrorNotFound) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Search path not provided").ok();
-/// render_result
-/// }
-///
-/// /// Renders the error when the given path is not a directory.
-/// #[renderer]
-/// fn render_error_not_dir(err: ErrorNotDir) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
-/// render_result
-/// }
-///
-/// /// Renders the structural error when no search path is provided.
-/// #[renderer]
-/// fn render_error_not_found_structural(_: ErrorNotFoundStructural) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Search path not provided").ok();
-/// render_result
-/// }
-///
-/// /// Renders the structural error when the given path is not a directory.
-/// #[renderer]
-/// fn render_error_not_dir_structural(err: ErrorNotDirStructural) -> RenderResult {
-/// let mut render_result = RenderResult::new();
-/// writeln!(render_result, "Not a directory: {}", err.info.display()).ok();
-/// render_result
-/// }
-///
-/// gen_program!();
-///
-/// fn main() {
-/// let mut program = ThisProgram::new();
-///
-/// // Add StructuralRendererSetup to support --json / --yaml flags
-/// program.with_setup(StructuralRendererSetup);
-///
-/// let _ = program.exec();
-/// }
-/// ```
-pub mod example_pack_err {}
/// Example Panic Unwind
///
/// > This example introduces how to catch Panic in the Mingling program loop
@@ -2171,7 +2027,9 @@ pub mod example_pack_err {}
/// use std::io::Write;
///
/// dispatcher!("panic", EntryPanic);
-/// pack!(NotPanic = ());
+///
+/// #[derive(Grouped)]
+/// pub struct NotPanic;
///
/// fn main() {
/// let mut program = ThisProgram::new();
@@ -2198,7 +2056,7 @@ pub mod example_pack_err {}
/// // Panic happens here, will be caught
/// panic!("{}", s)
/// }
-/// None => NotPanic::default().into(),
+/// None => NotPanic.into(),
/// }
/// }
///
@@ -2364,7 +2222,8 @@ pub mod example_pathfinder {}
/// }
///
/// // Create error route
-/// pack!(ErrorDirectoryNotExist = PathBuf);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ErrorDirectoryNotExist(PathBuf);
///
/// // Create commands: cd ls exit
/// dispatcher!("cd", EntryCd);
@@ -2373,16 +2232,18 @@ pub mod example_pathfinder {}
/// dispatcher!("clear", EntryClear);
///
/// // Define data needed for the cd command's execution phase
-/// pack!(StateChangeDirectory = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct StateChangeDirectory(String);
///
/// // Define data needed for the ls command's rendering phase
-/// pack!(ResultList = Vec<String>);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultList(Vec<String>);
///
/// // Parse cd command arguments
/// #[chain]
/// fn parse_cd_args(prev: EntryCd) -> Next {
/// let join = prev.pick_or_default(&arg![String]).unwrap();
-/// StateChangeDirectory::new(join).into()
+/// StateChangeDirectory(join).into()
/// }
///
/// // Execute directory change
@@ -2390,12 +2251,12 @@ pub mod example_pathfinder {}
/// fn handle_cd(prev: StateChangeDirectory, current_dir: &mut ResCurrentDir) -> Next {
/// use just_fmt::fmt_path::fmt_path;
///
-/// let join = prev.inner;
+/// let join = prev.0;
/// let new_dir = fmt_path(current_dir.dir.join(join)).unwrap_or_default();
///
/// // If the path is not found, route to error handling
/// if !new_dir.exists() {
-/// return ErrorDirectoryNotExist::new(new_dir).to_render();
+/// return ErrorDirectoryNotExist(new_dir).to_render();
/// }
///
/// current_dir.dir = new_dir;
@@ -2420,14 +2281,14 @@ pub mod example_pathfinder {}
/// .collect();
///
/// // Render ResultList
-/// ResultList::new(entries).to_render()
+/// ResultList(entries).to_render()
/// }
///
/// /// Render ResultList data
/// #[renderer]
/// fn render_list(list: ResultList) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// for item in list.inner {
+/// for item in list.0 {
/// writeln!(render_result, "{}", item).ok();
/// }
/// render_result
@@ -2454,12 +2315,7 @@ pub mod example_pathfinder {}
/// #[renderer]
/// fn render_error_directory_not_exist(err: ErrorDirectoryNotExist) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// writeln!(
-/// render_result,
-/// "Directory not found: {}",
-/// err.inner.display()
-/// )
-/// .ok();
+/// writeln!(render_result, "Directory not found: {}", err.0.display()).ok();
/// render_result
/// }
///
@@ -2636,13 +2492,14 @@ pub mod example_resources {}
///
/// dispatcher!("greet", EntryGreet);
///
-/// pack!(ResultGreeting = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultGreeting(String);
///
/// /// Chain: reads the `ResAppName` and `ResAppVersion` resources.
/// #[chain]
/// fn handle_greet(args: EntryGreet, app: &ResAppName, version: &ResAppVersion) -> Next {
/// let who = args
-/// .inner
+/// .0
/// .first()
/// .cloned()
/// .unwrap_or_else(|| "World".to_string());
@@ -2718,7 +2575,8 @@ pub mod example_setup {}
/// }
///
/// // --------- IMPORTANT ---------
-/// // For beautiful output structure, do not use `pack!` to wrap the types that need to be output.
+/// // For beautiful output structure, do not wrap the types that need to be output
+/// // in a newtype; instead, use a named struct.
/// // Instead, manually implement
/// // ____________________________________ Mark as structured data so it can be rendered
/// // / ____________________ Implement serde::Serialize
@@ -2734,7 +2592,7 @@ pub mod example_setup {}
/// }
/// // This will output: {"member_name":"name","member_age":32} structure
///
-/// // If using pack!(Info = (String, i32));
+/// // If wrapping with a tuple newtype (e.g. `#[derive(Grouped, Wrap)] pub struct Info((String, i32));`)
/// // Output: {"inner":["name", 32]}
///
/// // --------- IMPORTANT ---------
@@ -2812,30 +2670,30 @@ pub mod example_structural_renderer {}
/// let hello_with_valid_name = handle_hello(entry!("Peter")).into();
/// assert_render_result!(hello_with_valid_name);
/// let result_name = unpack_chain_process!(hello_with_valid_name, ResultName);
-/// assert_eq!(result_name.inner, "Peter");
+/// assert_eq!(result_name.0, "Peter");
/// }
///
/// #[test]
/// fn test_render_result_name() {
-/// let r = render_result_name(ResultName::new("Peter".into()));
+/// let r = render_result_name(ResultName("Peter".into()));
/// assert_eq!(r.to_string().as_str(), "Hello, Peter!")
/// }
///
/// #[test]
/// fn test_render_error_no_name_provided() {
-/// let r = render_error_no_name_provided(ErrorNoNameProvided::default());
+/// let r = render_error_no_name_provided(ErrorNoNameProvided);
/// assert_eq!(r.to_string().as_str(), "No name provided")
/// }
///
/// #[test]
/// fn test_render_error_name_not_available() {
-/// let r = render_error_name_not_available(ErrorNameNotAvailable::default());
+/// let r = render_error_name_not_available(ErrorNameNotAvailable);
/// assert_eq!(r.to_string().as_str(), "Name not available")
/// }
///
/// #[test]
/// fn test_render_error_name_too_long() {
-/// let r = render_error_name_too_long(ErrorNameTooLong::new(17));
+/// let r = render_error_name_too_long(ErrorNameTooLong(17));
/// assert_eq!(r.to_string().as_str(), "Name too long: 17 > 10")
/// }
/// // --------- IMPORTANT ---------
@@ -2843,29 +2701,35 @@ pub mod example_structural_renderer {}
///
/// dispatcher!("hello", EntryHello);
///
-/// pack!(ErrorNoNameProvided = ());
-/// pack!(ErrorNameTooLong = u16);
-/// pack!(ErrorNameNotAvailable = ());
+/// #[derive(Grouped)]
+/// pub struct ErrorNoNameProvided;
+///
+/// #[derive(Grouped, Wrap)]
+/// pub struct ErrorNameTooLong(u16);
+///
+/// #[derive(Grouped)]
+/// pub struct ErrorNameNotAvailable;
///
-/// pack!(ResultName = String);
+/// #[derive(Grouped, Wrap)]
+/// pub struct ResultName(String);
///
/// static VEC_REGISTERED_NAMES: &[&str] = &["Alice", "Bob", "Charlie", "David", "Eve"];
///
/// #[chain]
/// fn handle_hello(args: EntryHello) -> Next {
-/// let Some(name) = args.inner.first().cloned() else {
-/// return ErrorNoNameProvided::default().to_render();
+/// let Some(name) = args.0.first().cloned() else {
+/// return ErrorNoNameProvided.to_render();
/// };
///
/// if name.len() > 10 {
-/// return ErrorNameTooLong::new(name.len() as u16).to_render();
+/// return ErrorNameTooLong(name.len() as u16).to_render();
/// }
///
/// if VEC_REGISTERED_NAMES.contains(&name.as_str()) {
-/// return ErrorNameNotAvailable::default().to_render();
+/// return ErrorNameNotAvailable.to_render();
/// }
///
-/// ResultName::new(name).to_render()
+/// ResultName(name).to_render()
/// }
///
/// /// Renders a successful greeting with the given name.
@@ -2904,12 +2768,7 @@ pub mod example_structural_renderer {}
/// #[renderer]
/// fn render_entry_fallback(err: EntryFallback) -> RenderResult {
/// let mut render_result = RenderResult::new();
-/// writeln!(
-/// render_result,
-/// "Command not found: \"{}\"",
-/// err.inner.join(" ")
-/// )
-/// .ok();
+/// writeln!(render_result, "Command not found: \"{}\"", err.0.join(" ")).ok();
/// render_result
/// }
///
diff --git a/mingling/src/gen_program.rs b/mingling/src/gen_program.rs
index 2c476a2..ed60668 100644
--- a/mingling/src/gen_program.rs
+++ b/mingling/src/gen_program.rs
@@ -12,7 +12,7 @@ pub type Next = ChainProcess<ThisProgram>;
/// The generic program entry point.
///
-/// This type is created by the `pack!` macro as a variant of the
+/// This type is generated by the `gen_program!` macro as a variant of the
/// program's output type set (`ThisProgram`).
pub struct Entry {
/// The arguments provided by the user
@@ -41,7 +41,7 @@ pub enum ThisProgram {
/// A struct representing a "renderer not found" error.
///
-/// This type is created by the `pack!` macro as a variant of the
+/// This type is generated by the `gen_program!` macro as a variant of the
/// program's output type set (`ThisProgram`).
pub struct ErrorRendererNotFound {
/// The name of the renderer that was not found
@@ -50,7 +50,7 @@ pub struct ErrorRendererNotFound {
/// A struct representing a "dispatcher not found" error.
///
-/// This type is created by the `pack!` macro as a variant of the
+/// This type is generated by the `gen_program!` macro as a variant of the
/// program's output type set (`ThisProgram`).
pub struct EntryFallback {
/// The arguments provided by the user
@@ -61,8 +61,6 @@ pub struct EntryFallback {
pub struct ResultEmpty;
/// A dispatcher representing the subcommand `__comp` itself.
-///
-/// **You can register it using `with_dispatcher`.**
#[cfg(feature = "comp")]
pub struct CMDCompletion;
@@ -71,7 +69,7 @@ pub struct CMDCompletion;
/// This struct holds the raw command-line arguments that were passed to the `__comp`
/// subcommand, which will be used to compute completion suggestions.
///
-/// This type is created by the `pack!` macro as a variant of the
+/// This type is generated by the `gen_program!` macro as a variant of the
/// program's output type set (`ThisProgram`).
#[cfg(feature = "comp")]
pub struct CompletionContext {
@@ -85,7 +83,7 @@ pub struct CompletionContext {
/// which together provide the information needed to render completion candidates
/// to the user's shell.
///
-/// This type is created by the `pack!` macro as a variant of the
+/// This type is generated by the `gen_program!` macro as a variant of the
/// program's output type set (`ThisProgram`).
#[cfg(feature = "comp")]
pub struct CompletionSuggest {
diff --git a/mingling/src/lib.rs b/mingling/src/lib.rs
index 6a7074b..55240e5 100644
--- a/mingling/src/lib.rs
+++ b/mingling/src/lib.rs
@@ -51,7 +51,7 @@ pub mod consts {
///
/// This module re-exports all macros provided by the `mingling_macros` crate,
/// including `dispatcher!`, `chain!`, `renderer!`,
-/// `gen_program!`, `pack!`, and many others. These macros form the core
+/// `gen_program!`, and many others. These macros form the core
/// building blocks of the Mingling framework.
///
/// For detailed documentation, usage examples, and the full list of available
@@ -84,13 +84,6 @@ pub mod macros {
pub use mingling_macros::help;
pub use mingling_macros::metadata;
pub use mingling_macros::mlint;
- pub use mingling_macros::pack;
- #[cfg(feature = "extras")]
- pub use mingling_macros::pack_err;
- #[cfg(all(feature = "structural_renderer", feature = "extras"))]
- pub use mingling_macros::pack_err_structural;
- #[cfg(feature = "structural_renderer")]
- pub use mingling_macros::pack_structural;
#[cfg(feature = "comp")]
#[doc(hidden)]
pub use mingling_macros::program_comp_gen;
@@ -212,19 +205,7 @@ pub mod prelude {
#[cfg(feature = "macros")]
pub use crate::macros::gen_program;
#[cfg(feature = "macros")]
- pub use crate::macros::pack;
- #[cfg(all(feature = "extras", feature = "macros"))]
- pub use crate::macros::pack_err;
- #[cfg(feature = "macros")]
pub use crate::macros::renderer;
- #[cfg(all(
- feature = "macros",
- feature = "structural_renderer",
- feature = "extras"
- ))]
- pub use mingling_macros::pack_err_structural;
- #[cfg(all(feature = "macros", feature = "structural_renderer"))]
- pub use mingling_macros::pack_structural;
pub use mingling_macros::r_append;
pub use mingling_macros::r_eprint;
pub use mingling_macros::r_eprintln;