aboutsummaryrefslogtreecommitdiff
path: root/mingling_picker
diff options
context:
space:
mode:
Diffstat (limited to 'mingling_picker')
-rw-r--r--mingling_picker/src/flag.rs12
-rw-r--r--mingling_picker/src/infos.rs4
-rw-r--r--mingling_picker/src/pickable.rs9
-rw-r--r--mingling_picker/src/picker/parse.rs110
-rw-r--r--mingling_picker/src/picker/patterns.rs10
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,