diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-07-15 16:08:10 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-07-15 16:08:10 +0800 |
| commit | c3e990a5c47dc8894899d774a0d89f089adec308 (patch) | |
| tree | 85e8bdc834cc57bf41694f4c86e5bfd3386fcd09 | |
| parent | 7620fd1d1e9ff4105c2d93c80c73b2c2ec1cbc9a (diff) | |
refactor: rename `PickerResult` to `PickerArgResult` and add new
`PickerResult` struct
| -rw-r--r-- | mingling_picker/src/infos.rs | 144 | ||||
| -rw-r--r-- | mingling_picker/src/pickable.rs | 6 | ||||
| -rw-r--r-- | mingling_picker/src/pickable/implements.rs | 4 | ||||
| -rw-r--r-- | mingling_picker/src/picker.rs | 7 | ||||
| -rw-r--r-- | mingling_picker/src/picker/patterns.rs | 29 | ||||
| -rw-r--r-- | mingling_picker/src/picker/result.rs | 54 |
6 files changed, 161 insertions, 83 deletions
diff --git a/mingling_picker/src/infos.rs b/mingling_picker/src/infos.rs index ce9d198..95a54da 100644 --- a/mingling_picker/src/infos.rs +++ b/mingling_picker/src/infos.rs @@ -3,12 +3,12 @@ use crate::{Pickable, PickerFlag}; /// Represents the result of parsing or looking up a value. /// /// This enum is generic over the type being parsed. It models four possible outcomes: -/// - [`Unparsed`](PickerResult::Unparsed): The value has not yet been parsed (default). -/// - [`Parsed`](PickerResult::Parsed): The value was successfully parsed into `Type`. -/// - [`NotFound`](PickerResult::NotFound): The requested value could not be found. -/// - [`ParseError`](PickerResult::ParseError): The input could not be parsed due to a format error. +/// - [`Unparsed`](PickerArgResult::Unparsed): The value has not yet been parsed (default). +/// - [`Parsed`](PickerArgResult::Parsed): The value was successfully parsed into `Type`. +/// - [`NotFound`](PickerArgResult::NotFound): The requested value could not be found. +/// - [`ParseError`](PickerArgResult::ParseError): The input could not be parsed due to a format error. #[derive(Default)] -pub enum PickerResult<Type> { +pub enum PickerArgResult<Type> { /// The value has not yet been parsed (default). #[default] Unparsed, @@ -23,216 +23,216 @@ pub enum PickerResult<Type> { ParseError, } -impl<Type, E> From<Result<Type, E>> for PickerResult<Type> { - /// Converts a `Result<Type, E>` into a `PickerResult<Type>`. +impl<Type, E> From<Result<Type, E>> for PickerArgResult<Type> { + /// Converts a `Result<Type, E>` into a `PickerArgResult<Type>`. /// - /// - `Ok(value)` maps to [`Parsed(value)`](PickerResult::Parsed). - /// - `Err(_)` maps to [`ParseError`](PickerResult::ParseError). + /// - `Ok(value)` maps to [`Parsed(value)`](PickerArgResult::Parsed). + /// - `Err(_)` maps to [`ParseError`](PickerArgResult::ParseError). fn from(result: Result<Type, E>) -> Self { match result { - Ok(value) => PickerResult::Parsed(value), - Err(_) => PickerResult::ParseError, + Ok(value) => PickerArgResult::Parsed(value), + Err(_) => PickerArgResult::ParseError, } } } -impl<Type> From<Option<Type>> for PickerResult<Type> { - /// Converts an `Option<Type>` into a `PickerResult<Type>`. +impl<Type> From<Option<Type>> for PickerArgResult<Type> { + /// Converts an `Option<Type>` into a `PickerArgResult<Type>`. /// - /// - `Some(value)` maps to [`Parsed(value)`](PickerResult::Parsed). - /// - `None` maps to [`NotFound`](PickerResult::NotFound). + /// - `Some(value)` maps to [`Parsed(value)`](PickerArgResult::Parsed). + /// - `None` maps to [`NotFound`](PickerArgResult::NotFound). fn from(option: Option<Type>) -> Self { match option { - Some(value) => PickerResult::Parsed(value), - None => PickerResult::NotFound, + Some(value) => PickerArgResult::Parsed(value), + None => PickerArgResult::NotFound, } } } -impl<Type> PickerResult<Type> { - /// Returns `true` if the result is [`Parsed`](PickerResult::Parsed). +impl<Type> PickerArgResult<Type> { + /// Returns `true` if the result is [`Parsed`](PickerArgResult::Parsed). /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::Parsed(42); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42); /// assert!(result.is_parsed()); /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert!(!result.is_parsed()); /// ``` pub fn is_parsed(&self) -> bool { - matches!(self, PickerResult::Parsed(_)) + matches!(self, PickerArgResult::Parsed(_)) } - /// Returns `true` if the result is [`Parsed`](PickerResult::Parsed) or [`NotFound`](PickerResult::NotFound). + /// Returns `true` if the result is [`Parsed`](PickerArgResult::Parsed) or [`NotFound`](PickerArgResult::NotFound). /// i.e., the value exists (was either found or not yet parsed, but not a parse error). /// Typically indicates the value was "found" in some sense. /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::Parsed(42); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42); /// assert!(result.is_found()); /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert!(result.is_found()); /// - /// let result: PickerResult<i32> = PickerResult::ParseError; + /// let result: PickerArgResult<i32> = PickerArgResult::ParseError; /// assert!(!result.is_found()); /// ``` pub fn is_found(&self) -> bool { - matches!(self, PickerResult::Parsed(_) | PickerResult::NotFound) + matches!(self, PickerArgResult::Parsed(_) | PickerArgResult::NotFound) } - /// Returns `true` if the result is [`ParseError`](PickerResult::ParseError). + /// Returns `true` if the result is [`ParseError`](PickerArgResult::ParseError). /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::ParseError; + /// let result: PickerArgResult<i32> = PickerArgResult::ParseError; /// assert!(result.is_err()); /// - /// let result: PickerResult<i32> = PickerResult::Parsed(10); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(10); /// assert!(!result.is_err()); /// ``` pub fn is_err(&self) -> bool { - matches!(self, PickerResult::ParseError) + matches!(self, PickerArgResult::ParseError) } - /// Returns `Some(&Type)` if [`Parsed`](PickerResult::Parsed), otherwise `None`. + /// Returns `Some(&Type)` if [`Parsed`](PickerArgResult::Parsed), otherwise `None`. /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::Parsed(42); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42); /// assert_eq!(result.parsed(), Some(&42)); /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert_eq!(result.parsed(), None); /// ``` pub fn parsed(&self) -> Option<&Type> { - if let PickerResult::Parsed(value) = self { + if let PickerArgResult::Parsed(value) = self { Some(value) } else { None } } - /// Returns the contained [`Parsed`](PickerResult::Parsed) value or panics with a given message. + /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or panics with a given message. /// /// # Panics - /// Panics if the value is not [`Parsed`](PickerResult::Parsed), with a message including the provided `msg`. + /// Panics if the value is not [`Parsed`](PickerArgResult::Parsed), with a message including the provided `msg`. /// /// # Examples /// /// ```should_panic - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// result.expect("expected a parsed value"); /// ``` pub fn expect(self, msg: &str) -> Type { match self { - PickerResult::Parsed(value) => value, + PickerArgResult::Parsed(value) => value, _ => panic!("{}", msg), } } - /// Returns the contained [`Parsed`](PickerResult::Parsed) value or panics. + /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or panics. /// /// # Panics - /// Panics if the value is not [`Parsed`](PickerResult::Parsed). + /// Panics if the value is not [`Parsed`](PickerArgResult::Parsed). /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::Parsed(42); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42); /// assert_eq!(result.unwrap(), 42); /// ``` /// /// ```should_panic - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// result.unwrap(); /// ``` pub fn unwrap(self) -> Type { match self { - PickerResult::Parsed(value) => value, - PickerResult::Unparsed => { - panic!("called `PickerResult::unwrap()` on an `Unparsed` value") + PickerArgResult::Parsed(value) => value, + PickerArgResult::Unparsed => { + panic!("called `PickerArgResult::unwrap()` on an `Unparsed` value") } - PickerResult::NotFound => { - panic!("called `PickerResult::unwrap()` on a `NotFound` value") + PickerArgResult::NotFound => { + panic!("called `PickerArgResult::unwrap()` on a `NotFound` value") } - PickerResult::ParseError => { - panic!("called `PickerResult::unwrap()` on a `ParseError` value") + PickerArgResult::ParseError => { + panic!("called `PickerArgResult::unwrap()` on a `ParseError` value") } } } - /// Returns the contained [`Parsed`](PickerResult::Parsed) value or a provided `default`. + /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or a provided `default`. /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::Parsed(42); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42); /// assert_eq!(result.unwrap_or(0), 42); /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert_eq!(result.unwrap_or(0), 0); /// ``` pub fn unwrap_or(self, default: Type) -> Type { match self { - PickerResult::Parsed(value) => value, + PickerArgResult::Parsed(value) => value, _ => default, } } - /// Returns the contained [`Parsed`](PickerResult::Parsed) value or computes it from a closure. + /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or computes it from a closure. /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::Parsed(42); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42); /// assert_eq!(result.unwrap_or_else(|| 0), 42); /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert_eq!(result.unwrap_or_else(|| 0), 0); /// ``` pub fn unwrap_or_else<F: FnOnce() -> Type>(self, f: F) -> Type { match self { - PickerResult::Parsed(value) => value, + PickerArgResult::Parsed(value) => value, _ => f(), } } - /// Returns the contained [`Parsed`](PickerResult::Parsed) value or the default value of `Type`. + /// Returns the contained [`Parsed`](PickerArgResult::Parsed) value or the default value of `Type`. /// /// # Examples /// /// ``` - /// use mingling_picker::PickerResult; + /// use mingling_picker::PickerArgResult; /// - /// let result: PickerResult<i32> = PickerResult::Parsed(42); + /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42); /// assert_eq!(result.unwrap_or_default(), 42); /// - /// let result: PickerResult<i32> = PickerResult::NotFound; + /// let result: PickerArgResult<i32> = PickerArgResult::NotFound; /// assert_eq!(result.unwrap_or_default(), 0); /// ``` pub fn unwrap_or_default(self) -> Type @@ -240,7 +240,7 @@ impl<Type> PickerResult<Type> { Type: Default, { match self { - PickerResult::Parsed(value) => value, + PickerArgResult::Parsed(value) => value, _ => Type::default(), } } diff --git a/mingling_picker/src/pickable.rs b/mingling_picker/src/pickable.rs index 8bb012a..808830c 100644 --- a/mingling_picker/src/pickable.rs +++ b/mingling_picker/src/pickable.rs @@ -1,4 +1,4 @@ -use crate::{PickerArgInfo, PickerArgs, PickerFlag, PickerFlagAttr, PickerResult}; +use crate::{PickerArgInfo, PickerArgResult, PickerArgs, PickerFlag, PickerFlagAttr}; mod implements; @@ -64,9 +64,9 @@ where /// /// # Returns /// - /// Returns [`PickerResult<Self>`], i.e., the `Self` instance on success, or an appropriate + /// Returns [`PickerArgResult<Self>`], i.e., the `Self` instance on success, or an appropriate /// error message on failure. - fn pick(raw_strs: &[&str]) -> PickerResult<Self>; + fn pick(raw_strs: &[&str]) -> PickerArgResult<Self>; } /// Tag phase context, providing the necessary argument and state information for diff --git a/mingling_picker/src/pickable/implements.rs b/mingling_picker/src/pickable/implements.rs index cbf22c8..7d19a8c 100644 --- a/mingling_picker/src/pickable/implements.rs +++ b/mingling_picker/src/pickable/implements.rs @@ -9,7 +9,7 @@ impl<'a> Pickable<'a> for String { vec![] } - fn pick(_raw_strs: &[&str]) -> crate::PickerResult<Self> { + fn pick(_raw_strs: &[&str]) -> crate::PickerArgResult<Self> { todo!() } } @@ -23,7 +23,7 @@ impl<'a> Pickable<'a> for Vec<String> { vec![] } - fn pick(_raw_strs: &[&str]) -> crate::PickerResult<Self> { + fn pick(_raw_strs: &[&str]) -> crate::PickerArgResult<Self> { todo!() } } diff --git a/mingling_picker/src/picker.rs b/mingling_picker/src/picker.rs index 99ab2a9..246e013 100644 --- a/mingling_picker/src/picker.rs +++ b/mingling_picker/src/picker.rs @@ -5,7 +5,10 @@ mod parse; mod patterns; pub use patterns::*; -use crate::{Pickable, PickerFlag, PickerResult}; +mod result; +pub use result::*; + +use crate::{Pickable, PickerArgResult, PickerFlag}; /// Picker, used to record all states of a parameter parsing /// @@ -248,7 +251,7 @@ pub trait IntoPicker<'a> { PickerPattern1 { args: self.to_picker().args, flag_1: flag, - result_1: PickerResult::Unparsed, + result_1: PickerArgResult::Unparsed, default_1: None, post_1: None, } diff --git a/mingling_picker/src/picker/patterns.rs b/mingling_picker/src/picker/patterns.rs index 4f54f9d..b828849 100644 --- a/mingling_picker/src/picker/patterns.rs +++ b/mingling_picker/src/picker/patterns.rs @@ -1,6 +1,6 @@ use mingling_picker_macros::internal_repeat; -use crate::{Pickable, Picker, PickerArgs, PickerFlag, PickerResult}; +use crate::{Pickable, Picker, PickerArgResult, PickerArgs, PickerFlag}; internal_repeat!(1..=32 => { #[doc(hidden)] @@ -10,7 +10,7 @@ internal_repeat!(1..=32 => { pub args: PickerArgs<'a>, ( pub flag_$: &'a PickerFlag<'a, T$>, - pub result_$: PickerResult<T$>, + pub result_$: PickerArgResult<T$>, pub default_$: Option<Box<dyn FnOnce() -> T$>>, pub post_$: Option<Box<dyn FnOnce(T$) -> T$>>, +) @@ -43,6 +43,27 @@ internal_repeat!(1..=32 => { self } + /// Uses the default value for this flag's type if the flag is not provided. + /// + /// If the flag is not provided by the user at runtime, the default value for `T$` + /// (as defined by the `Default` trait) will be used. + /// + /// # Example + /// + /// ```ignore + /// let pattern = picker + /// .pick(&my_flag) + /// .or_default(); + /// ``` + #[allow(clippy::type_complexity)] + pub fn or_default(mut self) -> Self + where + T$: Default, + { + self.default_$ = Some(Box::new(|| T$::default())); + self + } + /// Attaches a post-processing function to this flag. /// /// After the flag's value is parsed (or defaulted), the given closure will be @@ -88,7 +109,7 @@ internal_repeat!(1..32 => { // Current flag_$+: flag, - result_$+: PickerResult::Unparsed, + result_$+: PickerArgResult::Unparsed, default_$+: None, post_$+: None, @@ -116,7 +137,7 @@ impl<'a> Picker<'a> { PickerPattern1 { args: self.args, flag_1: flag, - result_1: PickerResult::Unparsed, + result_1: PickerArgResult::Unparsed, default_1: None, post_1: None, } diff --git a/mingling_picker/src/picker/result.rs b/mingling_picker/src/picker/result.rs new file mode 100644 index 0000000..bd283cf --- /dev/null +++ b/mingling_picker/src/picker/result.rs @@ -0,0 +1,54 @@ +use mingling_picker_macros::internal_repeat; + +internal_repeat!(1..=32 => { + #[doc(hidden)] + pub struct PickerResult$<(T$,+), Route> { + /// The route selected by the picker, if any. + /// If this is `Some`, the picker chose to follow a route instead of selecting values, + /// and all value fields (`v1`, `v2`, ...) will be `None`. + /// + /// Note: "route" here refers to an alternative path/choice, not a network route. + pub route: Option<Route>, + + ( + #[doc = concat!("The optional value for the ", $, "th type parameter.")] + pub v$: Option<T$>, + +) + } +}); + +internal_repeat!(1..=32 => { + impl<(T$,+), Route> PickerResult$<(T$,+), Route> { + /// Unwraps the result, panicking if a route was selected. + /// + /// # Panics + /// + /// Panics if `self.route` is `Some(...)`. + pub fn unwrap(self) -> ((T$,+)) { + ((self.v$.unwrap(),+)) + } + + /// Returns the individual option values without checking the route. + pub fn unpack(self) -> ((Option<T$>,+)) { + ((self.v$,+)) + } + + /// Converts to a `Result`, returning `Err(route)` if a route was selected, + /// or `Ok(values)` otherwise. + pub fn to_result(self) -> Result<((T$,+)), Route> { + if let Some(r) = self.route { + return Err(r); + } + Ok(self.unwrap()) + } + + /// Converts to an `Option`, returning `None` if a route was selected, + /// or `Some(values)` otherwise. + pub fn to_option(self) -> Option<((T$,+))> { + if let Some(_) = self.route { + return None; + } + Some(self.unwrap()) + } + } +}); |
