diff options
| author | Weicao-CatilGrass <1992414357@qq.com> | 2026-05-23 23:41:04 +0800 |
|---|---|---|
| committer | Weicao-CatilGrass <1992414357@qq.com> | 2026-05-23 23:49:34 +0800 |
| commit | 0a2ef958c0dca21d19e4ffc38ba5a7c4078e182a (patch) | |
| tree | c82fc4242ed393b132ba514eb434d722e7d9c387 /examples/example-custom-pickable/src/main.rs | |
| parent | ccab1940c019dfbfb7dfcbbe4cb927258933755f (diff) | |
Rework examples and add entry macro for testing
Diffstat (limited to 'examples/example-custom-pickable/src/main.rs')
| -rw-r--r-- | examples/example-custom-pickable/src/main.rs | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/examples/example-custom-pickable/src/main.rs b/examples/example-custom-pickable/src/main.rs new file mode 100644 index 0000000..466ae43 --- /dev/null +++ b/examples/example-custom-pickable/src/main.rs @@ -0,0 +1,125 @@ +//! Example Custom Pickable +//! +//! > This example demonstrates how to use the Pickable trait to add parsing for your types +//! +//! Run: +//! ```bash +//! cargo run --manifest-path examples/example-custom-pickable/Cargo.toml --quiet -- connect 127.0.0.1:5012 +//! cargo run --manifest-path examples/example-custom-pickable/Cargo.toml --quiet -- connect 127.0.0.1 +//! ``` +//! +//! Output: +//! ```plaintext +//! Connected to "127.0.0.1:5012" +//! Failed to parse address +//! ``` + +use mingling::{Groupped, macros::route, parser::Pickable, prelude::*}; + +// Define types that can be recognized by Mingling +// ________________________ `Pickable` trait needs to implement Default +// / ________ The Groupped derive macro registers an ID for this type +// | / Mingling uses this ID to identify the type +// vvvvvvv vvvvvvvv +#[derive(Debug, Default, Clone, Groupped)] +pub struct Address { + pub ip: [u8; 4], + pub port: u16, +} + +// --------- IMPORTANT --------- +impl Pickable for Address { + type Output = Address; + fn pick(args: &mut mingling::parser::Argument, flag: mingling::Flag) -> Option<Self::Output> { + // Extract the raw string from Argument using the Flag + let raw: String = args.pick_argument(flag)?.to_string(); + + // Use TryFrom to parse the address + Address::try_from(raw).ok() + } +} +// --------- IMPORTANT --------- + +dispatcher!("connect", CMDConnect => EntryConnect); +pack!(ErrorParseAddressFailed = ()); + +#[chain] +fn handle_connect(prev: EntryConnect) -> Next { + let connect: Address = + route! { prev.pick_or_route((), ErrorParseAddressFailed::default().to_chain()).unpack() }; + connect.to_chain() +} + +#[renderer] +fn render_address(addr: Address) { + r_println!("Connected to \"{}\"", addr.to_string()); +} + +#[renderer] +fn render_error_parse_address_failed(_: ErrorParseAddressFailed) { + r_println!("Failed to parse address"); +} + +gen_program!(); + +fn main() { + let mut program = ThisProgram::new(); + program.with_dispatcher(CMDConnect); + program.exec_and_exit(); +} + +// Address conversion + +impl TryFrom<String> for Address { + type Error = String; + + fn try_from(raw: String) -> Result<Self, Self::Error> { + // Expected format: "192.168.1.1:8080" + let parts: Vec<&str> = raw.split(':').collect(); + if parts.len() != 2 { + return Err("Invalid format: expected 'IP:PORT'".to_string()); + } + + let ip_str = parts[0]; + let port_str = parts[1]; + + // Parse IP address (4 octets separated by dots) + let ip_parts: Vec<&str> = ip_str.split('.').collect(); + if ip_parts.len() != 4 { + return Err("Invalid IP address format".to_string()); + } + + let mut ip = [0u8; 4]; + for (i, part) in ip_parts.iter().enumerate() { + ip[i] = part + .parse::<u8>() + .map_err(|_| format!("Invalid IP octet: {}", part))?; + } + + // Parse port + let port = port_str + .parse::<u16>() + .map_err(|_| format!("Invalid port: {}", port_str))?; + + Ok(Address { ip, port }) + } +} + +impl From<Address> for String { + fn from(addr: Address) -> String { + format!( + "{}.{}.{}.{}:{}", + addr.ip[0], addr.ip[1], addr.ip[2], addr.ip[3], addr.port + ) + } +} + +impl std::fmt::Display for Address { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}.{}.{}.{}:{}", + self.ip[0], self.ip[1], self.ip[2], self.ip[3], self.port + ) + } +} |
