aboutsummaryrefslogtreecommitdiff
path: root/examples/example-outside-type/src/main.rs
blob: 7cf4d40a9c906a25882046f8d11ac31cb2aaf78b (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
//! Example: Using the `group!()` Macro to Register Outside Types
//!
//! This example demonstrates how to use the `group!()` macro to make outside
//! types (from `std` or other crates) recognizable by the Mingling framework,
//! without modifying the original type definition.
//!
//! Run:
//! ```bash
//! cargo run --manifest-path examples/example-outside-type/Cargo.toml --quiet -- parse 42
//! cargo run --manifest-path examples/example-outside-type/Cargo.toml --quiet -- parse hello
//! cargo run --manifest-path examples/example-outside-type/Cargo.toml --quiet -- error
//! ```
//!
//! Output:
//! ```plaintext
//! Parsed number: 42
//! Parse error: invalid digit found in string
//! IO_ERROR: Error
//! ```

use mingling::{macros::group, prelude::*};
use std::{io::ErrorKind::Other, num::ParseIntError};

dispatcher!("parse");
dispatcher!("error");

#[chain]
fn handle_entry_error(_args: EntryError) -> Next {
    std::io::Error::new(Other, "Error").to_render()
}

// --------- IMPORTANT ---------
// You can directly use the `group!` macro to define outside types as types
// recognizable by Mingling
//      _____________ from std::num::ParseIntError
//     /
//     vvvvvvvvvvvvv
group!(ParseIntError);
group!(ErrorIo = std::io::Error);
//     ^^^^^^^^^^^^^^^^^^^^^^^^
//     \_____________ For types whose names may cause ambiguity,
//                      you can use this syntax to create an alias simultaneously
// --------- IMPORTANT ---------

pack!(ParsedNumber = i32);

/// Parse the first argument as an `i32`
///
/// On success, routes to `render_number`.
/// 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();
    match input.parse::<i32>() {
        Ok(num) => ParsedNumber::new(num).to_chain(),
        Err(e) => e.to_chain(),
    }
}

/// Renderer for successful parse — displays the parsed integer.
//                     _____________ Using std::num::ParseIntError as a chain input
//                    /
#[renderer] //        vvvvvvvvvvvv
fn render_number(num: ParsedNumber) {
    r_println!("Parsed number: {}", *num);
}

/// Renderer for parse errors — using the outside `ParseIntError` type.
///
/// The `ParseIntError` type is registered via `group!` above, so it implements
/// `Groupped<ThisProgram>` and can be used directly in a `#[renderer]` function.
#[renderer]
fn render_parse_error(err: ParseIntError) {
    r_println!("Parse error: {}", err);
}

/// Renderer for IO errors — using `std::io::Error` registered as `ErrorIo`.
//                       ________ Must use alias `ErrorIo` here, not bare `std::io::Error`
//                      /
#[renderer] //          vvvvvvv
fn render_error_io(err: ErrorIo) {
    r_println!("IO_ERROR: {}", err.to_string());
}

fn main() {
    let mut program = ThisProgram::new();
    program.with_dispatcher(CMDParse);
    program.with_dispatcher(CMDError);
    program.exec_and_exit();
}

gen_program!();