1use crate::{buffer::Doc, item::Item};
2
3#[doc(hidden)]
4#[derive(Clone, Debug)]
5pub enum Meta {
6 And(Vec<Meta>),
8 Or(Vec<Meta>),
10 Optional(Box<Meta>),
12 Required(Box<Meta>),
14 Adjacent(Box<Meta>),
16 Item(Box<Item>),
18 Many(Box<Meta>),
20 Subsection(Box<Meta>, Box<Doc>),
24 Suffix(Box<Meta>, Box<Doc>),
26 Skip,
28 CustomUsage(Box<Meta>, Box<Doc>),
30 Strict(Box<Meta>),
32}
33
34impl Default for Meta {
36 fn default() -> Self {
37 Meta::Skip
38 }
39}
40
41#[derive(Debug, Clone, Copy)]
46enum StrictNorm {
47 Pull,
49 Push,
50 Strip,
52}
53
54impl StrictNorm {
55 fn push(&mut self) {
56 match *self {
57 StrictNorm::Pull => *self = StrictNorm::Push,
58 StrictNorm::Push | StrictNorm::Strip => {}
59 }
60 }
61}
62
63impl Meta {
64 fn is_command(&self) -> bool {
67 match self {
68 Meta::Item(i) => matches!(i.as_ref(), Item::Command { .. }),
69 Meta::Subsection(m, _) => m.is_command(),
70 _ => false,
71 }
72 }
73
74 pub(crate) fn positional_invariant_check(&self, verbose: bool) {
76 fn go(meta: &Meta, is_pos: &mut bool, v: bool) {
77 match meta {
78 Meta::And(xs) => {
79 for x in xs {
80 go(x, is_pos, v);
81 }
82 }
83 Meta::Or(xs) => {
84 let mut out = *is_pos;
85 for x in xs {
86 let mut this_pos = *is_pos;
87 go(x, &mut this_pos, v);
88 out |= this_pos;
89 }
90 *is_pos = out;
91 }
92 Meta::Item(i) => {
93 match (*is_pos, i.is_pos()) {
94 (true, true) | (false, false) => {}
95 (true, false) => {
96 panic!("bpaf usage BUG: all positional and command items must be placed in the right \
97 most position of the structure or tuple they are in but {:?} breaks this rule. \
98 See bpaf documentation for `positional` for details.", i);
99 }
100 (false, true) => {
101 *is_pos = true;
102 }
103 }
104 if let Item::Command { meta, .. } = &**i {
105 let mut command_pos = false;
106 if v {
107 println!("Checking\n{:#?}", meta);
108 }
109 go(meta, &mut command_pos, v);
110 }
111 }
112 Meta::Adjacent(m) => {
113 if let Some(i) = Meta::first_item(m) {
114 if i.is_pos() {
115 go(m, is_pos, v);
116 } else {
117 let mut inner = false;
118 go(m, &mut inner, v);
119 }
120 }
121 }
122 Meta::Optional(m)
123 | Meta::Required(m)
124 | Meta::Many(m)
125 | Meta::CustomUsage(m, _)
126 | Meta::Subsection(m, _)
127 | Meta::Strict(m)
128 | Meta::Suffix(m, _) => go(m, is_pos, v),
129 Meta::Skip => {}
130 }
131 }
132 let mut is_pos = false;
133 if verbose {
134 println!("Checking\n{:#?}", self);
135 }
136 go(self, &mut is_pos, verbose);
137 }
138
139 pub(crate) fn normalized(&self, for_usage: bool) -> Meta {
140 let mut m = self.clone();
141 let mut norm = StrictNorm::Pull;
142 m.normalize(for_usage, &mut norm);
143 if let Meta::Required(i) = m {
145 m = *i;
146 }
147 if matches!(m, Meta::Or(_)) {
148 m = Meta::Required(Box::new(m));
149 }
150 if matches!(norm, StrictNorm::Push) {
151 m = Meta::Strict(Box::new(m));
152 }
153 m
154 }
155
156 pub(crate) fn first_item(meta: &Meta) -> Option<&Item> {
158 match meta {
159 Meta::And(xs) => xs.first().and_then(Self::first_item),
160 Meta::Item(item) => Some(item),
161 Meta::Skip | Meta::Or(_) => None,
162 Meta::Optional(x)
163 | Meta::Strict(x)
164 | Meta::Required(x)
165 | Meta::Adjacent(x)
166 | Meta::Many(x)
167 | Meta::Subsection(x, _)
168 | Meta::Suffix(x, _)
169 | Meta::CustomUsage(x, _) => Self::first_item(x),
170 }
171 }
172
173 fn normalize(&mut self, for_usage: bool, norm: &mut StrictNorm) {
175 fn normalize_vec(
176 xs: &mut Vec<Meta>,
177 for_usage: bool,
178 norm: &mut StrictNorm,
179 or: bool,
180 ) -> Option<Meta> {
181 let mut final_norm = *norm;
182 for m in xs.iter_mut() {
183 let mut this_norm = *norm;
184 m.normalize(for_usage, &mut this_norm);
185 let target: &mut StrictNorm = if or { &mut final_norm } else { norm };
186
187 match (*target, this_norm) {
188 (_, StrictNorm::Pull) | (StrictNorm::Strip, _) => {}
189 (StrictNorm::Pull, StrictNorm::Push) => {
190 *m = Meta::Strict(Box::new(std::mem::take(m)));
191 *target = StrictNorm::Strip;
192 }
193 _ => {
194 *target = this_norm;
195 }
196 }
197 }
198 xs.retain(|m| !matches!(m, Meta::Skip));
199
200 *norm = final_norm;
201
202 match xs.len() {
203 0 => Some(Meta::Skip),
204 1 => Some(xs.remove(0)),
205 _ => None,
206 }
207 }
208
209 match self {
210 Meta::And(xs) => {
211 if let Some(replacement) = normalize_vec(xs, for_usage, norm, false) {
212 *self = replacement;
213 }
214 }
215 Meta::Or(xs) => {
217 if let Some(replacement) = normalize_vec(xs, for_usage, norm, true) {
218 *self = replacement;
219 } else {
220 let mut saw_cmd = false;
221 xs.retain(|m| {
223 let is_cmd = m.is_command();
224 let keep = !(is_cmd && saw_cmd);
225 saw_cmd |= is_cmd;
226 keep
227 });
228 match xs.len() {
229 0 => *self = Meta::Skip,
230 1 => *self = xs.remove(0),
231 _ => *self = Meta::Required(Box::new(std::mem::take(self))),
232 }
233 }
234 }
235 Meta::Optional(m) => {
236 m.normalize(for_usage, norm);
237 if matches!(**m, Meta::Skip) {
238 *self = Meta::Skip;
240 } else if let Meta::Required(mm) | Meta::Optional(mm) = m.as_mut() {
241 *m = std::mem::take(mm);
244 } else if let Meta::Many(many) = m.as_mut() {
245 if let Meta::Required(x) = many.as_mut() {
247 *self = Meta::Many(Box::new(Meta::Optional(std::mem::take(x))));
248 }
249 }
250 }
251 Meta::Required(m) => {
252 m.normalize(for_usage, norm);
253 if matches!(**m, Meta::Skip) {
254 *self = Meta::Skip;
256 } else if matches!(**m, Meta::And(_) | Meta::Or(_)) {
257 } else {
259 *self = std::mem::take(m);
261 }
262 }
263 Meta::Many(m) => {
264 m.normalize(for_usage, norm);
265 if matches!(**m, Meta::Skip) {
266 *self = Meta::Skip;
267 }
268 }
269 Meta::Adjacent(m) | Meta::Subsection(m, _) | Meta::Suffix(m, _) => {
270 m.normalize(for_usage, norm);
271 *self = std::mem::take(m);
272 }
273 Meta::Item(i) => i.normalize(for_usage),
274 Meta::Skip => {
275 }
277 Meta::CustomUsage(m, u) => {
278 m.normalize(for_usage, norm);
279 if for_usage {
281 if u.is_empty() {
282 *self = Meta::Skip;
283 }
284 } else {
285 *self = std::mem::take(m);
286 }
287 }
288 Meta::Strict(m) => {
289 m.normalize(for_usage, norm);
290 norm.push();
291 *self = std::mem::take(m);
292 }
293 }
294 }
295}
296
297impl From<Item> for Meta {
298 fn from(value: Item) -> Self {
299 Meta::Item(Box::new(value))
300 }
301}
302
303impl Meta {
304 fn alts(self, to: &mut Vec<Meta>) {
305 match self {
306 Meta::Or(mut xs) => to.append(&mut xs),
307 Meta::Skip => {}
308 meta => to.push(meta),
309 }
310 }
311
312 pub(crate) fn or(self, other: Meta) -> Self {
313 let mut res = Vec::new();
314 self.alts(&mut res);
315 other.alts(&mut res);
316 match res.len() {
317 0 => Meta::Skip,
318 1 => res.remove(0),
319 _ => Meta::Or(res),
320 }
321 }
322
323 pub(crate) fn collect_shorts(&self, flags: &mut Vec<char>, args: &mut Vec<char>) {
325 match self {
326 Meta::And(xs) | Meta::Or(xs) => {
327 for x in xs {
328 x.collect_shorts(flags, args);
329 }
330 }
331 Meta::Item(m) => match &**m {
332 Item::Any { .. } | Item::Positional { .. } => {}
333 Item::Command { meta, .. } => {
334 meta.collect_shorts(flags, args);
335 }
336 Item::Flag { shorts, .. } => flags.extend(shorts),
337 Item::Argument { shorts, .. } => args.extend(shorts),
338 },
339 Meta::CustomUsage(m, _)
340 | Meta::Required(m)
341 | Meta::Optional(m)
342 | Meta::Adjacent(m)
343 | Meta::Subsection(m, _)
344 | Meta::Suffix(m, _)
345 | Meta::Many(m) => {
346 m.collect_shorts(flags, args);
347 }
348 Meta::Skip | Meta::Strict(_) => {}
349 }
350 }
351}