diff options
Diffstat (limited to 'mingling_picker/src')
| -rw-r--r-- | mingling_picker/src/flag.rs | 4 | ||||
| -rw-r--r-- | mingling_picker/src/lib.rs | 3 | ||||
| -rw-r--r-- | mingling_picker/src/parselib.rs | 3 | ||||
| -rw-r--r-- | mingling_picker/src/parselib/seek.rs | 1 | ||||
| -rw-r--r-- | mingling_picker/src/pickable.rs | 22 | ||||
| -rw-r--r-- | mingling_picker/src/pickable/implements.rs | 52 | ||||
| -rw-r--r-- | mingling_picker/src/picker.rs | 2 | ||||
| -rw-r--r-- | mingling_picker/src/picker/parse.rs | 2 | ||||
| -rw-r--r-- | mingling_picker/src/picker/patterns.rs | 10 | ||||
| -rw-r--r-- | mingling_picker/src/tag.rs | 176 |
10 files changed, 231 insertions, 44 deletions
diff --git a/mingling_picker/src/flag.rs b/mingling_picker/src/flag.rs index 0b351f8..86712c9 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, + Type: Default + 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, + Type: Default + Pickable<'a>, { /// Creates a new `PickerFlag` with the provided parameters. pub fn new(full: &'a [&'a str], short: Option<char>, positional: bool) -> Self { diff --git a/mingling_picker/src/lib.rs b/mingling_picker/src/lib.rs index d3d3fdd..fa45d71 100644 --- a/mingling_picker/src/lib.rs +++ b/mingling_picker/src/lib.rs @@ -10,6 +10,9 @@ pub use flag::*; mod result; pub use result::*; +mod tag; +pub use tag::*; + pub mod parselib; pub mod prelude { diff --git a/mingling_picker/src/parselib.rs b/mingling_picker/src/parselib.rs index 132045b..21f0ba2 100644 --- a/mingling_picker/src/parselib.rs +++ b/mingling_picker/src/parselib.rs @@ -1,2 +1,5 @@ +mod seek; +// pub use seek::*; + mod style; pub use style::*; diff --git a/mingling_picker/src/parselib/seek.rs b/mingling_picker/src/parselib/seek.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/mingling_picker/src/parselib/seek.rs @@ -0,0 +1 @@ + diff --git a/mingling_picker/src/pickable.rs b/mingling_picker/src/pickable.rs index 9fe2c9d..7a89631 100644 --- a/mingling_picker/src/pickable.rs +++ b/mingling_picker/src/pickable.rs @@ -1,4 +1,4 @@ -use crate::PickerResult; +use crate::{PickerFlag, PickerResult, PickerTag}; mod implements; @@ -20,20 +20,28 @@ mod implements; /// # Examples /// /// ``` -/// # use mingling_picker::{Pickable, PickerResult}; +/// # use mingling_picker::{Pickable, PickerResult, PickerFlag, PickerTag}; /// #[derive(Default)] /// struct MyType(String); /// -/// impl Pickable for MyType { -/// fn pick(raw_str: &str) -> PickerResult<Self> { -/// PickerResult::Parsed(MyType(raw_str.to_string())) +/// impl<'a> Pickable<'a> for MyType { +/// fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a> { +/// let tag = PickerTag::from(flag); +/// } +/// +/// fn pick(raw_strs: &[&str]) -> PickerResult<Self> { +/// PickerResult::Parsed(MyType(raw_strs.join(" "))) /// } /// } /// ``` -pub trait Pickable +pub trait Pickable<'a> where Self: Sized + Default, { + /// Given a [`PickerFlag`], returns a [`PickerTag`] that tells the parser + /// about the argument's characteristics (e.g., positional, optional, multi). + fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a>; + /// Parses a `Self` value from the given raw string input. - fn pick(raw_str: &str) -> PickerResult<Self>; + fn pick(raw_strs: &[&str]) -> PickerResult<Self>; } diff --git a/mingling_picker/src/pickable/implements.rs b/mingling_picker/src/pickable/implements.rs index 34f9727..665bde5 100644 --- a/mingling_picker/src/pickable/implements.rs +++ b/mingling_picker/src/pickable/implements.rs @@ -1,15 +1,20 @@ -use crate::{Pickable, PickerResult}; -use std::path::PathBuf; +use crate::{Pickable, PickerFlag, PickerResult, PickerTag}; macro_rules! impl_pickable { ($($t:ty),*) => { - $( - impl Pickable for $t { - fn pick(raw_str: &str) -> PickerResult<Self> { - raw_str.parse::<$t>().into() - } + $(impl<'a> Pickable<'a> for $t { + fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a> { + flag.into() } - )* + + fn pick(raw_strs: &[&str]) -> PickerResult<Self> { + raw_strs + .first() + .and_then(|s| s.parse().ok()) + .map(PickerResult::Parsed) + .unwrap_or(PickerResult::NotFound) + } + })* }; } @@ -17,27 +22,18 @@ impl_pickable!( i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, usize, f32, f64, isize ); -impl Pickable for String { - fn pick(raw_str: &str) -> PickerResult<Self> { - PickerResult::Parsed(raw_str.to_string()) +impl<'a> Pickable<'a> for String { + fn tag(flag: &'a PickerFlag<'a, Self>) -> PickerTag<'a> { + let mut tag: PickerTag = flag.into(); + tag.set_optional(false); + tag.set_multi(false); + tag } -} -impl Pickable for PathBuf { - fn pick(raw_str: &str) -> PickerResult<Self> { - PickerResult::Parsed(PathBuf::from(raw_str)) - } -} - -impl<T: Pickable> Pickable for Option<T> { - fn pick(raw_str: &str) -> PickerResult<Self> { - if raw_str.is_empty() { - PickerResult::Parsed(None) - } else { - match T::pick(raw_str) { - PickerResult::Parsed(v) => PickerResult::Parsed(Some(v)), - _ => PickerResult::Parsed(None), - } - } + fn pick(raw_strs: &[&str]) -> PickerResult<Self> { + raw_strs + .first() + .map(|s| PickerResult::Parsed(s.to_string())) + .unwrap_or(PickerResult::NotFound) } } diff --git a/mingling_picker/src/picker.rs b/mingling_picker/src/picker.rs index 01c94a9..3a740cf 100644 --- a/mingling_picker/src/picker.rs +++ b/mingling_picker/src/picker.rs @@ -241,7 +241,7 @@ pub trait IntoPicker<'a> { fn pick<N>(self, flag: &'a PickerFlag<'a, N>) -> PickerPattern1<'a, N> where Self: Sized, - N: Pickable + Default + Sized, + N: Pickable<'a> + Default + Sized, { PickerPattern1 { args: self.to_picker().args, diff --git a/mingling_picker/src/picker/parse.rs b/mingling_picker/src/picker/parse.rs index defbcbf..f69e078 100644 --- a/mingling_picker/src/picker/parse.rs +++ b/mingling_picker/src/picker/parse.rs @@ -7,7 +7,7 @@ internal_repeat!(1..=32 => { internal_repeat!(1..=32 => { impl<'a, (T$,+)> PickerPattern$<'a, (T$,+)> - where (T$: Pickable + Default,+) + where (T$: Pickable<'a> + Default,+) { #[allow(clippy::type_complexity)] pub fn parse(self) -> PickerResult<((T$,+))> { diff --git a/mingling_picker/src/picker/patterns.rs b/mingling_picker/src/picker/patterns.rs index a33860b..b12f151 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 + Default,+) + where (T$: Pickable<'a> + Default,+) { 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 + Default,+) + where (T$: Pickable<'a> + Default,+) { /// 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 + Default,+) + where (T$: Pickable<'a> + Default,+) { #[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 + Default, + N: Pickable<'a> + Default, { 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 + Default, + N: Pickable<'a> + Default, { PickerPattern1 { args: self.args, diff --git a/mingling_picker/src/tag.rs b/mingling_picker/src/tag.rs new file mode 100644 index 0000000..6f91630 --- /dev/null +++ b/mingling_picker/src/tag.rs @@ -0,0 +1,176 @@ +use crate::{Pickable, PickerFlag}; + +/// Represents a command-line argument/flag tag for a picker. +/// +/// This struct defines how a picker argument should be parsed from the command line, +/// including its short name (e.g., `-n`), long name (e.g., `--name`), and aliases. +/// +/// # Fields +/// +/// * `short` - The short form of the tag, typically a single character (e.g., `-n`). +/// * `long` - The long form of the tag (e.g., `--name`). +/// * `alias` - Alternative names for the tag (e.g., `["-N", "--nickname"]`). +/// * `positional` - Whether this tag is a positional argument (no `-` or `--` prefix). +/// * `optional` - Whether this tag is optional or required. +/// * `multi` - Whether this tag can accept multiple values. +pub struct PickerTag<'a> { + /// The short form of the tag, e.g. `'n'` for `-n`. + pub short: Option<char>, + /// The long form of the tag, e.g. `"name"` for `--name`. + pub long: Option<&'a str>, + /// Alternative names for the tag, e.g. `["-N", "--nickname"]`. + pub alias: Option<Vec<&'a str>>, + /// Whether this tag is a positional argument (no `-` or `--` prefix). + pub positional: bool, + /// Whether this tag is optional or required. + pub optional: bool, + /// Whether this tag can accept multiple values. + pub multi: bool, +} + +impl<'a, T> From<PickerFlag<'a, T>> for PickerTag<'a> +where + T: Pickable<'a> + Default, +{ + fn from(value: PickerFlag<'a, T>) -> Self { + let (long, alias) = match value.full.len() { + 0 => (None, None), + _ => { + let long = Some(value.full[0]); + let alias = if value.full.len() > 1 { + Some(value.full[1..].to_vec()) + } else { + None + }; + (long, alias) + } + }; + + Self { + short: value.short, + long, + alias, + positional: value.positional, + optional: false, + multi: false, + } + } +} + +impl<'a, T: Pickable<'a> + Default> From<&'a PickerFlag<'a, T>> for PickerTag<'a> { + fn from(value: &'a PickerFlag<'a, T>) -> Self { + let (long, alias) = match value.full.len() { + 0 => (None, None), + _ => { + let long = Some(value.full[0]); + let alias = if value.full.len() > 1 { + Some(value.full[1..].to_vec()) + } else { + None + }; + (long, alias) + } + }; + + Self { + short: value.short, + long, + alias, + positional: value.positional, + optional: false, + multi: false, + } + } +} + +impl<'a> PickerTag<'a> { + /// Create a new `PickerTag` with default values. + pub fn new() -> Self { + Self { + short: None, + long: None, + alias: None, + positional: false, + optional: false, + multi: false, + } + } + + /// Set the short flag (e.g., `'n'` for `-n`). + pub fn with_short(mut self, short: char) -> Self { + self.short = Some(short); + self + } + + /// Set the long flag (e.g., `"name"` for `--name`). + pub fn with_long(mut self, long: &'a str) -> Self { + self.long = Some(long); + self + } + + /// Set aliases for the tag. + pub fn with_alias(mut self, alias: Vec<&'a str>) -> Self { + self.alias = Some(alias); + self + } + + /// Mark the tag as positional. + pub fn with_positional(mut self, positional: bool) -> Self { + self.positional = positional; + self + } + + /// Mark the tag as optional. + pub fn with_optional(mut self, optional: bool) -> Self { + self.optional = optional; + self + } + + /// Mark the tag as multi-value. + pub fn with_multi(mut self, multi: bool) -> Self { + self.multi = multi; + self + } + + /// Set the short flag (e.g., `'n'` for `-n`). + pub fn set_short(&mut self, short: char) -> &mut Self { + self.short = Some(short); + self + } + + /// Set the long flag (e.g., `"name"` for `--name`). + pub fn set_long(&mut self, long: &'a str) -> &mut Self { + self.long = Some(long); + self + } + + /// Set aliases for the tag. + pub fn set_alias(&mut self, alias: Vec<&'a str>) -> &mut Self { + self.alias = Some(alias); + self + } + + /// Set whether this tag is positional. + pub fn set_positional(&mut self, positional: bool) -> &mut Self { + self.positional = positional; + self + } + + /// Set whether this tag is optional. + pub fn set_optional(&mut self, optional: bool) -> &mut Self { + self.optional = optional; + self + } + + /// Set whether this tag accepts multiple values. + pub fn set_multi(&mut self, multi: bool) -> &mut Self { + self.multi = multi; + self + } +} + +impl<'a> Default for PickerTag<'a> { + fn default() -> Self { + Self::new() + } +} |
