aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mingling_picker/src/infos.rs25
-rw-r--r--mingling_picker/src/picker.rs1
-rw-r--r--mingling_picker/src/picker/parse.rs35
-rw-r--r--mingling_picker/src/picker/patterns.rs25
-rw-r--r--mingling_picker/src/picker/result.rs2
5 files changed, 77 insertions, 11 deletions
diff --git a/mingling_picker/src/infos.rs b/mingling_picker/src/infos.rs
index f15ae88..ff78b0a 100644
--- a/mingling_picker/src/infos.rs
+++ b/mingling_picker/src/infos.rs
@@ -234,6 +234,31 @@ impl<Type> PickerArgResult<Type> {
_ => Type::default(),
}
}
+
+ /// Converts `PickerArgResult<Type>` into `Option<Type>`.
+ ///
+ /// Returns `Some(Type)` if [`Parsed`](PickerArgResult::Parsed), otherwise `None`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use mingling_picker::PickerArgResult;
+ ///
+ /// let result: PickerArgResult<i32> = PickerArgResult::Parsed(42);
+ /// assert_eq!(result.to_option(), Some(42));
+ ///
+ /// let result: PickerArgResult<i32> = PickerArgResult::NotFound;
+ /// assert_eq!(result.to_option(), None);
+ ///
+ /// let result: PickerArgResult<i32> = PickerArgResult::Unparsed;
+ /// assert_eq!(result.to_option(), None);
+ /// ```
+ pub fn to_option(self) -> Option<Type> {
+ match self {
+ PickerArgResult::Parsed(value) => Some(value),
+ _ => None,
+ }
+ }
}
pub struct PickerArgInfo<'a> {
diff --git a/mingling_picker/src/picker.rs b/mingling_picker/src/picker.rs
index 3926554..b1e8527 100644
--- a/mingling_picker/src/picker.rs
+++ b/mingling_picker/src/picker.rs
@@ -259,6 +259,7 @@ pub trait IntoPicker<'a, Route> {
flag_1: flag,
result_1: PickerArgResult::Unparsed,
default_1: None,
+ route_1: None,
post_1: None,
error_route: None,
}
diff --git a/mingling_picker/src/picker/parse.rs b/mingling_picker/src/picker/parse.rs
index ab72206..f9a59d7 100644
--- a/mingling_picker/src/picker/parse.rs
+++ b/mingling_picker/src/picker/parse.rs
@@ -14,14 +14,15 @@ use mingling_picker_macros::internal_repeat;
internal_repeat!(1..=32 => {
use crate::PickerPattern$;
+ use crate::PickerResult$;
});
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)]
- pub fn parse(mut self) -> PickerArgResult<((T$,+))> {
+ pub fn parse(mut self) -> PickerResult$<(T$,+), Route> {
// ArgInfos
let arg_infos: [PickerArgInfo; $] = [
(
@@ -35,10 +36,10 @@ internal_repeat!(1..=32 => {
PickerFlagAttr,
// Tag Func
- Option<Box<dyn FnOnce(&PickerArgs<'a>) -> Vec<usize>>>,
+ Box<dyn FnOnce(&PickerArgs<'a>) -> Vec<usize>>,
// Pick Func
- Option<Box<dyn FnOnce(&[&str])>>,
+ Box<dyn FnOnce(&[&str], &mut Option<Route>)>,
// Index
usize
@@ -50,16 +51,16 @@ internal_repeat!(1..=32 => {
T$::get_attr(self.flag_$),
// Tag Func
- Some(Box::new(|args| {
+ Box::new(|args| {
let ctx = TagPhaseContext {
arg_info: &arg_infos[$],
args,
};
T$::tag(ctx)
- })),
+ }),
// Pick Func
- Some(Box::new(|args| {
+ Box::new(|args, error_route| {
self.result_$ = match T$::pick(args) {
PickerArgResult::Parsed(mut value) => {
// Postprocess
@@ -79,12 +80,17 @@ internal_repeat!(1..=32 => {
PickerArgResult::Parsed(value)
} else {
+ if error_route.is_none() {
+ if let Some(get_route) = self.route_$ {
+ *error_route = Some(get_route());
+ }
+ }
other
}
},
}
- })),
+ }),
// Index
$
@@ -99,7 +105,7 @@ internal_repeat!(1..=32 => {
for (_, tag_func, pick_func, _idx) in bundle {
// Tag phase
- let tagged = (tag_func.unwrap())(&self.args);
+ let tagged = tag_func(&self.args);
let mut args_to_pick: Vec<&str> = vec![];
for i in tagged {
@@ -108,10 +114,17 @@ internal_repeat!(1..=32 => {
}
// Pick phase
- (pick_func.unwrap())(args_to_pick.as_slice());
+ pick_func(args_to_pick.as_slice(), &mut self.error_route);
}
-
+ // Combine Result
+ let result: PickerResult$<(T$,+), Route> = PickerResult$ {
+ route: self.error_route,
+ (
+ v$: self.result_$.to_option(),
+ +)
+ };
+ result
}
}
});
diff --git a/mingling_picker/src/picker/patterns.rs b/mingling_picker/src/picker/patterns.rs
index d8a2797..1b21d32 100644
--- a/mingling_picker/src/picker/patterns.rs
+++ b/mingling_picker/src/picker/patterns.rs
@@ -13,6 +13,7 @@ internal_repeat!(1..=32 => {
pub flag_$: &'a PickerFlag<'a, T$>,
pub result_$: PickerArgResult<T$>,
pub default_$: Option<Box<dyn FnOnce() -> T$>>,
+ pub route_$: Option<Box<dyn FnOnce() -> Route>>,
pub post_$: Option<Box<dyn FnOnce(T$) -> T$>>,
+)
}
@@ -65,6 +66,27 @@ internal_repeat!(1..=32 => {
self
}
+ /// Sets a route for when the flag is not provided.
+ ///
+ /// If the flag is not provided by the user at runtime, the given closure will be
+ /// called to produce a route value that will be returned early.
+ ///
+ /// # Example
+ ///
+ /// ```ignore
+ /// let pattern = picker
+ /// .pick(&my_flag)
+ /// .or_route(|| Redirect::home());
+ /// ```
+ pub fn or_route<F>(mut self, func: F) -> Self
+ where
+ F: FnMut() -> Route,
+ F: 'static,
+ {
+ self.route_$ = Some(Box::new(func));
+ self
+ }
+
/// Attaches a post-processing function to this flag.
///
/// After the flag's value is parsed (or defaulted), the given closure will be
@@ -113,6 +135,7 @@ internal_repeat!(1..32 => {
flag_$+: flag,
result_$+: PickerArgResult::Unparsed,
default_$+: None,
+ route_$+: None,
post_$+: None,
// Prev
@@ -120,6 +143,7 @@ internal_repeat!(1..32 => {
flag_$: self.flag_$,
result_$: self.result_$,
default_$: self.default_$,
+ route_$: self.route_$,
post_$: self.post_$,
+)
}
@@ -141,6 +165,7 @@ impl<'a, Route> Picker<'a, Route> {
error_route: None::<Route>,
flag_1: flag,
result_1: PickerArgResult::Unparsed,
+ route_1: None,
default_1: None,
post_1: None,
}
diff --git a/mingling_picker/src/picker/result.rs b/mingling_picker/src/picker/result.rs
index bd283cf..9cd78ae 100644
--- a/mingling_picker/src/picker/result.rs
+++ b/mingling_picker/src/picker/result.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::type_complexity)] // Aha, Type Gymnastics!
+
use mingling_picker_macros::internal_repeat;
internal_repeat!(1..=32 => {