aboutsummaryrefslogtreecommitdiff
path: root/examples/example-pack-err/src/main.rs
blob: 72fecd6947826d041bafea5e5b69ab0072a9c192 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! 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"}
//! ```

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();
}