Skip to main content

bpaf/
structs.rs

1//! Structures that implement different methods on [`Parser`] trait
2use crate::{
3    args::State,
4    buffer::MetaInfo,
5    error::{Message, MissingItem},
6    Doc, Error, Meta, Parser,
7};
8use std::marker::PhantomData;
9
10/// Parser that substitutes missing value with a function results but not parser
11/// failure, created with [`fallback_with`](Parser::fallback_with).
12pub struct ParseFallbackWith<T, P, F, E> {
13    pub(crate) inner: P,
14    pub(crate) inner_res: PhantomData<T>,
15    pub(crate) fallback: F,
16    pub(crate) value_str: String,
17    pub(crate) err: PhantomData<E>,
18}
19
20impl<T, P, F, E> Parser<T> for ParseFallbackWith<T, P, F, E>
21where
22    P: Parser<T>,
23    F: Fn() -> Result<T, E>,
24    E: ToString,
25{
26    fn eval(&self, args: &mut State) -> Result<T, Error> {
27        let mut clone = args.clone();
28        match self.inner.eval(&mut clone) {
29            Ok(ok) => {
30                std::mem::swap(args, &mut clone);
31                Ok(ok)
32            }
33            Err(Error(e)) => {
34                #[cfg(feature = "autocomplete")]
35                args.swap_comps(&mut clone);
36                if e.can_catch() {
37                    match (self.fallback)() {
38                        Ok(ok) => Ok(ok),
39                        Err(e) => Err(Error(Message::PureFailed(e.to_string()))),
40                    }
41                } else {
42                    Err(Error(e))
43                }
44            }
45        }
46    }
47
48    fn meta(&self) -> Meta {
49        let m = Meta::Optional(Box::new(self.inner.meta()));
50        if self.value_str.is_empty() {
51            m
52        } else {
53            let buf = Doc::from(self.value_str.as_str());
54            Meta::Suffix(Box::new(m), Box::new(buf))
55        }
56    }
57}
58
59/// Parser with attached message to several fields, created with [`group_help`](Parser::group_help).
60pub struct ParseGroupHelp<P> {
61    pub(crate) inner: P,
62    pub(crate) message: Doc,
63}
64
65impl<T, P> Parser<T> for ParseGroupHelp<P>
66where
67    P: Parser<T>,
68{
69    fn eval(&self, args: &mut State) -> Result<T, Error> {
70        #[cfg(feature = "autocomplete")]
71        let mut comp_items = Vec::new();
72        #[cfg(feature = "autocomplete")]
73        args.swap_comps_with(&mut comp_items);
74
75        #[allow(clippy::let_and_return)]
76        let res = self.inner.eval(args);
77
78        #[cfg(feature = "autocomplete")]
79        args.swap_comps_with(&mut comp_items);
80        #[cfg(feature = "autocomplete")]
81        args.push_with_group(&self.message.to_completion(), &mut comp_items);
82
83        res
84    }
85
86    fn meta(&self) -> Meta {
87        let meta = Box::new(self.inner.meta());
88        Meta::Subsection(meta, Box::new(self.message.clone()))
89    }
90}
91
92/// Parser with attached message to several fields, created with [`group_help`](Parser::group_help).
93pub struct ParseWithGroupHelp<P, F> {
94    pub(crate) inner: P,
95    pub(crate) f: F,
96}
97
98impl<T, P, F> Parser<T> for ParseWithGroupHelp<P, F>
99where
100    P: Parser<T>,
101    F: Fn(MetaInfo) -> Doc,
102{
103    fn eval(&self, args: &mut State) -> Result<T, Error> {
104        self.inner.eval(args)
105    }
106
107    fn meta(&self) -> Meta {
108        let meta = self.inner.meta();
109        let buf = (self.f)(MetaInfo(&meta));
110
111        Meta::Subsection(Box::new(meta), Box::new(buf))
112    }
113}
114
115/// Apply inner parser several times and collect results into `Vec`, created with
116/// [`some`](Parser::some), requires for at least one item to be available to succeed.
117/// Implements [`catch`](ParseMany::catch)
118pub struct ParseSome<P> {
119    pub(crate) inner: P,
120    pub(crate) message: &'static str,
121    pub(crate) catch: bool,
122}
123
124impl<P> ParseSome<P> {
125    #[must_use]
126    /// Handle parse failures
127    ///
128    /// Can be useful to decide to skip parsing of some items on a command line
129    /// When parser succeeds - `catch` version would return a value as usual
130    /// if it fails - `catch` would restore all the consumed values and return None.
131    ///
132    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
133    /// and [`ParseSome`], behavior should be identical for all of them.
134    #[cfg_attr(not(doctest), doc = include_str!("docs2/some_catch.md"))]
135    pub fn catch(mut self) -> Self {
136        self.catch = true;
137        self
138    }
139}
140
141impl<T, P> Parser<Vec<T>> for ParseSome<P>
142where
143    P: Parser<T>,
144{
145    fn eval(&self, args: &mut State) -> Result<Vec<T>, Error> {
146        let mut res = Vec::new();
147        let mut len = usize::MAX;
148
149        while let Some(val) = parse_option(&self.inner, &mut len, args, self.catch)? {
150            res.push(val);
151        }
152
153        if res.is_empty() {
154            Err(Error(Message::ParseSome(self.message)))
155        } else {
156            Ok(res)
157        }
158    }
159
160    fn meta(&self) -> Meta {
161        Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
162    }
163}
164
165/// Apply inner parser several times and collect results into `FromIterator`, created with
166/// [`collect`](Parser::collect),
167/// Implements [`catch`](ParseCollect::catch)
168pub struct ParseCollect<P, C, T> {
169    pub(crate) inner: P,
170    pub(crate) catch: bool,
171    pub(crate) ctx: PhantomData<(C, T)>,
172}
173
174impl<T, C, P> ParseCollect<P, C, T> {
175    #[must_use]
176    /// Handle parse failures
177    ///
178    /// Can be useful to decide to skip parsing of some items on a command line
179    /// When parser succeeds - `catch` version would return a value as usual
180    /// if it fails - `catch` would restore all the consumed values and return None.
181    ///
182    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
183    /// and [`ParseSome`], behavior should be identical for all of them.
184    #[cfg_attr(not(doctest), doc = include_str!("docs2/some_catch.md"))]
185    pub fn catch(mut self) -> Self {
186        self.catch = true;
187        self
188    }
189}
190
191impl<T, C, P> Parser<C> for ParseCollect<P, C, T>
192where
193    P: Parser<T>,
194    C: FromIterator<T>,
195{
196    fn eval(&self, args: &mut State) -> Result<C, Error> {
197        let mut len = usize::MAX;
198        std::iter::from_fn(|| parse_option(&self.inner, &mut len, args, self.catch).transpose())
199            .collect::<Result<C, Error>>()
200    }
201
202    fn meta(&self) -> Meta {
203        Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
204    }
205}
206
207/// Parser that returns results as usual but not shown in `--help` output, created with
208/// [`Parser::hide`]
209pub struct ParseHide<P> {
210    pub(crate) inner: P,
211}
212
213impl<T, P> Parser<T> for ParseHide<P>
214where
215    P: Parser<T>,
216{
217    fn eval(&self, args: &mut State) -> Result<T, Error> {
218        #[cfg(feature = "autocomplete")]
219        let mut comps = Vec::new();
220
221        #[cfg(feature = "autocomplete")]
222        args.swap_comps_with(&mut comps);
223
224        #[allow(clippy::let_and_return)]
225        let res = self.inner.eval(args);
226
227        #[cfg(feature = "autocomplete")]
228        args.swap_comps_with(&mut comps);
229        if let Err(Error(Message::Missing(_))) = res {
230            Err(Error(Message::Missing(Vec::new())))
231        } else {
232            res
233        }
234    }
235
236    fn meta(&self) -> Meta {
237        Meta::Skip
238    }
239}
240
241/// Parser that hides inner parser from usage line
242///
243/// No other changes to the inner parser
244pub struct ParseUsage<P> {
245    pub(crate) inner: P,
246    pub(crate) usage: Doc,
247}
248impl<T, P> Parser<T> for ParseUsage<P>
249where
250    P: Parser<T>,
251{
252    fn eval(&self, args: &mut State) -> Result<T, Error> {
253        self.inner.eval(args)
254    }
255
256    fn meta(&self) -> Meta {
257        Meta::CustomUsage(Box::new(self.inner.meta()), Box::new(self.usage.clone()))
258    }
259}
260
261/// Parser that tries to either of two parsers and uses one that succeeeds, created with
262/// [`Parser::or_else`].
263pub struct ParseOrElse<T> {
264    pub(crate) this: Box<dyn Parser<T>>,
265    pub(crate) that: Box<dyn Parser<T>>,
266}
267
268impl<T> Parser<T> for ParseOrElse<T> {
269    fn eval(&self, args: &mut State) -> Result<T, Error> {
270        #[cfg(feature = "autocomplete")]
271        let mut comp_items = Vec::new();
272        #[cfg(feature = "autocomplete")]
273        args.swap_comps_with(&mut comp_items);
274
275        // create forks for both branches
276        // if they both fail - fallback to the original arguments
277        // if they both succed - pick the one that consumes left, remember the second one
278        // if one succeeds - pick that, forget the remaining one unless we are doing completion
279        let mut args_a = args.clone();
280        let mut args_b = args.clone();
281
282        // run both parsers, expand Result<T, Error> into Option<T> + Option<Error>
283        // so that code that does a bunch of comparing logic can be shared across
284        // all invocations of parsers rather than being inlined into each one.
285
286        let (res_a, err_a) = match self.this.eval(&mut args_a) {
287            Ok(ok) => (Some(ok), None),
288            Err(err) => (None, Some(err)),
289        };
290
291        let (res_b, err_b) = match self.that.eval(&mut args_b) {
292            Ok(ok) => (Some(ok), None),
293            Err(err) => (None, Some(err)),
294        };
295
296        if this_or_that_picks_first(
297            err_a,
298            err_b,
299            args,
300            &mut args_a,
301            &mut args_b,
302            #[cfg(feature = "autocomplete")]
303            comp_items,
304        )? {
305            Ok(res_a.unwrap())
306        } else {
307            Ok(res_b.unwrap())
308        }
309    }
310
311    fn meta(&self) -> Meta {
312        self.this.meta().or(self.that.meta())
313    }
314}
315
316/// Given two possible errors along with to sets of arguments produce a new error or an instruction
317/// to pick between two answers. Updates arguments state to match the results
318fn this_or_that_picks_first(
319    err_a: Option<Error>,
320    err_b: Option<Error>,
321    args: &mut State,
322    args_a: &mut State,
323    args_b: &mut State,
324
325    #[cfg(feature = "autocomplete")] mut comp_stash: Vec<crate::complete_gen::Comp>,
326) -> Result<bool, Error> {
327    // if higher depth parser succeeds - it takes a priority
328    // completion from different depths should never mix either
329    match Ord::cmp(&args_a.depth(), &args_b.depth()) {
330        std::cmp::Ordering::Less => {
331            std::mem::swap(args, args_b);
332            #[cfg(feature = "autocomplete")]
333            if let Some(comp) = args.comp_mut() {
334                comp.extend_comps(comp_stash);
335            }
336            return match err_b {
337                Some(err) => Err(err),
338                None => Ok(false),
339            };
340        }
341        std::cmp::Ordering::Equal => {}
342        std::cmp::Ordering::Greater => {
343            std::mem::swap(args, args_a);
344            #[cfg(feature = "autocomplete")]
345            if let Some(comp) = args.comp_mut() {
346                comp.extend_comps(comp_stash);
347            }
348            return match err_a {
349                Some(err) => Err(err),
350                None => Ok(true),
351            };
352        }
353    }
354
355    let no_consume_a = args.len() == args_a.len();
356    let no_consume_b = args.len() == args_b.len();
357    // otherwise, pick based on the left most or successful one
358    #[allow(clippy::let_and_return)] // <- it is without autocomplete only
359    let res = match (err_a, err_b) {
360        (None, None) => {
361            if no_consume_a && no_consume_b {
362                Ok((true, None))
363            } else {
364                Ok(args_a.pick_winner(args_b))
365            }
366        }
367        // non consuming parsers should not take priority
368        (None, Some(e2)) if no_consume_a && e2.0.wrong_input() => Err(e2),
369        (Some(e1), None) if no_consume_b && e1.0.wrong_input() => Err(e1),
370        (Some(e1), Some(e2)) => Err(e1.combine_with(e2)),
371        // otherwise, either `a` or `b` are success, `true` means `a` is success
372        (a_ok, _) => Ok((a_ok.is_none(), None)),
373    };
374
375    #[cfg(feature = "autocomplete")]
376    {
377        let mut keep_a = true;
378        let mut keep_b = true;
379        if args_a.len() != args_b.len() {
380            // If neither parser consumed anything - both can produce valid completions, otherwise
381            // look for the first "significant" consume and keep that parser
382            //
383            // This is needed to preserve completion from a choice between a positional and a flag
384            // See https://github.com/pacak/bpaf/issues/303 for more details
385            if let (Some(_), Some(_)) = (args_a.comp_mut(), args_b.comp_mut()) {
386                'check: for (ix, arg) in args_a.items.iter().enumerate() {
387                    // During completion process named and unnamed arguments behave
388                    // different - `-` and `--` are positional arguments, but we want to produce
389                    // named items too. An empty string is also a special type of item that
390                    // gets passed when user starts completion without passing any actual data.
391                    //
392                    // All other strings are either valid named items or valid positional items
393                    // those are hopefully follow the right logic for being parsed/not parsed
394                    if ix + 1 == args_a.items.len() {
395                        let os = arg.os_str();
396                        if os.is_empty() || os == "-" || os == "--" {
397                            break 'check;
398                        }
399                    }
400                    if let (Some(a), Some(b)) = (args_a.present(ix), args_b.present(ix)) {
401                        match (a, b) {
402                            (false, true) => {
403                                keep_b = false;
404                                break 'check;
405                            }
406                            (true, false) => {
407                                keep_a = false;
408                                break 'check;
409                            }
410                            _ => {}
411                        }
412                    }
413                }
414            }
415        }
416
417        if let (Some(a), Some(b)) = (args_a.comp_mut(), args_b.comp_mut()) {
418            if keep_a {
419                comp_stash.extend(a.drain_comps());
420            }
421            if keep_b {
422                comp_stash.extend(b.drain_comps());
423            }
424        }
425    }
426
427    match res {
428        Ok((true, ix)) => {
429            if let Some(win) = ix {
430                args_a.save_conflicts(args_b, win);
431            }
432            std::mem::swap(args, args_a);
433        }
434        Ok((false, ix)) => {
435            if let Some(win) = ix {
436                args_b.save_conflicts(args_a, win);
437            }
438            std::mem::swap(args, args_b);
439        }
440        // no winner, keep the completions but don't touch args otherwise
441        Err(_) => {}
442    }
443
444    #[cfg(feature = "autocomplete")]
445    if let Some(comp) = args.comp_mut() {
446        comp.extend_comps(comp_stash);
447    }
448
449    Ok(res?.0)
450}
451
452/// Parser that transforms parsed value with a failing function, created with
453/// [`parse`](Parser::parse)
454pub struct ParseWith<T, P, F, E, R> {
455    pub(crate) inner: P,
456    pub(crate) inner_res: PhantomData<T>,
457    pub(crate) parse_fn: F,
458    pub(crate) res: PhantomData<R>,
459    pub(crate) err: PhantomData<E>,
460}
461
462impl<T, P, F, E, R> Parser<R> for ParseWith<T, P, F, E, R>
463where
464    P: Parser<T>,
465    F: Fn(T) -> Result<R, E>,
466    E: ToString,
467{
468    fn eval(&self, args: &mut State) -> Result<R, Error> {
469        let t = self.inner.eval(args)?;
470        match (self.parse_fn)(t) {
471            Ok(r) => Ok(r),
472            Err(e) => Err(Error(Message::ParseFailed(args.current, e.to_string()))),
473        }
474    }
475
476    fn meta(&self) -> Meta {
477        self.inner.meta()
478    }
479}
480
481/// Parser that substitutes missing value but not parse failure, created with
482/// [`fallback`](Parser::fallback).
483pub struct ParseFallback<P, T> {
484    pub(crate) inner: P,
485    pub(crate) value: T,
486    pub(crate) value_str: String,
487}
488
489impl<P, T> Parser<T> for ParseFallback<P, T>
490where
491    P: Parser<T>,
492    T: Clone,
493{
494    fn eval(&self, args: &mut State) -> Result<T, Error> {
495        let mut clone = args.clone();
496        match self.inner.eval(&mut clone) {
497            Ok(ok) => {
498                std::mem::swap(args, &mut clone);
499                Ok(ok)
500            }
501            Err(Error(e)) => {
502                #[cfg(feature = "autocomplete")]
503                args.swap_comps(&mut clone);
504                if e.can_catch() {
505                    Ok(self.value.clone())
506                } else {
507                    Err(Error(e))
508                }
509            }
510        }
511    }
512
513    fn meta(&self) -> Meta {
514        let m = Meta::Optional(Box::new(self.inner.meta()));
515        if self.value_str.is_empty() {
516            m
517        } else {
518            let buf = Doc::from(self.value_str.as_str());
519            Meta::Suffix(Box::new(m), Box::new(buf))
520        }
521    }
522}
523
524/// An implementation detail for [`ParseFallback::format_fallback`] and
525/// [`ParseFallbackWith::format_fallback`], to allow for custom fallback formatting.
526struct DisplayWith<'a, T, F>(&'a T, F);
527
528impl<'a, T, F: Fn(&'a T, &mut std::fmt::Formatter<'_>) -> std::fmt::Result> std::fmt::Display
529    for DisplayWith<'a, T, F>
530{
531    #[inline(always)]
532    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
533        let Self(value, display) = self;
534        display(value, f)
535    }
536}
537
538impl<P, T: std::fmt::Display> ParseFallback<P, T> {
539    /// Show [`fallback`](Parser::fallback) value in `--help` using [`Display`](std::fmt::Display)
540    /// representation
541    ///
542    #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback.md"))]
543    #[must_use]
544    pub fn display_fallback(mut self) -> Self {
545        self.value_str = format!("[default: {}]", self.value);
546        self
547    }
548}
549
550impl<P, T: std::fmt::Debug> ParseFallback<P, T> {
551    /// Show [`fallback`](Parser::fallback) value in `--help` using [`Debug`](std::fmt::Debug)
552    /// representation
553    ///
554    #[cfg_attr(not(doctest), doc = include_str!("docs2/deb_fallback_with.md"))]
555    #[must_use]
556    pub fn debug_fallback(mut self) -> Self {
557        self.value_str = format!("[default: {:?}]", self.value);
558        self
559    }
560}
561
562impl<P, T> ParseFallback<P, T> {
563    /// Show [`fallback`](Parser::fallback) value in `--help` using the provided formatting
564    /// function.
565    ///
566    #[cfg_attr(not(doctest), doc = include_str!("docs2/format_fallback.md"))]
567    #[must_use]
568    pub fn format_fallback(
569        mut self,
570        format: impl Fn(&T, &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
571    ) -> Self {
572        self.value_str = format!("[default: {}]", DisplayWith(&self.value, format));
573        self
574    }
575}
576
577impl<P, T: std::fmt::Display, F, E> ParseFallbackWith<T, P, F, E>
578where
579    F: Fn() -> Result<T, E>,
580{
581    /// Show [`fallback_with`](Parser::fallback_with) value in `--help` using [`Display`](std::fmt::Display)
582    /// representation
583    ///
584    /// If fallback function fails - no value will show up
585    ///
586    #[cfg_attr(not(doctest), doc = include_str!("docs2/dis_fallback_with.md"))]
587    #[must_use]
588    pub fn display_fallback(mut self) -> Self {
589        if let Ok(val) = (self.fallback)() {
590            self.value_str = format!("[default: {}]", val);
591        }
592        self
593    }
594}
595
596impl<P, T: std::fmt::Debug, F, E> ParseFallbackWith<T, P, F, E>
597where
598    F: Fn() -> Result<T, E>,
599{
600    /// Show [`fallback_with`](Parser::fallback_with) value in `--help` using [`Debug`](std::fmt::Debug)
601    /// representation
602    ///
603    /// If fallback function fails - no value will show up
604    ///
605    #[cfg_attr(not(doctest), doc = include_str!("docs2/deb_fallback.md"))]
606    #[must_use]
607    pub fn debug_fallback(mut self) -> Self {
608        if let Ok(val) = (self.fallback)() {
609            self.value_str = format!("[default: {:?}]", val);
610        }
611        self
612    }
613}
614
615impl<P, T, F, E> ParseFallbackWith<T, P, F, E>
616where
617    F: Fn() -> Result<T, E>,
618{
619    /// Show [`fallback_with`](Parser::fallback_with) value in `--help` using the provided
620    /// formatting function.
621    ///
622    #[cfg_attr(not(doctest), doc = include_str!("docs2/format_fallback_with.md"))]
623    #[must_use]
624    pub fn format_fallback(
625        mut self,
626        format: impl Fn(&T, &mut std::fmt::Formatter<'_>) -> std::fmt::Result,
627    ) -> Self {
628        if let Ok(val) = (self.fallback)() {
629            self.value_str = format!("[default: {}]", DisplayWith(&val, format));
630        }
631        self
632    }
633}
634
635/// Parser fails with a message if check returns false, created with [`guard`](Parser::guard).
636pub struct ParseGuard<P, F> {
637    pub(crate) inner: P,
638    pub(crate) check: F,
639    pub(crate) message: &'static str,
640}
641
642impl<T, P, F> Parser<T> for ParseGuard<P, F>
643where
644    P: Parser<T>,
645    F: Fn(&T) -> bool,
646{
647    fn eval(&self, args: &mut State) -> Result<T, Error> {
648        let t = self.inner.eval(args)?;
649        if (self.check)(&t) {
650            Ok(t)
651        } else {
652            Err(Error(Message::GuardFailed(args.current, self.message)))
653        }
654    }
655
656    fn meta(&self) -> Meta {
657        self.inner.meta()
658    }
659}
660
661/// Apply inner parser as many times as it succeeds while consuming something and return this
662/// number
663pub struct ParseCount<P, T> {
664    pub(crate) inner: P,
665    pub(crate) ctx: PhantomData<T>,
666}
667
668impl<T, P> Parser<usize> for ParseCount<P, T>
669where
670    P: Parser<T>,
671{
672    fn eval(&self, args: &mut State) -> Result<usize, Error> {
673        let mut res = 0;
674        let mut current = args.len();
675        let mut len = usize::MAX;
676        while (parse_option(&self.inner, &mut len, args, false)?).is_some() {
677            res += 1;
678            if current == args.len() {
679                break;
680            }
681            current = args.len();
682        }
683        Ok(res)
684    }
685
686    fn meta(&self) -> Meta {
687        Meta::Many(Box::new(Meta::Optional(Box::new(self.inner.meta()))))
688    }
689}
690
691/// Apply inner parser as many times as it succeeds while consuming something and return this
692/// number
693pub struct ParseLast<P> {
694    pub(crate) inner: P,
695}
696
697impl<T, P> Parser<T> for ParseLast<P>
698where
699    P: Parser<T>,
700{
701    fn eval(&self, args: &mut State) -> Result<T, Error> {
702        let mut last = None;
703        let mut current = args.len();
704        let mut len = usize::MAX;
705        while let Some(val) = parse_option(&self.inner, &mut len, args, false)? {
706            last = Some(val);
707            if current == args.len() {
708                break;
709            }
710            current = args.len();
711        }
712        if let Some(last) = last {
713            Ok(last)
714        } else {
715            self.inner.eval(args)
716        }
717    }
718
719    fn meta(&self) -> Meta {
720        Meta::Many(Box::new(Meta::Required(Box::new(self.inner.meta()))))
721    }
722}
723
724/// Apply inner parser, return a value in `Some` if items requested by it are all present, restore
725/// and return `None` if any are missing. Created with [`optional`](Parser::optional). Implements
726/// [`catch`](ParseOptional::catch)
727pub struct ParseOptional<P> {
728    pub(crate) inner: P,
729    pub(crate) catch: bool,
730}
731
732impl<T, P> Parser<Option<T>> for ParseOptional<P>
733where
734    P: Parser<T>,
735{
736    fn eval(&self, args: &mut State) -> Result<Option<T>, Error> {
737        let mut len = usize::MAX;
738        parse_option(&self.inner, &mut len, args, self.catch)
739    }
740
741    fn meta(&self) -> Meta {
742        Meta::Optional(Box::new(self.inner.meta()))
743    }
744}
745
746impl<P> ParseOptional<P> {
747    #[must_use]
748    /// Handle parse failures for optional parsers
749    ///
750    /// Can be useful to decide to skip parsing of some items on a command line.
751    /// When parser succeeds - `catch` version would return a value as usual
752    /// if it fails - `catch` would restore all the consumed values and return None.
753    ///
754    /// `catch` won't catch errors related to partial/incomplete input, for example a named
755    /// argument that lacks a value (`--name` where parser expects `--name Alice`) or a positional
756    /// item that parser expects to be after `--`.
757    ///
758    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
759    /// and [`ParseSome`], behavior should be identical for all of them.
760    ///
761    /// Those examples are very artificial and designed to show what difference `catch` makes, to
762    /// actually parse arguments like in examples you should [`parse`](Parser::parse) or construct
763    /// enum with alternative branches
764    #[cfg_attr(not(doctest), doc = include_str!("docs2/optional_catch.md"))]
765    pub fn catch(mut self) -> Self {
766        self.catch = true;
767        self
768    }
769}
770
771/// Apply inner parser several times and collect results into `Vec`, created with
772/// [`many`](Parser::many), implements [`catch`](ParseMany::catch).
773pub struct ParseMany<P> {
774    pub(crate) inner: P,
775    pub(crate) catch: bool,
776}
777
778impl<P> ParseMany<P> {
779    #[must_use]
780    /// Handle parse failures
781    ///
782    /// Can be useful to decide to skip parsing of some items on a command line
783    /// When parser succeeds - `catch` version would return a value as usual
784    /// if it fails - `catch` would restore all the consumed values and return None.
785    ///
786    /// There's several structures that implement this attribute: [`ParseOptional`], [`ParseMany`]
787    /// and [`ParseSome`], behavior should be identical for all of them.
788    #[cfg_attr(not(doctest), doc = include_str!("docs2/many_catch.md"))]
789    pub fn catch(mut self) -> Self {
790        self.catch = true;
791        self
792    }
793}
794
795/// try to parse
796fn parse_option<P, T>(
797    parser: &P,
798    len: &mut usize,
799    args: &mut State,
800    mut catch: bool,
801) -> Result<Option<T>, Error>
802where
803    P: Parser<T>,
804{
805    let mut orig_args = args.clone();
806    match parser.eval(args) {
807        // we keep including values for as long as we consume values from the argument
808        // list or at least one value
809        Ok(val) => Ok(if args.len() < *len {
810            *len = args.len();
811            Some(val)
812        } else {
813            None
814        }),
815        Err(Error(err)) => {
816            // this is safe to return Ok(None) in following scenarios
817            // when inner parser never consumed anything and
818            // 1. produced Error::Missing
819            // 2. produced Error::Message(_, true)
820            // 3. produced Error::Message and catch is enabled
821            //
822            // In all other scenarios we should return the original error
823            //
824            // When parser returns Ok(None) we should return the original arguments so if there's
825            // anything left unconsumed - this won't be lost.
826
827            let missing = matches!(err, Message::Missing(_));
828
829            catch &= !err.wrong_input();
830
831            if catch || (missing && orig_args.len() == args.len()) || (!missing && err.can_catch())
832            {
833                std::mem::swap(&mut orig_args, args);
834                #[cfg(feature = "autocomplete")]
835                if orig_args.comp_mut().is_some() {
836                    args.swap_comps(&mut orig_args);
837                }
838                Ok(None)
839            } else {
840                Err(Error(err))
841            }
842        }
843    }
844}
845
846impl<T, P> Parser<Vec<T>> for ParseMany<P>
847where
848    P: Parser<T>,
849{
850    fn eval(&self, args: &mut State) -> Result<Vec<T>, Error> {
851        let mut len = usize::MAX;
852        std::iter::from_fn(|| parse_option(&self.inner, &mut len, args, self.catch).transpose())
853            .collect::<Result<Vec<T>, Error>>()
854    }
855
856    fn meta(&self) -> Meta {
857        Meta::Many(Box::new(Meta::Optional(Box::new(self.inner.meta()))))
858    }
859}
860
861/// Parser that returns a given value without consuming anything, created with
862/// [`pure`](crate::pure).
863pub struct ParsePure<T>(pub(crate) T);
864impl<T: Clone + 'static> Parser<T> for ParsePure<T> {
865    fn eval(&self, args: &mut State) -> Result<T, Error> {
866        args.current = None;
867        Ok(self.0.clone())
868    }
869
870    fn meta(&self) -> Meta {
871        Meta::Skip
872    }
873}
874
875pub struct ParsePureWith<T, F, E>(pub(crate) F)
876where
877    F: Fn() -> Result<T, E>,
878    E: ToString;
879impl<T: Clone + 'static, F: Fn() -> Result<T, E>, E: ToString> Parser<T>
880    for ParsePureWith<T, F, E>
881{
882    fn eval(&self, _args: &mut State) -> Result<T, Error> {
883        match (self.0)() {
884            Ok(ok) => Ok(ok),
885            Err(e) => Err(Error(Message::PureFailed(e.to_string()))),
886        }
887    }
888
889    fn meta(&self) -> Meta {
890        Meta::Skip
891    }
892}
893
894/// Parser that fails without consuming any input, created with [`fail`](crate::fail).
895pub struct ParseFail<T> {
896    pub(crate) field1: &'static str,
897    pub(crate) field2: PhantomData<T>,
898}
899impl<T> Parser<T> for ParseFail<T> {
900    fn eval(&self, args: &mut State) -> Result<T, Error> {
901        args.current = None;
902        Err(Error(Message::ParseFail(self.field1)))
903    }
904
905    fn meta(&self) -> Meta {
906        Meta::Skip
907    }
908}
909
910/// Parser that transforms parsed value with a function, created with [`map`](Parser::map).
911pub struct ParseMap<T, P, F, R> {
912    pub(crate) inner: P,
913    pub(crate) inner_res: PhantomData<T>,
914    pub(crate) map_fn: F,
915    pub(crate) res: PhantomData<R>,
916}
917impl<P, T, F, R> Parser<R> for ParseMap<T, P, F, R>
918where
919    F: Fn(T) -> R,
920    P: Parser<T> + Sized,
921{
922    fn eval(&self, args: &mut State) -> Result<R, Error> {
923        let t = self.inner.eval(args)?;
924        Ok((self.map_fn)(t))
925    }
926
927    fn meta(&self) -> Meta {
928        self.inner.meta()
929    }
930}
931
932/// Create parser from a function, [`construct!`](crate::construct!) uses it internally
933pub struct ParseCon<P> {
934    /// inner parser closure
935    pub inner: P,
936    /// metas for inner parsers
937    pub meta: Meta,
938    /// To produce a better error messages while parsing constructed values
939    /// we want to look at all the items so values that can be consumed are consumed
940    /// autocomplete relies on the same logic
941    ///
942    /// However when dealing with adjacent restriction detecting the first item relies on failing
943    /// fast
944    pub failfast: bool,
945}
946
947impl<T, P> Parser<T> for ParseCon<P>
948where
949    P: Fn(bool, &mut State) -> Result<T, Error>,
950{
951    fn eval(&self, args: &mut State) -> Result<T, Error> {
952        let res = (self.inner)(self.failfast, args);
953        args.current = None;
954        res
955    }
956
957    fn meta(&self) -> Meta {
958        self.meta.clone()
959    }
960}
961
962impl<T> ParseCon<T> {
963    #[must_use]
964    /// Automagically restrict the inner parser scope to accept adjacent values only
965    ///
966    /// `adjacent` can solve surprisingly wide variety of problems: sequential command chaining,
967    /// multi-value arguments, option-structs to name a few. If you want to run a parser on a
968    /// sequential subset of arguments - `adjacent` might be able to help you. Check the examples
969    /// for better intuition.
970    ///
971    /// Let's consider two examples with consumed items marked in bold and constructor containing
972    /// parsers for `-c` and `-d`.
973    ///
974    /// - <code>**-a** -b **-c** -d</code>
975    /// - <code>**-a** **-c** -b -d</code>
976    ///
977    /// In the first example `-b` breaks the adjacency for all the consumed items so parsing will fail,
978    /// while here in the second one all the consumed items are adjacent to each other so
979    /// parsing will succeed.
980    ///
981    /// # Multi-value arguments
982    ///
983    /// Parsing things like `--point X Y Z`
984    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_0.md"))]
985    ///
986    /// # Structure groups
987    ///
988    /// Parsing things like `--rect --width W --height H --rect --height H --width W`
989    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_1.md"))]
990    ///
991    /// # Chaining commands
992    /// This example explains [`adjacent`](crate::params::ParseCommand::adjacent), but the same idea holds.
993    /// Parsing things like `cmd1 --arg1 cmd2 --arg2 --arg3 cmd3 --flag`
994    ///
995    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_command.md"))]
996    ///
997    /// # Capturing everything between markers
998    ///
999    /// Parsing things like `find . --exec foo {} -bar ; --more`
1000    ///
1001    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_3.md"))]
1002    ///
1003    /// # Multi-value arguments with optional flags
1004    ///
1005    /// Parsing things like `--foo ARG1 --flag --inner ARG2`
1006    ///
1007    /// So you can parse things while parsing things. Not sure why you might need this, but you can
1008    /// :)
1009    ///
1010    #[cfg_attr(not(doctest), doc = include_str!("docs2/adjacent_struct_4.md"))]
1011    ///
1012    /// # Performance and other considerations
1013    ///
1014    /// `bpaf` can run adjacently restricted parsers multiple times to refine the guesses. It's
1015    /// best not to have complex inter-fields verification since they might trip up the detection
1016    /// logic: instead of restricting, for example "sum of two fields to be 5 or greater" *inside* the
1017    /// `adjacent` parser, you can restrict it *outside*, once `adjacent` done the parsing.
1018    ///
1019    /// There's also similar method [`adjacent`](crate::parsers::ParseArgument) that allows to restrict argument
1020    /// parser to work only for arguments where both key and a value are in the same shell word:
1021    /// `-f=bar` or `-fbar`, but not `-f bar`.
1022    pub fn adjacent(mut self) -> ParseAdjacent<Self> {
1023        self.failfast = true;
1024        ParseAdjacent { inner: self }
1025    }
1026}
1027
1028/// Parser that replaces metavar placeholders with actual info in shell completion
1029#[cfg(feature = "autocomplete")]
1030pub struct ParseComp<P, F> {
1031    pub(crate) inner: P,
1032    pub(crate) op: F,
1033    pub(crate) group: Option<String>,
1034}
1035
1036#[cfg(feature = "autocomplete")]
1037impl<P, F> ParseComp<P, F> {
1038    #[must_use]
1039    /// Attach group name to parsed values
1040    pub fn group(mut self, group: impl Into<String>) -> Self {
1041        self.group = Some(group.into());
1042        self
1043    }
1044}
1045
1046#[cfg(feature = "autocomplete")]
1047impl<P, T, F, M> Parser<T> for ParseComp<P, F>
1048where
1049    P: Parser<T> + Sized,
1050    M: Into<String>,
1051    F: Fn(&T) -> Vec<(M, Option<M>)>,
1052{
1053    fn eval(&self, args: &mut State) -> Result<T, Error> {
1054        // stash old
1055        let mut comp_items = Vec::new();
1056        args.swap_comps_with(&mut comp_items);
1057
1058        let res = self.inner.eval(args);
1059
1060        // restore old, now metavars added by inner parser, if any, are in comp_items
1061        args.swap_comps_with(&mut comp_items);
1062
1063        if let Some(comp) = &mut args.comp_mut() {
1064            if res.is_err() {
1065                comp.extend_comps(comp_items);
1066                return res;
1067            }
1068        }
1069
1070        let res = res?;
1071
1072        // completion function generates suggestions based on the parsed inner value, for
1073        // that `res` must contain a parsed value
1074        let depth = args.depth();
1075        if let Some(comp) = &mut args.comp_mut() {
1076            for ci in comp_items {
1077                let is_meta = ci.is_metavar();
1078                if let Some(is_arg) = is_meta {
1079                    let suggestions = (self.op)(&res);
1080                    // strip metavar when completion makes a single good suggestion
1081                    if suggestions.len() != 1 {
1082                        comp.push_comp(ci);
1083                    }
1084                    for (replacement, description) in suggestions {
1085                        let group = self.group.clone();
1086                        comp.push_value(
1087                            replacement.into(),
1088                            description.map(Into::into),
1089                            group,
1090                            depth,
1091                            is_arg,
1092                        );
1093                    }
1094                } else {
1095                    comp.push_comp(ci);
1096                }
1097            }
1098        }
1099        Ok(res)
1100    }
1101
1102    fn meta(&self) -> Meta {
1103        self.inner.meta()
1104    }
1105}
1106
1107/*
1108#[cfg(feature = "autocomplete")]
1109pub struct ParseCompStyle<P> {
1110    pub(crate) inner: P,
1111    pub(crate) style: CompleteDecor,
1112}
1113
1114#[cfg(feature = "autocomplete")]
1115impl<P, T> Parser<T> for ParseCompStyle<P>
1116where
1117    P: Parser<T> + Sized,
1118{
1119    fn eval(&self, args: &mut State) -> Result<T, Error> {
1120        let mut comp_items = Vec::new();
1121        args.swap_comps_with(&mut comp_items);
1122        let res = self.inner.eval(args);
1123        args.swap_comps_with(&mut comp_items);
1124        args.extend_with_style(self.style, &mut comp_items);
1125        res
1126    }
1127
1128    fn meta(&self) -> Meta {
1129        self.inner.meta()
1130    }
1131}*/
1132
1133pub struct ParseAdjacent<P> {
1134    pub(crate) inner: P,
1135}
1136impl<P, T> Parser<T> for ParseAdjacent<P>
1137where
1138    P: Parser<T> + Sized,
1139{
1140    fn eval(&self, args: &mut State) -> Result<T, Error> {
1141        let original_scope = args.scope();
1142
1143        let first_item;
1144        let inner_meta = self.inner.meta();
1145        let mut best_error = if let Some(item) = Meta::first_item(&inner_meta) {
1146            first_item = item;
1147            let missing_item = MissingItem {
1148                item: item.clone(),
1149                position: original_scope.start,
1150                scope: original_scope.clone(),
1151            };
1152            Message::Missing(vec![missing_item])
1153        } else {
1154            unreachable!("bpaf usage BUG: adjacent should start with a required argument");
1155        };
1156        let mut best_args = args.clone();
1157        let mut best_consumed = 0;
1158
1159        for (start, width, mut this_arg) in args.ranges(first_item) {
1160            // since we only want to parse things to the right of the first item we perform
1161            // parsing in two passes:
1162            // - try to run the parser showing only single argument available at all the indices
1163            // - try to run the parser showing starting at that argument and to the right of it
1164            // this means constructing argument parsers from req flag and positional works as
1165            // expected:
1166            // consider examples "42 -n" and "-n 42"
1167            // without multi step approach first command line also parses into 42
1168            let mut scratch = this_arg.clone();
1169            scratch.set_scope(start..start + width);
1170            let before = scratch.len();
1171
1172            // nothing to consume, might as well skip this segment right now
1173            // it will most likely fail, but it doesn't matter, we are only looking for the
1174            // left most match
1175            if before == 0 {
1176                continue;
1177            }
1178
1179            let _ = self.inner.eval(&mut scratch);
1180
1181            if before == scratch.len() {
1182                // failed to consume anything which means we don't start parsing at this point
1183                continue;
1184            }
1185
1186            this_arg.set_scope(start..original_scope.end);
1187            let before = this_arg.len();
1188
1189            // values consumed by adjacent must be actually adjacent - if a scope contains
1190            // already parsed values inside we need to trim it
1191            if original_scope.end - start > before {
1192                this_arg.set_scope(this_arg.adjacently_available_from(start));
1193            }
1194
1195            loop {
1196                match self.inner.eval(&mut this_arg) {
1197                    Ok(res) => {
1198                        // there's a smaller adjacent scope, we must try it before returning.
1199                        if let Some(adj_scope) = this_arg.adjacent_scope(args) {
1200                            this_arg = args.clone();
1201                            this_arg.set_scope(adj_scope);
1202                        } else {
1203                            std::mem::swap(args, &mut this_arg);
1204                            args.set_scope(original_scope);
1205                            return Ok(res);
1206                        }
1207                    }
1208                    Err(Error(err)) => {
1209                        let consumed = before - this_arg.len();
1210                        if consumed > best_consumed {
1211                            best_consumed = consumed;
1212                            std::mem::swap(&mut best_args, &mut this_arg);
1213                            best_error = err;
1214                        }
1215                        break;
1216                    }
1217                }
1218            }
1219        }
1220
1221        std::mem::swap(args, &mut best_args);
1222        Err(Error(best_error))
1223    }
1224
1225    fn meta(&self) -> Meta {
1226        let meta = self.inner.meta();
1227        Meta::Adjacent(Box::new(meta))
1228    }
1229}
1230
1231impl<T> Parser<T> for Box<dyn Parser<T>> {
1232    fn eval(&self, args: &mut State) -> Result<T, Error> {
1233        self.as_ref().eval(args)
1234    }
1235    fn meta(&self) -> Meta {
1236        self.as_ref().meta()
1237    }
1238}