aboutsummaryrefslogtreecommitdiff
path: root/examples/example-metadata/src/main.rs
blob: 855241ecb4de460a8ba4ef828a6ad61749ba09f5 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! Example: Entry Metadata (no `pathf`)
//!
//! > Demonstrates attaching arbitrary, compile-time-typed metadata (`Description`)
//! > to an entry via `#[metadata(Entry)]`, and retrieving it at runtime through
//! > `ProgramCollect::get_metadata`. The `desc` and `nodoc` subcommands dispatch
//! > through the normal chain/render pipeline — exactly like `example-basic`.
//!
//! Run:
//! ```bash
//! cargo run --manifest-path examples/example-metadata/Cargo.toml --quiet -- greet Alice
//! cargo run --manifest-path examples/example-metadata/Cargo.toml --quiet -- greet
//! cargo run --manifest-path examples/example-metadata/Cargo.toml --quiet -- desc
//! cargo run --manifest-path examples/example-metadata/Cargo.toml --quiet -- nodoc
//! ```
//!
//! Output:
//! ```plaintext
//! Hello, Alice!
//! Hello, World!
//! EntryGreet desc = ok
//! EntryDescription has no description
//! ```

use mingling::{macros::metadata, prelude::*};
use std::io::Write;

// Define the `greet` subcommand
dispatcher!("greet", CMDGreet => EntryGreet);

// Define the `desc` subcommand, which queries metadata bound to EntryGreet
dispatcher!("desc", CMDDescription => EntryDescription);

// Define the `nodoc` subcommand, which queries metadata for an entry that has none
dispatcher!("nodoc", CMDNoDescription => EntryNoDescription);

fn main() {
    let mut program = ThisProgram::new();
    program.with_dispatcher(CMDGreet);
    program.with_dispatcher(CMDDescription);
    program.with_dispatcher(CMDNoDescription);
    program.exec_and_exit();
}

/// The metadata type attached to an entry.
#[derive(Debug, PartialEq, Eq)]
pub struct Description {
    pub desc: String,
}

// --------- IMPORTANT ---------
/// Attach a `Description` to `EntryGreet`.
///
/// - `BindType` = `EntryGreet` (the enum variant / entry type)
/// - `DataType` = `Description` (the function's return type)
#[metadata(EntryGreet)]
pub fn greet_desc() -> Description {
    Description {
        desc: "ok".to_string(),
    }
}
// --------- IMPORTANT ---------

pack!(ResultName = String);
pack!(DescResult = String);

/// Chain for `greet` — reads the name and produces a `ResultName`.
#[chain]
fn handle_greet(args: EntryGreet) -> Next {
    let name: ResultName = args
        .inner
        .first()
        .cloned()
        .unwrap_or_else(|| "World".to_string())
        .into();
    name.into()
}

/// Chain for `desc` — looks up the metadata bound to `EntryGreet`.
#[chain]
fn handle_desc(_args: EntryDescription) -> Next {
    use mingling::ProgramCollect;
    // --------- IMPORTANT ---------
    let msg = match ThisProgram::get_metadata::<Description>(ThisProgram::EntryGreet) {
        Some(d) => format!("EntryGreet desc = {}", d.desc),
        None => "EntryGreet has no description".to_string(),
    };
    // --------- IMPORTANT ---------
    DescResult::new(msg).to_render()
}

/// Chain for `nodoc` — asks for metadata on an entry that has none.
#[chain]
fn handle_nodoc(_args: EntryNoDescription) -> Next {
    use mingling::ProgramCollect;
    // --------- IMPORTANT ---------
    let msg = match ThisProgram::get_metadata::<Description>(ThisProgram::EntryDescription) {
        Some(d) => format!("EntryDescription desc = {}", d.desc),
        None => "EntryDescription has no description".to_string(),
    };
    // --------- IMPORTANT ---------
    DescResult::new(msg).to_render()
}

/// Renders the greeting message with the provided name.
#[renderer]
fn render_name(name: ResultName) -> RenderResult {
    let mut render_result = RenderResult::new();
    writeln!(render_result, "Hello, {}!", *name).ok();
    render_result
}

/// Renders the metadata query result.
#[renderer]
fn render_desc(msg: DescResult) -> RenderResult {
    let mut render_result = RenderResult::new();
    writeln!(render_result, "{}", *msg).ok();
    render_result
}

gen_program!();