diff options
| -rw-r--r-- | mingling_picker/src/infos.rs | 25 | ||||
| -rw-r--r-- | mingling_picker/src/picker.rs | 1 | ||||
| -rw-r--r-- | mingling_picker/src/picker/parse.rs | 35 | ||||
| -rw-r--r-- | mingling_picker/src/picker/patterns.rs | 25 | ||||
| -rw-r--r-- | mingling_picker/src/picker/result.rs | 2 |
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 => { |
