From 85ee549f68449bc70a7f1271a93ad26a8207ee40 Mon Sep 17 00:00:00 2001
From: 魏曹先生 <1992414357@qq.com>
Date: Tue, 28 Apr 2026 22:39:59 +0800
Subject: Rebuild and rewrite the documentation site infrastructure
---
docs/pages/3-features/1-parser.md | 376 --------------------------------------
1 file changed, 376 deletions(-)
delete mode 100644 docs/pages/3-features/1-parser.md
(limited to 'docs/pages/3-features/1-parser.md')
diff --git a/docs/pages/3-features/1-parser.md b/docs/pages/3-features/1-parser.md
deleted file mode 100644
index 0b5ded5..0000000
--- a/docs/pages/3-features/1-parser.md
+++ /dev/null
@@ -1,376 +0,0 @@
-
Parser
-
- Mingling's Features
-
-
----
-
-## Enable Feature
-
-`parser` is a feature provided by **Mingling**. You can enable it in the following way:
-
-```toml
-[dependencies]
-mingling = {
- version = "...",
- features = ["parser"]
-}
-```
-
-## Usage
-
-`parser` provides the ability to transform user input into structured data. Its core concept is **pick**.
-
-The following demonstrates the parsing approach without using a `Picker`:
-
-```rust
-#[chain]
-fn parse_hello(prev: HelloEntry) -> NextProcess {
- let args = &*prev;
- let first = args.first().cloned().unwrap_or_else(|| "World".to_string());
- ParsedHello::new(first).to_render()
-}
-```
-
-This is how it looks when using `Picker`:
-
-```rust
-#[chain]
-fn parse_hello(prev: HelloEntry) -> NextProcess {
- // Create Picker
- let picker = Picker::::new(prev.inner);
-
- // Extract the first argument from the Picker,
- // fallback to "World" if it doesn't exist
- let first = picker
- .pick_or((), "World")
- .unpack_directly();
-
- ParsedHello::new(first).to_render()
-}
-```
-
-You might notice that using `Picker` can sometimes make statements more verbose, but this is only when parsing a small number of arguments. What if we complicate the scenario?
-
-Suppose we want to design the following commands:
-
-```bash
-# Eat 1 apple weighing at least 20
-fruit eat Apple --min-weight 20
-
-# Eat 10 apples weighing at least 20
-fruit eat Apple --min-weight 20 --count 10
-
-# Eat 1 apple weighing between 10 and 20
-fruit eat Apple --min-weight 10 --max-weight 20
-
-# Eat 1 apple weighing between 20 and 10 (incorrect logic)
-fruit eat Apple --min-weight 20 --max-weight 10
-
-# When no specific fruit is specified, eat banana
-fruit eat --count 5
-```
-
-For this complex scenario, the `Picker` comes into play!
-
-We first design the type `ParsedEatFruit`
-
-```rust
-#[derive(Debug, Default, Groupped)]
-struct ParsedEatFruit {
- count: i16,
- weight_range: (i16, i16),
- fruit_type: Fruit,
-}
-
-#[derive(Debug, Default, EnumTag)]
-enum Fruit {
- #[default]
- Banana,
- Apple,
- Orange,
-}
-```
-
-Then create the basic binary program `fruit`
-
-```rust
-use mingling::{
- EnumTag, Groupped,
- macros::{chain, dispatcher, gen_program, r_println, renderer},
- parser::PickableEnum,
-};
-
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(FruitEatCommand);
- program.exec();
-}
-
-dispatcher!("eat",
- FruitEatCommand => FruitEatEntry);
-
-#[derive(Debug, Default, Groupped)]
-struct ParsedEatFruit {
- count: i16,
- weight_range: (i16, i16),
- fruit_type: Fruit,
-}
-
-#[derive(Debug, Default, EnumTag)]
-enum Fruit {
- #[default]
- Banana,
- Apple,
- Orange,
-}
-
-// Implement PickableEnum for Fruit to make it pickable
-impl PickableEnum for Fruit {}
-
-#[chain]
-fn parse_fruit_eat(prev: FruitEatEntry) -> NextProcess {
- // ...
-}
-
-#[renderer]
-fn render_fruit_eat(prev: ParsedEatFruit) {
- let weight_str = match prev.weight_range {
- (min, max) if min == 0 && max > 0 => {
- format!("up to {}.", max)
- }
- (min, max) if min > 0 && max == 0 => {
- format!("at least {}.", min)
- }
- (min, max) if min > 0 && max > 0 && min != max => {
- format!("between {} and {}.", min, max)
- }
- (min, max) if min > 0 && max > 0 && min == max => {
- format!("exactly {}.", min)
- }
- _ => "unknown.".to_string(),
- };
-
- let fruit_type = if prev.count > 1 {
- format!("{}s", prev.fruit_type.enum_info().0)
- } else {
- prev.fruit_type.enum_info().0.to_string()
- };
-
- r_println!(
- "I ate {} {}, each weighing {}",
- prev.count,
- fruit_type,
- weight_str
- );
-}
-
-gen_program!();
-```
-
-Now focus on writing the logic for `parse_fruit_eat`:
-
-> Review the business logic:
->
-> 1 - The default fruit is Banana
->
-> 2 - The default quantity is 1
->
-> 3 - The default weight is (0, 0)
->
-> 4 - When `max-weight` is less than `min-weight`, the business logic is in error
-
-Before writing the code, define the error type `MinGreaterThanMax` and the related `Renderer`
-
-```rust
-pack!(MinGreaterThanMax = ());
-
-#[renderer]
-fn render_min_greater_than_max(_prev: MinGreaterThanMax) {
- r_println!("Error: min weight cannot be greater than max weight.");
-}
-```
-
-Now start writing the logic:
-
-```rust
-#[chain]
-fn parse_fruit_eat(prev: FruitEatEntry) -> NextProcess {
- let picker = Picker::new(prev.inner);
- let mut min_weight: i16 = 0;
- let parsed = picker
- .pick_or(["--count", "-n"], 1)
- .pick::("--min-weight") // default: 0
- .after(|min| {
- // Copy `min` to external variable
- min_weight = min;
- min
- })
- .pick_or::("--max-weight", min_weight) // default: min_weight
- .after_or_route(|max| {
- // Check if `max` is valid
- if max < &min_weight {
- Err(MinGreaterThanMax::default())
- } else {
- Ok(max.clone())
- }
- })
- .pick(())
- // Since there's a possibility of being routed,
- // don't use `unpack_directly`
- .unpack();
-
- match parsed {
- Ok((count, min_weight, max_weight, fruit_type)) => {
- let parsed = ParsedEatFruit {
- count,
- weight_range: (min_weight, max_weight),
- fruit_type,
- };
-
- AnyOutput::new(parsed).route_renderer()
- }
- Err(route) => route.to_render(),
- }
-}
-```
-
-Complete code:
-
-```rust
-use mingling::{
- AnyOutput, EnumTag, Groupped,
- macros::{chain, dispatcher, gen_program, pack, r_println, renderer},
- parser::{PickableEnum, Picker},
-};
-
-fn main() {
- let mut program = ThisProgram::new();
- program.with_dispatcher(FruitEatCommand);
- program.exec();
-}
-
-dispatcher!("eat",
- FruitEatCommand => FruitEatEntry);
-
-#[derive(Debug, Default, Groupped)]
-struct ParsedEatFruit {
- count: i16,
- weight_range: (i16, i16),
- fruit_type: Fruit,
-}
-
-#[derive(Debug, Default, EnumTag)]
-enum Fruit {
- #[default]
- Banana,
- Apple,
- Orange,
-}
-
-impl PickableEnum for Fruit {}
-
-pack!(MinGreaterThanMax = ());
-
-#[chain]
-fn parse_fruit_eat(prev: FruitEatEntry) -> NextProcess {
- let picker = Picker::new(prev.inner);
- let mut min_weight: i16 = 0;
- let (count, min_weight, max_weight, fruit_type) = route! {
- picker
- // Pick count
- .pick_or::(["--count", "-n"], 1 as i16)
-
- // Pick min/max weight
- .pick::("--min-weight")
- .after(|min| {
- min_weight = min;
- min
- })
-
- .pick_or::("--max-weight", min_weight)
- .after_or_route(|max| {
- if max < &min_weight {
- Err(MinGreaterThanMax::default().to_render())
- } else {
- Ok(max.clone())
- }
- })
-
- // Pick Type
- .pick(())
- .unpack()
- };
-
- ParsedEatFruit {
- count,
- weight_range: (min_weight, max_weight),
- fruit_type,
- }
- .to_render()
-}
-
-#[renderer]
-fn render_min_greater_than_max(_prev: MinGreaterThanMax) {
- r_println!("Error: min weight cannot be greater than max weight.");
-}
-
-#[renderer]
-fn render_fruit_eat(prev: ParsedEatFruit) {
- let weight_str = match prev.weight_range {
- (min, max) if min == 0 && max > 0 => {
- format!("up to {}.", max)
- }
- (min, max) if min > 0 && max == 0 => {
- format!("at least {}.", min)
- }
- (min, max) if min > 0 && max > 0 && min != max => {
- format!("between {} and {}.", min, max)
- }
- (min, max) if min > 0 && max > 0 && min == max => {
- format!("exactly {}.", min)
- }
- _ => "unknown.".to_string(),
- };
-
- let fruit_type = if prev.count > 1 {
- format!("{}s", prev.fruit_type.enum_info().0)
- } else {
- prev.fruit_type.enum_info().0.to_string()
- };
-
- r_println!(
- "I ate {} {}, each weighing {}",
- prev.count,
- fruit_type,
- weight_str
- );
-}
-
-gen_program!();
-```
-
-Now compile the program and run it:
-
-```bash
-cargo install --path ./
-```
-
-Running results:
-
-```bash
-~> fruit eat Apple --min-weight 20
-I ate 1 Apple, each weighing exactly 20.
-
-~> fruit eat Apple --min-weight 20 --count 10
-I ate 10 Apples, each weighing exactly 20.
-
-~> fruit eat Apple --min-weight 10 --max-weight 20
-I ate 1 Apple, each weighing between 10 and 20.
-
-~> fruit eat Apple --min-weight 20 --max-weight 10
-Error: min weight cannot be greater than max weight.
-
-~> fruit eat --count 5
-I ate 5 Bananas, each weighing unknown.
-```
--
cgit