diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-08-17 05:49:19 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-08-17 05:49:19 +0800 |
| commit | 57c53affe3542cb6bd4e79ee4c18f20a1bd76b2d (patch) | |
| tree | 1cd4aef44cb7a45a8cd9d520b598f5f181e24c76 /docs/pages/3-define-a-chain.md | |
| parent | ef23cd944402939605c78a4a853ef6e33af02c21 (diff) | |
refactor!: replace pack! macros with derive-based pipeline types
Remove the `pack!`, `pack_err!`, `pack_structural!`, and
`pack_err_structural!` macros, replacing all pipeline type definitions
with `#[derive(Grouped)]` and `#[derive(Grouped, Wrap)]` attributes.
This changes the generated struct shape from named-field structs with an
`inner` field to tuple structs accessed via `.0`, and removes the
auto-generated `name` and `info` fields from error types.
Diffstat (limited to 'docs/pages/3-define-a-chain.md')
| -rw-r--r-- | docs/pages/3-define-a-chain.md | 54 |
1 files changed, 35 insertions, 19 deletions
diff --git a/docs/pages/3-define-a-chain.md b/docs/pages/3-define-a-chain.md index 72ade94..ea39f6b 100644 --- a/docs/pages/3-define-a-chain.md +++ b/docs/pages/3-define-a-chain.md @@ -17,14 +17,15 @@ We need a Chain to process it. ```rust @@@dispatcher!("greet", EntryGreet); -pack!(ResultName = String); +#[derive(Grouped, Wrap)] +pub struct ResultName(String); #[chain] fn handle_greet(args: EntryGreet) -> Next { // args contains the remaining params after matching user input - let name = args.inner.first().cloned().unwrap_or_else(|| "World".to_string()); + let name = args.0.first().cloned().unwrap_or_else(|| "World".to_string()); // Wrap the result into Next, telling the dispatcher where to go next - ResultName::new(name).into() + ResultName(name).into() } ``` @@ -32,7 +33,7 @@ Notice anything? The Chain function signature declares what it needs — `args: EntryGreet`. -Then it returns a newtype via `ResultName::new(name)`. +Then it returns a newtype via `ResultName(name)`. This returned `Next` expands into `impl Into<ChainProcess<ThisProgram>>`. @@ -41,17 +42,30 @@ This returned `Next` expands into `impl Into<ChainProcess<ThisProgram>>`. > > Check out the [Any Output Mechanism](pages/concepts/3-any-output) chapter to learn about `ChainProcess`. -## The `pack!` Macro +## Declaring Types with `#[derive(Grouped, Wrap)]` -You've probably guessed it — `pack!(ResultName = String)` defines a type that flows through the pipeline: +You've probably guessed it — `#[derive(Grouped, Wrap)] pub struct ResultName(String);` defines a type that flows through the pipeline: ```rust -// pack!(ResultName = String) generates code roughly like this +// #[derive(Grouped, Wrap)] generates code roughly like this -#[derive(Grouped)] -pub struct ResultName { - pub inner: String, +pub struct ResultName(String); + +impl From<String> for ResultName { + fn from(inner: String) -> Self { + ResultName(inner) + } +} + +impl std::ops::Deref for ResultName { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.0 + } } + +// Grouped generates member_id() → ThisProgram::ResultName, +// giving the type its routing identity and Into<ChainProcess> conversion. ``` Think of it as a **tagged** `String`. @@ -59,7 +73,7 @@ Think of it as a **tagged** `String`. The dispatcher uses this tag for precise routing, ensuring data doesn't get mixed up — e.g., data sent to `RenderGreet` won't be misdelivered to `RenderError`. > [!NOTE] -> Unlike a simple type alias (`type`), `pack!` generates a completely new type with its own `TypeId`. +> Unlike a simple type alias (`type`), `#[derive(Grouped, Wrap)]` declares a completely new type with its own `TypeId`. Here's a recommended naming convention: @@ -70,25 +84,26 @@ Here's a recommended naming convention: | Result | `Result` + description | `ResultGreetSomeone` | | Error | `Error` + description | `ErrorUserNotFound` | -See [Naming Convention](pages/other/naming_rule) for details, but for now just remember: **use `pack!` to give your data a meaningful name**. +See [Naming Convention](pages/other/naming_rule) for details, but for now just remember: **use `#[derive(Grouped)]` (optionally with `Wrap`) to give your data a meaningful name**. ## Extracting Params from Entry -`EntryGreet`'s `inner` is a `Vec<String>`, which you can freely process inside a Chain: +`EntryGreet`'s `.0` is a `Vec<String>`, which you can freely process inside a Chain: ```rust @@@dispatcher!("greet", EntryGreet); -@@@pack!(ResultName = String); +@@@#[derive(Grouped, Wrap)] +@@@pub struct ResultName(String); #[chain] fn handle_greet(args: EntryGreet) -> Next { // Take the first param, or use a default let name = args - .inner + .0 .first() .cloned() .unwrap_or_else(|| "World".to_string()); - ResultName::new(name).into() + ResultName(name).into() } ``` @@ -103,16 +118,17 @@ Now let's connect the Dispatcher and Chain: dispatcher!("greet", EntryGreet); // 2. Declare the pipeline data type -pack!(ResultName = String); +#[derive(Grouped, Wrap)] +pub struct ResultName(String); // 3. Processing logic #[chain] fn handle_greet(args: EntryGreet) -> Next { - let name = args.inner + let name = args.0 .first() .cloned() .unwrap_or_else(|| "World".to_string()); - ResultName::new(name).into() + ResultName(name).into() } fn main() { |
