From 79ec6878877f0fd9246d67d3cd4f8cc2d1200150 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Fri, 17 Jul 2026 11:08:07 +0800 Subject: refactor: rename `mingling_picker` to `arg_picker` --- arg_picker/src/pickable/multi_pickable.rs | 76 +++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 arg_picker/src/pickable/multi_pickable.rs (limited to 'arg_picker/src/pickable/multi_pickable.rs') diff --git a/arg_picker/src/pickable/multi_pickable.rs b/arg_picker/src/pickable/multi_pickable.rs new file mode 100644 index 0000000..84a8068 --- /dev/null +++ b/arg_picker/src/pickable/multi_pickable.rs @@ -0,0 +1,76 @@ +use crate::{ + Pickable, PickerArg, PickerArgAttr, PickerArgResult, SinglePickable, TagPhaseContext, + matcher_needed::Matcher, + parselib::{MultiArgMatcher, ParserStyle}, +}; + +/// Boundary check for multi-value positional parameters. +pub trait BoundaryCheck { + fn check_boundary(raw: &str) -> bool; +} + +/// Trait for multi-value parameters. +pub trait MultiPickableWithBoundary: Sized { + type Checker: BoundaryCheck; + fn pick_multi(raw: Vec) -> PickerArgResult; +} + +/// Marker: unit type that always accepts — no boundary. +pub struct NoBoundary; + +impl BoundaryCheck for NoBoundary { + #[inline(always)] + fn check_boundary(_raw: &str) -> bool { + false + } +} + +/// `Vec` is greedy — it takes everything with `NoBoundary`. +impl MultiPickableWithBoundary for Vec { + type Checker = NoBoundary; + + fn pick_multi(raw: Vec) -> PickerArgResult { + let mut result = Vec::with_capacity(raw.len()); + for s in &raw { + match T::pick_single(Some(s)) { + PickerArgResult::Parsed(v) => result.push(v), + PickerArgResult::NotFound => return PickerArgResult::NotFound, + PickerArgResult::Unparsed => {} + } + } + PickerArgResult::Parsed(result) + } +} + +/// If the first raw string looks like a named flag (starts with the +/// style's long or short prefix), strip it — it's the flag, not a value. +fn strip_flag<'a>(raw_strs: &'a [&'a str]) -> &'a [&'a str] { + if let Some(first) = raw_strs.first() { + let style = ParserStyle::global_style(); + if first.starts_with(style.long_prefix) || first.starts_with(style.short_prefix) { + return &raw_strs[1..]; + } + } + raw_strs +} + +// Pickable impl for Vec + +impl<'a, T> Pickable<'a> for Vec +where + T: SinglePickable, +{ + fn get_attr(flag: &'a PickerArg<'a, Self>) -> PickerArgAttr { + PickerArgAttr::positional_or_multi(flag) + } + + fn tag(ctx: TagPhaseContext) -> Vec { + MultiArgMatcher::match_all(ctx.into()) + } + + fn pick(raw_strs: &[&str]) -> PickerArgResult { + let strs = strip_flag(raw_strs); + let owned: Vec = strs.iter().map(|&s| s.to_string()).collect(); + as MultiPickableWithBoundary>::pick_multi(owned) + } +} -- cgit