aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-15 16:08:16 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-15 16:14:15 +0800
commita7a116110a80dee887ee2d9a2660fbff5e0cbc62 (patch)
tree120f5f497d6ba169a57af8ea77fd8df7e8432b9d
parentc3e990a5c47dc8894899d774a0d89f089adec308 (diff)
feat(picker): add Route generic parameter for error routing
-rw-r--r--mingling_picker/src/picker.rs51
-rw-r--r--mingling_picker/src/picker/parse.rs40
-rw-r--r--mingling_picker/src/picker/patterns.rs15
3 files changed, 59 insertions, 47 deletions
diff --git a/mingling_picker/src/picker.rs b/mingling_picker/src/picker.rs
index 246e013..3926554 100644
--- a/mingling_picker/src/picker.rs
+++ b/mingling_picker/src/picker.rs
@@ -1,4 +1,4 @@
-use std::ops::Index;
+use std::{marker::PhantomData, ops::Index};
mod parse;
@@ -17,7 +17,9 @@ use crate::{Pickable, PickerArgResult, PickerFlag};
/// - Basic arguments
/// - Parsing states
/// - Parsing results
-pub struct Picker<'a> {
+pub struct Picker<'a, Route> {
+ route_phantom: PhantomData<Route>,
+
/// Internal arguments of Picker
args: PickerArgs<'a>,
}
@@ -101,31 +103,34 @@ impl<'a> IntoIterator for &'a PickerArgs<'a> {
}
}
-impl<'a> From<&'a [&'a str]> for Picker<'a> {
+impl<'a, Route> From<&'a [&'a str]> for Picker<'a, Route> {
fn from(value: &'a [&'a str]) -> Self {
Picker {
+ route_phantom: PhantomData,
args: PickerArgs::Slice(value),
}
}
}
-impl<'a> From<Vec<&'a str>> for Picker<'a> {
+impl<'a, Route> From<Vec<&'a str>> for Picker<'a, Route> {
fn from(value: Vec<&'a str>) -> Self {
Picker {
+ route_phantom: PhantomData,
args: PickerArgs::Vec(value),
}
}
}
-impl<'a> From<Vec<String>> for Picker<'a> {
+impl<'a, Route> From<Vec<String>> for Picker<'a, Route> {
fn from(value: Vec<String>) -> Self {
Picker {
+ route_phantom: PhantomData,
args: PickerArgs::Owned(value),
}
}
}
-impl<'a> Picker<'a> {
+impl<'a, Route> Picker<'a, Route> {
/// Returns a reference to the internal `PickerArgs`.
pub fn args(&self) -> &PickerArgs<'a> {
&self.args
@@ -157,7 +162,7 @@ impl<'a> Picker<'a> {
}
}
-impl<'a> Index<usize> for Picker<'a> {
+impl<'a, Route> Index<usize> for Picker<'a, Route> {
type Output = str;
fn index(&self, index: usize) -> &Self::Output {
@@ -165,7 +170,7 @@ impl<'a> Index<usize> for Picker<'a> {
}
}
-impl<'a> Index<usize> for &Picker<'a> {
+impl<'a, Route> Index<usize> for &Picker<'a, Route> {
type Output = str;
fn index(&self, index: usize) -> &Self::Output {
@@ -173,7 +178,7 @@ impl<'a> Index<usize> for &Picker<'a> {
}
}
-impl<'a> IntoIterator for &'a Picker<'a> {
+impl<'a, Route> IntoIterator for &'a Picker<'a, Route> {
type Item = String;
type IntoIter = PickerIter<'a>;
@@ -218,9 +223,10 @@ impl<'a> ExactSizeIterator for PickerIter<'a> {}
///
/// Implemented for:
/// - `&[&str]` (borrowed slice)
+/// - `&[String]` (borrowed slice of owned strings)
/// - `Vec<&str>` (owned vector of borrowed strings)
/// - `Vec<String>` (owned vector of owned strings)
-pub trait IntoPicker<'a> {
+pub trait IntoPicker<'a, Route> {
/// Converts the value into a `Picker`
///
/// # Examples
@@ -237,13 +243,13 @@ pub trait IntoPicker<'a> {
/// let args: Picker = vec!["a".to_string(), "b".to_string()].to_picker();
/// assert_eq!(args.len(), 2);
/// ```
- fn to_picker(self) -> Picker<'a>;
+ fn to_picker(self) -> Picker<'a, Route>;
/// Creates a `PickerPattern1` from the given flag for the `pick` method.
///
/// This method converts the value into a `Picker` and starts a parameter
/// picking chain with one flag. The result is initially `Unparsed`.
- fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N>
+ fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N, Route>
where
Self: Sized,
N: Pickable<'a> + Default + Sized,
@@ -254,38 +260,43 @@ pub trait IntoPicker<'a> {
result_1: PickerArgResult::Unparsed,
default_1: None,
post_1: None,
+ error_route: None,
}
}
}
-impl<'a> IntoPicker<'a> for &'a [&'a str] {
- fn to_picker(self) -> Picker<'a> {
+impl<'a, Route> IntoPicker<'a, Route> for &'a [&'a str] {
+ fn to_picker(self) -> Picker<'a, Route> {
Picker {
+ route_phantom: PhantomData,
args: PickerArgs::Slice(self),
}
}
}
-impl<'a> IntoPicker<'a> for &'a [String] {
- fn to_picker(self) -> Picker<'a> {
+impl<'a, Route> IntoPicker<'a, Route> for &'a [String] {
+ fn to_picker(self) -> Picker<'a, Route> {
let vec: Vec<&str> = self.iter().map(|s| s.as_str()).collect();
Picker {
+ route_phantom: PhantomData,
args: PickerArgs::Vec(vec),
}
}
}
-impl<'a> IntoPicker<'a> for Vec<&'a str> {
- fn to_picker(self) -> Picker<'a> {
+impl<'a, Route> IntoPicker<'a, Route> for Vec<&'a str> {
+ fn to_picker(self) -> Picker<'a, Route> {
Picker {
+ route_phantom: PhantomData,
args: PickerArgs::Vec(self),
}
}
}
-impl<'a> IntoPicker<'a> for Vec<String> {
- fn to_picker(self) -> Picker<'a> {
+impl<'a, Route> IntoPicker<'a, Route> for Vec<String> {
+ fn to_picker(self) -> Picker<'a, Route> {
Picker {
+ route_phantom: PhantomData,
args: PickerArgs::Owned(self),
}
}
diff --git a/mingling_picker/src/picker/parse.rs b/mingling_picker/src/picker/parse.rs
index 8a55e03..ab72206 100644
--- a/mingling_picker/src/picker/parse.rs
+++ b/mingling_picker/src/picker/parse.rs
@@ -7,7 +7,9 @@
// P.S. If there's a better way, please let me know. Thanks!
// --------------------------------------------------------------------------------------------
-use crate::{Pickable, PickerArgInfo, PickerArgs, PickerFlagAttr, PickerResult, TagPhaseContext};
+use crate::{
+ Pickable, PickerArgInfo, PickerArgResult, PickerArgs, PickerFlagAttr, TagPhaseContext,
+};
use mingling_picker_macros::internal_repeat;
internal_repeat!(1..=32 => {
@@ -19,7 +21,7 @@ internal_repeat!(1..=32 => {
where (T$: Pickable<'a>,+)
{
#[allow(clippy::type_complexity)]
- pub fn parse(mut self) -> PickerResult<((T$,+))> {
+ pub fn parse(mut self) -> PickerArgResult<((T$,+))> {
// ArgInfos
let arg_infos: [PickerArgInfo; $] = [
(
@@ -27,17 +29,16 @@ internal_repeat!(1..=32 => {
+)
];
- // Read & sort attrs
- let mut attrs: [
+ let mut bundle: [
(
// Flag Attr
PickerFlagAttr,
// Tag Func
- Box<dyn FnOnce(&PickerArgs<'a>) -> Vec<usize>>,
+ Option<Box<dyn FnOnce(&PickerArgs<'a>) -> Vec<usize>>>,
// Pick Func
- Box<dyn FnOnce(&[&str])>,
+ Option<Box<dyn FnOnce(&[&str])>>,
// Index
usize
@@ -49,23 +50,23 @@ internal_repeat!(1..=32 => {
T$::get_attr(self.flag_$),
// Tag Func
- Box::new(|args| {
+ Some(Box::new(|args| {
let ctx = TagPhaseContext {
arg_info: &arg_infos[$],
args,
};
T$::tag(ctx)
- }),
+ })),
// Pick Func
- Box::new(|args| {
+ Some(Box::new(|args| {
self.result_$ = match T$::pick(args) {
- PickerResult::Parsed(mut value) => {
+ PickerArgResult::Parsed(mut value) => {
// Postprocess
if let Some(post) = self.post_$ {
value = post(value);
}
- PickerResult::Parsed(value)
+ PickerArgResult::Parsed(value)
},
other => {
if let Some(get_default) = self.default_$ {
@@ -76,14 +77,14 @@ internal_repeat!(1..=32 => {
value = post(value);
}
- PickerResult::Parsed(value)
+ PickerArgResult::Parsed(value)
} else {
other
}
},
}
- }),
+ })),
// Index
$
@@ -91,14 +92,14 @@ internal_repeat!(1..=32 => {
+)
];
- // Sort by Attr Ord (descending)
- attrs.sort_by(|a, b| b.0.cmp(&a.0));
+ // Sort by Bundle Ord (descending)
+ bundle.sort_by(|a, b| b.0.cmp(&a.0));
// Parsing
- for (_, tag_func, pick_func, _idx) in attrs {
+ for (_, tag_func, pick_func, _idx) in bundle {
// Tag phase
- let tagged = tag_func(&self.args);
+ let tagged = (tag_func.unwrap())(&self.args);
let mut args_to_pick: Vec<&str> = vec![];
for i in tagged {
@@ -107,13 +108,10 @@ internal_repeat!(1..=32 => {
}
// Pick phase
- pick_func(args_to_pick.as_slice());
+ (pick_func.unwrap())(args_to_pick.as_slice());
}
- // Sort by Index Ord
- attrs.sort_by(|a, b| a.3.cmp(&b.3));
- PickerResult::NotFound
}
}
});
diff --git a/mingling_picker/src/picker/patterns.rs b/mingling_picker/src/picker/patterns.rs
index b828849..d8a2797 100644
--- a/mingling_picker/src/picker/patterns.rs
+++ b/mingling_picker/src/picker/patterns.rs
@@ -4,10 +4,11 @@ use crate::{Pickable, Picker, PickerArgResult, PickerArgs, PickerFlag};
internal_repeat!(1..=32 => {
#[doc(hidden)]
- pub struct PickerPattern$<'a, (T$,+)>
+ pub struct PickerPattern$<'a, (T$,+), Route>
where (T$: Pickable<'a>,+)
{
pub args: PickerArgs<'a>,
+ pub error_route: Option<Route>,
(
pub flag_$: &'a PickerFlag<'a, T$>,
pub result_$: PickerArgResult<T$>,
@@ -18,7 +19,7 @@ internal_repeat!(1..=32 => {
});
internal_repeat!(1..=32 => {
- impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)>
+ impl<'a, (T$,+), Route> PickerPattern$<'a, (T$,+), Route>
where (T$: Pickable<'a>,+)
{
/// Sets a default value provider for this flag.
@@ -90,7 +91,7 @@ internal_repeat!(1..=32 => {
});
internal_repeat!(1..32 => {
- impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)>
+ impl<'a, (T$,+), Route> PickerPattern$<'a, (T$,+), Route>
where (T$: Pickable<'a>,+)
{
#[allow(clippy::type_complexity)]
@@ -99,13 +100,14 @@ internal_repeat!(1..32 => {
/// This method extends the current picking pattern by appending an additional flag.
/// The previous flags and their results are preserved as part of the new pattern.
/// The new flag's result is initially `Unparsed`.
- pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern$+<'a, (T$,+), N>
+ pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern$+<'a, (T$,+), N, Route>
where
N: Pickable<'a>,
{
PickerPattern$+ {
// Args
args: self.args,
+ error_route: self.error_route,
// Current
flag_$+: flag,
@@ -125,17 +127,18 @@ internal_repeat!(1..32 => {
}
});
-impl<'a> Picker<'a> {
+impl<'a, Route> Picker<'a, Route> {
/// Creates a `PickerPattern1` from the given flag to start a picking chain.
///
/// This method initiates a parameter picking chain with one flag.
/// The result is initially `Unparsed`.
- pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N>
+ pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N, Route>
where
N: Pickable<'a>,
{
PickerPattern1 {
args: self.args,
+ error_route: None::<Route>,
flag_1: flag,
result_1: PickerArgResult::Unparsed,
default_1: None,