aboutsummaryrefslogtreecommitdiff
path: root/docs/pages/2-basic/5-renderer.md
blob: 2dc7e271b3609e2f9fefb95037ab2fe29408d99a (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
<h1 align="center">Renderer</h1>
<p align="center">
    Mingling's Basic Components
</p>

---

## Intro

`Renderer` is similar to [Chain](pages/2-basic/4-chain) in that they both handle processing for a specific type. The difference is: [Chain](pages/2-basic/4-chain) transforms the type, while `Renderer` terminates the program and prints the information of that type to the terminal.

A type can be processed by both [Chain](pages/2-basic/4-chain) and `Renderer`. If the type is `route_chain`ed, the system will search for a [Chain](pages/2-basic/4-chain) capable of handling that type. If none is found, it will automatically be routed to the `Renderer` to print the result of that type.

The following example demonstrates how to handle rendering logic:

```rust
dispatcher!("hello",
    HelloCommand => HelloEntry);

pack!(ParsedHello = String);

// It's the Chain defined in the Dispatcher chapter
#[chain]
fn parse_hello(prev: HelloEntry) -> NextProcess {
    let args = &*prev;
    let first = args
        .first()
        .cloned()
        .unwrap_or_else(|| 
            "World".to_string()
        );

    // Distribute the type to the Renderer
    ParsedHello::new(first).to_render()
}

// Define the renderer to 
//   handle rendering of ParsedHello
#[renderer]
fn render_hello(prev: ParsedHello) {
    // Use r_println or r_print to 
    //   render the content of ParsedHello
    r_println!("Hello, {}!", *prev)
}
```

> **About r_print**
>
> `r_print!` can only be used inside a `Renderer`. This is because after the `renderer!` macro expands, it injects `r: &mut RenderResult` into the context.
>
> And `r_print!` directly writes content to the value `r`.
> This means: if there is no `&mut RenderResult` named `r` in the context, `r_print!` cannot be used.

## Manual Impl

Similarly, you can also manually implement `Renderer`,

but note that inside the `renderer!` macro, a `register_type!` macro is executed. This macro itself does not expand into any content; it is only used to inform the `gen_program` context that the type exists:

```rust
struct RenderHello;
impl Renderer for RenderHello {
    type Previous = ParsedHello;
    fn render(
        prev: Self::Previous, 
        r: &mut RenderResult
    ) {
        r_println!("Hello, {}!", *prev)
    }
}
 
// Register renderer to the context
register_renderer!(ParsedHello, RenderHello);
```