1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
mod flag_matcher;
pub use flag_matcher::*;
mod style;
pub use style::*;
mod utils;
pub use utils::*;
use crate::{PickerArgInfo, PickerArgs};
/// Represents a single argument with its original raw string and index.
///
/// This is used during pattern matching to provide context about
/// which argument is being processed.
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct MaskedArg<'a> {
/// The raw string value of the argument.
pub raw: &'a str,
/// The original index of the argument in the full argument list.
pub raw_idx: usize,
}
/// Trait for defining matching logic against masked arguments.
///
/// Implementors can define custom strategies for matching one or all
/// arguments that pass through a mask filter.
pub trait Matcher {
/// Called when only one match is needed.
///
/// Returns the index of the first matched argument, or `None` if no match.
fn on_match_one(
args: &[MaskedArg],
style: &ParserStyle,
arg_info: &PickerArgInfo,
) -> Option<usize>;
/// Called when all matches are needed.
///
/// Returns a vector of indices of all matched arguments.
fn on_match_all(
args: &[MaskedArg],
style: &ParserStyle,
arg_info: &PickerArgInfo,
) -> Vec<usize>;
/// Convenience method that builds masked arguments from `PickerArgs` and a mask,
/// then calls `on_match_one`.
fn match_one<'a>(ctx: MatcherContext<'a>) -> Option<usize> {
let masked_args = build_masked_args(ctx.args, ctx.mask);
Self::on_match_one(masked_args.as_slice(), ctx.style, ctx.arg_info)
}
/// Convenience method that builds masked arguments from `PickerArgs` and a mask,
/// then calls `on_match_all`.
fn match_all<'a>(ctx: MatcherContext<'a>) -> Vec<usize> {
let masked_args = build_masked_args(ctx.args, ctx.mask);
Self::on_match_all(masked_args.as_slice(), ctx.style, ctx.arg_info)
}
}
/// Context for matcher operations
///
/// This struct bundles together the key pieces of data needed during matching:
/// - `args`: The full set of parsed arguments.
/// - `mask`: A byte mask indicating which arguments are currently active (non-zero = active).
/// - `style`: The parsing style configuration.
pub struct MatcherContext<'a> {
/// The full set of parsed arguments.
pub args: &'a PickerArgs<'a>,
/// A byte mask where non-zero values indicate the argument at that position is active/should be matched.
pub mask: &'a [u8],
/// The parsing style configuration.
pub style: &'a ParserStyle<'a>,
/// Metadata about the command-line argument/flag being processed.
///
/// Contains information such as short form (`-n`), long form (`--name`),
/// aliases, and parsing flags (positional, optional, multi, is_flag).
/// Used by matchers to make decisions based on argument characteristics.
pub arg_info: &'a PickerArgInfo<'a>,
}
impl<'a> From<&'a crate::TagPhaseContext<'a>> for MatcherContext<'a> {
fn from(ctx: &'a crate::TagPhaseContext<'a>) -> Self {
MatcherContext {
args: ctx.args,
mask: ctx.mask,
style: ParserStyle::global_style(),
arg_info: ctx.arg_info,
}
}
}
impl<'a> From<crate::TagPhaseContext<'a>> for MatcherContext<'a> {
fn from(ctx: crate::TagPhaseContext<'a>) -> Self {
MatcherContext {
args: ctx.args,
mask: ctx.mask,
style: ParserStyle::global_style(),
arg_info: ctx.arg_info,
}
}
}
#[inline(always)]
fn is_masked(mask: &[u8], idx: usize) -> bool {
idx < mask.len() && mask[idx] != 0
}
#[inline(always)]
fn build_masked_args<'a>(args: &'a PickerArgs, mask: &'a [u8]) -> Vec<MaskedArg<'a>> {
let mut cidx = 0;
args.iter()
.filter_map(|r| {
let idx = cidx;
cidx += 1;
// Include args where mask is 0 (available/not yet claimed).
// mask[i] = 0 means available; mask[i] != 0 means already claimed.
if !is_masked(mask, idx) {
Some(MaskedArg {
raw: r,
raw_idx: idx,
})
} else {
None
}
})
.collect()
}
|