diff options
Diffstat (limited to 'mingling_picker')
| -rw-r--r-- | mingling_picker/src/flag.rs | 12 | ||||
| -rw-r--r-- | mingling_picker/src/infos.rs | 4 | ||||
| -rw-r--r-- | mingling_picker/src/pickable.rs | 9 | ||||
| -rw-r--r-- | mingling_picker/src/picker/parse.rs | 110 | ||||
| -rw-r--r-- | mingling_picker/src/picker/patterns.rs | 10 |
5 files changed, 120 insertions, 25 deletions
diff --git a/mingling_picker/src/flag.rs b/mingling_picker/src/flag.rs index 6c63c53..33c7829 100644 --- a/mingling_picker/src/flag.rs +++ b/mingling_picker/src/flag.rs @@ -24,7 +24,7 @@ use std::marker::PhantomData; #[derive(Default, Clone, Copy)] pub struct PickerFlag<'a, Type> where - Type: Default + Pickable<'a>, + Type: Pickable<'a>, { /// Full name, may include variant names (aliases), e.g., `["config", "cfg"]`. pub full: &'a [&'a str], @@ -41,7 +41,7 @@ where impl<'a, Type> PickerFlag<'a, Type> where - Type: Default + Pickable<'a>, + Type: Pickable<'a>, { /// Creates a new `PickerFlag` with the provided parameters. pub fn new(full: &'a [&'a str], short: Option<char>, positional: bool) -> Self { @@ -162,7 +162,7 @@ impl PickerFlagAttr { other: fn() -> PickerFlagAttr, ) -> PickerFlagAttr where - T: Pickable<'a> + Default, + T: Pickable<'a>, { if flag.is_positional() { PickerFlagAttr::Positional @@ -181,7 +181,7 @@ impl PickerFlagAttr { #[inline(always)] pub fn positional_or<'a, T>(flag: &PickerFlag<'a, T>, default: PickerFlagAttr) -> PickerFlagAttr where - T: Pickable<'a> + Default, + T: Pickable<'a>, { if flag.is_positional() { PickerFlagAttr::Positional @@ -199,7 +199,7 @@ impl PickerFlagAttr { #[inline(always)] pub fn positional_or_single<'a, T>(flag: &PickerFlag<'a, T>) -> PickerFlagAttr where - T: Pickable<'a> + Default, + T: Pickable<'a>, { if flag.is_positional() { PickerFlagAttr::Positional @@ -217,7 +217,7 @@ impl PickerFlagAttr { #[inline(always)] pub fn positional_or_multi<'a, T>(flag: &PickerFlag<'a, T>) -> PickerFlagAttr where - T: Pickable<'a> + Default, + T: Pickable<'a>, { if flag.is_positional() { PickerFlagAttr::PositionalMulti diff --git a/mingling_picker/src/infos.rs b/mingling_picker/src/infos.rs index f820c9a..ce9d198 100644 --- a/mingling_picker/src/infos.rs +++ b/mingling_picker/src/infos.rs @@ -265,7 +265,7 @@ pub struct PickerArgInfo<'a> { impl<'a, T> From<PickerFlag<'a, T>> for PickerArgInfo<'a> where - T: Pickable<'a> + Default, + T: Pickable<'a>, { fn from(value: PickerFlag<'a, T>) -> Self { let (long, alias) = match value.full.len() { @@ -293,7 +293,7 @@ where } } -impl<'a, T: Pickable<'a> + Default> From<&'a PickerFlag<'a, T>> for PickerArgInfo<'a> { +impl<'a, T: Pickable<'a>> From<&'a PickerFlag<'a, T>> for PickerArgInfo<'a> { fn from(value: &'a PickerFlag<'a, T>) -> Self { let (long, alias) = match value.full.len() { 0 => (None, None), diff --git a/mingling_picker/src/pickable.rs b/mingling_picker/src/pickable.rs index 9d3f054..8bb012a 100644 --- a/mingling_picker/src/pickable.rs +++ b/mingling_picker/src/pickable.rs @@ -18,7 +18,7 @@ mod implements; /// * `'a` - Lifetime parameter, used to associate references in [`PickerFlag`]. pub trait Pickable<'a> where - Self: Sized + Default, + Self: Sized, { /// Returns the parse-order attribute of this flag. /// @@ -78,11 +78,4 @@ pub struct TagPhaseContext<'a> { /// A read-only list of all arguments in the current [`Picker`]. pub args: &'a PickerArgs<'a>, - - /// Availability mask, recording positions already occupied by other `Pickable` tags. - /// - /// `mask.len()` equals `args.len()`. Where: - /// - `0` means the position is currently available (unoccupied); - /// - `1` means the position is already occupied and cannot be used again. - pub mask: &'a [usize], } diff --git a/mingling_picker/src/picker/parse.rs b/mingling_picker/src/picker/parse.rs index f69e078..8a55e03 100644 --- a/mingling_picker/src/picker/parse.rs +++ b/mingling_picker/src/picker/parse.rs @@ -1,4 +1,13 @@ -use crate::{Pickable, PickerResult}; +// -------------------------------------------------------------------------------------------- +// I have to say, the code generated by this `internal_repeat!` macro is really UGLY. +// +// But I have to admit, this is a **trade-off**. To achieve the syntax of `pick().pick().pick()` +// while ensuring type safety, this is the best approach I could think of. +// +// P.S. If there's a better way, please let me know. Thanks! +// -------------------------------------------------------------------------------------------- + +use crate::{Pickable, PickerArgInfo, PickerArgs, PickerFlagAttr, PickerResult, TagPhaseContext}; use mingling_picker_macros::internal_repeat; internal_repeat!(1..=32 => { @@ -7,11 +16,104 @@ internal_repeat!(1..=32 => { internal_repeat!(1..=32 => { impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)> - where (T$: Pickable<'a> + Default,+) + where (T$: Pickable<'a>,+) { #[allow(clippy::type_complexity)] - pub fn parse(self) -> PickerResult<((T$,+))> { - todo!() + pub fn parse(mut self) -> PickerResult<((T$,+))> { + // ArgInfos + let arg_infos: [PickerArgInfo; $] = [ + ( + PickerArgInfo::from(self.flag_$), + +) + ]; + + // Read & sort attrs + let mut attrs: [ + ( + // Flag Attr + PickerFlagAttr, + + // Tag Func + Box<dyn FnOnce(&PickerArgs<'a>) -> Vec<usize>>, + + // Pick Func + Box<dyn FnOnce(&[&str])>, + + // Index + usize + ) + ; $] = [ + ( + ( + // Flag Attr + T$::get_attr(self.flag_$), + + // Tag Func + Box::new(|args| { + let ctx = TagPhaseContext { + arg_info: &arg_infos[$], + args, + }; + T$::tag(ctx) + }), + + // Pick Func + Box::new(|args| { + self.result_$ = match T$::pick(args) { + PickerResult::Parsed(mut value) => { + // Postprocess + if let Some(post) = self.post_$ { + value = post(value); + } + PickerResult::Parsed(value) + }, + other => { + if let Some(get_default) = self.default_$ { + let mut value = get_default(); + + // Postprocess + if let Some(post) = self.post_$ { + value = post(value); + } + + PickerResult::Parsed(value) + } else { + other + } + }, + + } + }), + + // Index + $ + ), + +) + ]; + + // Sort by Attr Ord (descending) + attrs.sort_by(|a, b| b.0.cmp(&a.0)); + + // Parsing + for (_, tag_func, pick_func, _idx) in attrs { + + // Tag phase + let tagged = tag_func(&self.args); + let mut args_to_pick: Vec<&str> = vec![]; + + for i in tagged { + // Update args to pick + args_to_pick.push(self.args.get(i).unwrap_or_default()); + } + + // Pick phase + pick_func(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 b12f151..4f54f9d 100644 --- a/mingling_picker/src/picker/patterns.rs +++ b/mingling_picker/src/picker/patterns.rs @@ -5,7 +5,7 @@ use crate::{Pickable, Picker, PickerArgs, PickerFlag, PickerResult}; internal_repeat!(1..=32 => { #[doc(hidden)] pub struct PickerPattern$<'a, (T$,+)> - where (T$: Pickable<'a> + Default,+) + where (T$: Pickable<'a>,+) { pub args: PickerArgs<'a>, ( @@ -19,7 +19,7 @@ internal_repeat!(1..=32 => { internal_repeat!(1..=32 => { impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)> - where (T$: Pickable<'a> + Default,+) + where (T$: Pickable<'a>,+) { /// Sets a default value provider for this flag. /// @@ -70,7 +70,7 @@ internal_repeat!(1..=32 => { internal_repeat!(1..32 => { impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)> - where (T$: Pickable<'a> + Default,+) + where (T$: Pickable<'a>,+) { #[allow(clippy::type_complexity)] /// Adds a new flag to the picking chain, returning a new `PickerPattern` with one more type parameter. @@ -80,7 +80,7 @@ internal_repeat!(1..32 => { /// The new flag's result is initially `Unparsed`. pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern$+<'a, (T$,+), N> where - N: Pickable<'a> + Default, + N: Pickable<'a>, { PickerPattern$+ { // Args @@ -111,7 +111,7 @@ impl<'a> Picker<'a> { /// The result is initially `Unparsed`. pub fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N> where - N: Pickable<'a> + Default, + N: Pickable<'a>, { PickerPattern1 { args: self.args, |
