aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-04-15 13:22:06 +0800
committer魏曹先生 <1992414357@qq.com>2026-04-15 13:22:06 +0800
commit6f3158896977a60c7c886c0960c8f9c0f2f0b2d9 (patch)
tree7c5569c4874cf52d31942bbd148426cbb0b898a6 /docs
parentac69d89702269436303f704f8b028dd5fe6578be (diff)
Add documentation for Dispatcher, Chain, and Renderer
Diffstat (limited to 'docs')
-rw-r--r--docs/pages/2-basic/3-dispatcher.md84
-rw-r--r--docs/pages/2-basic/4-chain.md71
-rw-r--r--docs/pages/2-basic/5-renderer.md71
3 files changed, 226 insertions, 0 deletions
diff --git a/docs/pages/2-basic/3-dispatcher.md b/docs/pages/2-basic/3-dispatcher.md
index 643a752..d0858d2 100644
--- a/docs/pages/2-basic/3-dispatcher.md
+++ b/docs/pages/2-basic/3-dispatcher.md
@@ -5,8 +5,92 @@
---
+## Intro
+`Dispatcher` is a core concept in **Mingling**, used to dispatch user-input arguments to corresponding types, which are then handled by [Chain](pages/2-basic/4-chain) or [Renderer](pages/2-basic/5-renderer).
+To define a `Dispatcher`, it is recommended to use the `dispatcher!` macro provided by `mingling_macros`:
+
+```rust
+// User input: your_bin hello
+// Will access HelloCommand and
+// dispatch arguments to HelloEntry
+dispatcher!("hello",
+ HelloCommand => HelloEntry);
+
+// User input: your_bin sub foo
+// Will access FooCommand and
+// dispatch arguments to FooEntry
+dispatcher!("sub.foo",
+ FooCommand => FooEntry);
+
+// Same as above
+dispatcher!("sub.bar",
+ BarCommand => BarEntry);
+```
+
+If you explicitly specify a name in the `gen_program!` macro, for example:
+
+```rust
+gen_program!(MyProgram);
+```
+
+Then when using the `dispatcher!` macro, you must also explicitly specify the [Program](pages/2-basic/1-program):
+
+```rust
+dispatcher!(MyProgram, "hello",
+ HelloCommand => HelloEntry);
+```
+
+**Tips:** Finally, add the `Dispatcher` you created to the [Program](pages/2-basic/1-program):
+
+```rust
+#[tokio::main]
+async fn main() {
+ let mut program = ThisProgram::new();
+ program.with_dispatcher(HelloCommand);
+ program.with_dispatcher(SubFooCommand);
+ program.with_dispatcher(SubBarCommand);
+ program.exec().await;
+}
+```
+
+## Manual Impl
+
+You can also manually implement the basic `Dispatcher` for more fine-grained control. However, compared to the procmacro, it is more cumbersome and cannot intelligently introduce certain traits based on the state of feature flags.
+
+```rust
+// Define AddMemberEntry
+// Use the `Groupped` derive to
+// mark AddMemberEntry as a member of ThisProgram
+#[derive(Debug, Groupped)]
+pub struct AddMemberEntry {
+ // Define arguments to store user input
+ pub(crate) args: Vec<String>,
+}
+
+// Implement the Dispatcher trait
+impl Dispatcher<ThisProgram> for AddMemberCommand {
+ // Return the node name of this Dispatcher
+ fn node(&self) -> Node {
+ node!("member.add")
+ }
+
+ // When executing this Dispatcher, output AddMemberEntry
+ fn begin(&self, args: Vec<String>)
+ -> ChainProcess<ThisProgram>
+ {
+ AnyOutput::new(AddMemberEntry { args }).route_chain()
+ }
+
+ // Used to implement the clone trait for this Dispatcher
+ fn clone_dispatcher(&self)
+ -> Box<dyn Dispatcher<ThisProgram>>
+ {
+ Box::new(AddMemberCommand)
+ }
+}
+```
## 💡 Next Page
> **Basic Component** - Chain [Go](./pages/2-basic/4-chain)
diff --git a/docs/pages/2-basic/4-chain.md b/docs/pages/2-basic/4-chain.md
index e9676c2..87a50f2 100644
--- a/docs/pages/2-basic/4-chain.md
+++ b/docs/pages/2-basic/4-chain.md
@@ -5,6 +5,77 @@
---
+## Intro
+
+Like `Dispatcher`, `Chain` is also a core concept in building the entire **Mingling** framework. It is used to receive a dispatch of one type and convert it into another type.
+
+```rust
+dispatcher!("hello",
+ HelloCommand => HelloEntry);
+
+// Define intermediate type ParsedHello, internally a String
+pack!(ParsedHello = String);
+
+// Define chain parse_hello (expands to ParseHello)
+// Declare conversion from HelloEntry
+#[chain]
+async fn parse_hello(prev: HelloEntry) -> NextProcess {
+ // Take the inner reference of HelloEntry
+ let args = &*prev;
+
+ // Extract the first argument, use default value "World"
+ // if it doesn't exist
+ let first = args.first().cloned().unwrap_or_else(|| "World".to_string());
+
+ // Pack the extracted argument into ParsedHello and
+ // dispatch to the next chain
+ ParsedHello::new(first).to_chain()
+}
+```
+
+> **About NextProcess**
+>
+> `NextProcess` is a marker type in **Mingling**, from `mingling::marker`.
+>
+> It serves no functional purpose other than to simplify the declaration of chain functions. After the `chain!` macro expands, `NextProcess` will be replaced with `mingling::ChainProcess<ThisProgram>`.
+
+## Manual Impl
+
+> ⚠️ WARNING
+>
+> The following content is not yet fully implemented; currently, only the `chain!` macro is allowed for implementation.
+
+You can also manually implement the basic `Chain` for finer control.
+
+However, please note that within the `chain!` macro, a `register_type!` macro is executed. This macro does not expand to any content; it only informs the `gen_program` context that this type exists.
+
+```rust
+dispatcher!("hello",
+ HelloCommand => HelloEntry);
+
+pack!(ParsedHello = String);
+
+struct ParseHello;
+impl Chain<ThisProgram> for ParseHello {
+ type Previous = HelloEntry;
+ async fn proc(prev: Self::Previous)
+ -> ChainProcess<ThisProgram>
+ {
+ let args = &*prev;
+ let first = args
+ .first()
+ .cloned()
+ .unwrap_or_else(||
+ "World".to_string()
+ );
+ ParsedHello::new(first).to_chain()
+ }
+}
+
+// Register HelloEntry to the context and
+// assign an ID for it
+register_type!(HelloEntry);
+```
## 💡 Next Page
> **Basic Component** - Renderer [Go](./pages/2-basic/5-renderer)
diff --git a/docs/pages/2-basic/5-renderer.md b/docs/pages/2-basic/5-renderer.md
index f3e09de..1f566f2 100644
--- a/docs/pages/2-basic/5-renderer.md
+++ b/docs/pages/2-basic/5-renderer.md
@@ -4,3 +4,74 @@
</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]
+async 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
+
+> ⚠️ WARNING
+>
+> The following content is not yet fully implemented; currently, only the `renderer!` macro is allowed for implementation.
+
+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_type!(ParsedHello);
+```