aboutsummaryrefslogtreecommitdiff
path: root/docs/pages/2-implementing-fallbacks.md
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-05-02 00:52:41 +0800
committer魏曹先生 <1992414357@qq.com>2026-05-02 00:52:41 +0800
commitf31347533c2b13f58eeae29ffc3910ca5e2f04d5 (patch)
treedb5770b67071749a44aa4b33baca5bbc6a29ee80 /docs/pages/2-implementing-fallbacks.md
parent1140b9cd48c19d02392ab7df415a3d35c3eaf1bc (diff)
Add documentation for fallback mechanisms
Diffstat (limited to 'docs/pages/2-implementing-fallbacks.md')
-rw-r--r--docs/pages/2-implementing-fallbacks.md139
1 files changed, 139 insertions, 0 deletions
diff --git a/docs/pages/2-implementing-fallbacks.md b/docs/pages/2-implementing-fallbacks.md
new file mode 100644
index 0000000..a376580
--- /dev/null
+++ b/docs/pages/2-implementing-fallbacks.md
@@ -0,0 +1,139 @@
+<h1 align="center">Implementing Fallbacks</h1>
+<p align="center">
+ Handling error cases in your program using a fallback mechanism
+</p>
+
+## Recap
+
+ In the last post, we introduced how to develop a basic CLI program using **Mingling**: you can use the `"greet"` subcommand to output `"Hello, World!"`, or use `"greet Alice"` to output `"Hello, Alice!"`
+
+ But what happens when the user does not enter `"greet"`? Let's type a command and find out ⌨️
+
+```bash
+~> your-bin hello
+~> your-bin hello Alice
+```
+
+ **It does nothing!** 👆
+
+ Let me explain why: **Mingling** doesn't presume to act; it will not output anything to the terminal no matter what happens (except for `panic!` under `unwind`)
+
+ This means that if you need to actively do something when your CLI program encounters an error, you have to state it explicitly.
+
+ Fortunately, **Mingling** provides a convenient interface for this functionality: inside the `gen_program!` macro, two `FallBack` types are generated
+
+|Type|When it occurs|How it occurs|
+|-|-|-|
+|RendererNotFound|When a renderer cannot be found for scheduling|Scheduled as a `Chain`|
+|DispatcherNotFound|When a command is entered but no dispatcher matches|Scheduled as a `Chain`|
+
+### The `DispatcherNotFound` Type
+
+ Let's first focus on the `DispatcherNotFound` type. It is produced as follows:
+
+```rust
+// 1. Define the `greet` command
+dispatcher!("greet", GreetCommand => GreetEntry);
+
+fn main() {
+ // ->> User enters "hello Alice"
+ let mut program = ThisProgram::new();
+
+ // 2. Import the `greet` command
+ program.with_dispatcher(GreetCommand);
+
+ // 3. Execute the program
+ program.exec();
+}
+
+// ...
+
+// 5. Receive the DispatcherNotFound dispatch
+#[renderer]
+fn dispatcher_not_found(prev: DispatcherNotFound) {
+ // 6. Output
+ r_println!(
+ "Cannot match any command! Current input: \"{}\"",
+ prev.join(" ")
+ );
+}
+
+// 4. Cannot match any dispatcher named `hello`
+// Forward the user's arguments as-is to DispatcherNotFound
+gen_program!();
+```
+
+ The output of the above program is:
+
+```bash
+~> omg hello
+Cannot match any command! Current input: "hello"
+
+~> omg hello Alice
+Cannot match any command! Current input: "hello Alice"
+```
+
+ Now, if the user enters a command that doesn't match, **Mingling** will output the appropriate message!
+
+## The `RendererNotFound` Type
+
+ `RendererNotFound` can be produced in two ways:
+
+ 1. The type was explicitly dispatched to a `Renderer` (using the `.to_render()` function), but the type does not have a renderer implementation
+ 2. The type was dispatched to a `Chain`, but the type has neither a chain nor a renderer implementation
+
+ Generally, `RendererNotFound` **should not occur in business logic**: its dispatch means your type needs to be rendered but can't be. You can use this type to pinpoint which type is missing a renderer implementation ✏️
+
+```rust
+dispatcher!("greet", GreetCommand => GreetEntry);
+
+fn main() {
+ let mut program = ThisProgram::new();
+
+ program.with_dispatcher(GreetCommand);
+ program.exec();
+}
+
+pack!(ResultGreetSomeone = String);
+
+#[chain]
+fn handle_greet_entry(prev: GreetEntry) -> NextProcess {
+ let args = prev.inner;
+ let name = args.first().cloned().unwrap_or_else(|| "World".to_string());
+
+ ResultGreetSomeone::new(name)
+}
+
+// Let's intentionally remove the renderer implementation for `ResultGreetSomeone`
+// #[renderer]
+// fn render_greet_someone(prev: ResultGreetSomeone) {
+// r_println!("Hello, {}!", *prev);
+// }
+
+#[renderer]
+fn renderer_not_found(prev: RendererNotFound) {
+ if *prev == "DispatcherNotFound" {
+ return; // Exclude the "DispatcherNotFound" type
+ }
+
+ // Trigger `panic!` when a renderer is not found
+ panic!("Renderer \"{}\" not found!", *prev);
+}
+
+gen_program!();
+
+```
+
+ The output of the above program is:
+
+```bash
+~> your-bin greet Alice
+
+thread 'main' (90772) panicked at src/bin/your-bin.rs:30:5:
+Renderer "ResultGreetSomeone" not found!
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+```
+
+<p align="center" style="font-size: 0.85em; color: gray;">
+ Written by @Weicao-CatilGrass
+</p>