Skip to main content

simon/
lib.rs

1use std::env;
2use std::ffi::OsStr;
3use std::fmt;
4use std::process;
5use std::str::FromStr;
6
7mod util;
8mod validation;
9pub use util::Never;
10pub use validation::Invalid;
11
12pub type Matches = getopts::Matches;
13
14#[derive(Hash, PartialEq, Eq, Clone, Debug)]
15pub struct SwitchCommon {
16    pub short: String,
17    pub long: String,
18    pub doc: String,
19}
20
21impl SwitchCommon {
22    fn new(short: &str, long: &str, doc: &str) -> Self {
23        Self {
24            short: short.to_string(),
25            long: long.to_string(),
26            doc: doc.to_string(),
27        }
28    }
29
30    fn key_to_search_in_matches(&self) -> &str {
31        if self.short.len() != 0 {
32            self.short.as_str()
33        } else {
34            self.long.as_str()
35        }
36    }
37}
38
39#[derive(Hash, PartialEq, Eq, Clone, Debug)]
40pub enum SwitchShape {
41    Flag,
42    Opt { hint: String },
43}
44
45pub trait Switches {
46    fn add(&mut self, common: SwitchCommon, shape: SwitchShape);
47}
48
49impl Switches for getopts::Options {
50    fn add(&mut self, common: SwitchCommon, shape: SwitchShape) {
51        match shape {
52            SwitchShape::Flag => {
53                self.optflag(
54                    common.short.as_str(),
55                    common.long.as_str(),
56                    common.doc.as_str(),
57                );
58            }
59            SwitchShape::Opt { hint } => {
60                self.optopt(
61                    common.short.as_str(),
62                    common.long.as_str(),
63                    common.doc.as_str(),
64                    hint.as_str(),
65                );
66            }
67        }
68    }
69}
70
71#[derive(Debug)]
72pub enum TopLevelError<E> {
73    Getopts(getopts::Fail),
74    Other(E),
75}
76
77impl<E: fmt::Display> fmt::Display for TopLevelError<E> {
78    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
79        match self {
80            Self::Getopts(fail) => fmt::Display::fmt(&fail, f),
81            Self::Other(other) => fmt::Display::fmt(&other, f),
82        }
83    }
84}
85
86pub struct Usage {
87    opts: getopts::Options,
88    program_name: String,
89}
90
91impl Usage {
92    pub fn render(&self) -> String {
93        let brief = format!("Usage: {} [options]", &self.program_name);
94        self.opts.usage(&brief)
95    }
96}
97
98pub struct ParseResult<I, E> {
99    pub usage: Usage,
100    pub result: Result<I, TopLevelError<E>>,
101}
102
103pub trait Arg: Sized {
104    type Item;
105    type Error: fmt::Debug + fmt::Display;
106    fn update_switches<S: Switches>(&self, switches: &mut S);
107    fn name(&self) -> String;
108    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error>;
109    fn validate(&self) -> Result<(), Invalid> {
110        let mut checker = validation::Checker::default();
111        self.update_switches(&mut checker);
112        if let Some(invalid) = checker.invalid() {
113            Err(invalid)
114        } else {
115            Ok(())
116        }
117    }
118    fn parse_specified_ignoring_validation<I>(
119        self,
120        program_name: String,
121        args: I,
122    ) -> ParseResult<Self::Item, Self::Error>
123    where
124        I: IntoIterator,
125        I::Item: AsRef<OsStr>,
126    {
127        let mut opts = getopts::Options::new();
128        self.update_switches(&mut opts);
129        ParseResult {
130            result: opts
131                .parse(args)
132                .map_err(TopLevelError::Getopts)
133                .and_then(|matches| self.get(&matches).map_err(TopLevelError::Other)),
134            usage: Usage { opts, program_name },
135        }
136    }
137    fn parse_specified<I>(
138        self,
139        program_name: String,
140        args: I,
141    ) -> ParseResult<Self::Item, Self::Error>
142    where
143        I: IntoIterator,
144        I::Item: AsRef<OsStr>,
145    {
146        if let Err(invalid) = self.validate() {
147            panic!("Invalid command spec:\n{}", invalid);
148        }
149        self.parse_specified_ignoring_validation(program_name, args)
150    }
151    fn parse_env(self) -> ParseResult<Self::Item, Self::Error> {
152        let args = env::args().collect::<Vec<_>>();
153        let program_name = args[0].clone();
154        self.parse_specified(program_name, &args[1..])
155    }
156    fn with_help(self, help_flag: Flag) -> WithHelp<Self> {
157        WithHelp {
158            arg: self,
159            help_flag,
160        }
161    }
162    fn with_help_default(self) -> WithHelp<Self> {
163        self.with_help(Flag::new("h", "help", "print this help menu"))
164    }
165    fn option_map<F, T, U>(self, f: F) -> OptionMap<Self, F>
166    where
167        F: FnOnce(T) -> U,
168    {
169        OptionMap { arg: self, f }
170    }
171    fn with_default<T>(self, default_value: T) -> WithDefault<Self, T> {
172        WithDefault {
173            arg: self,
174            default_value,
175        }
176    }
177    fn with_default_lazy<F>(self, default_value_f: F) -> WithDefaultLazy<Self, F> {
178        WithDefaultLazy {
179            arg: self,
180            default_value_f,
181        }
182    }
183    fn choice<O>(self, other: O) -> Choice<Self, O>
184    where
185        O: Arg<Item = Self::Item>,
186    {
187        Choice { a: self, b: other }
188    }
189    fn both<O>(self, other: O) -> Both<Self, O>
190    where
191        O: Arg,
192    {
193        Both { a: self, b: other }
194    }
195    fn map<F, U>(self, f: F) -> Map<Self, F>
196    where
197        F: FnOnce(Self::Item) -> U,
198    {
199        Map { arg: self, f }
200    }
201    fn required(self) -> Required<Self> {
202        Required { arg: self }
203    }
204    fn convert_string<F, T, E>(self, f: F) -> ConvertString<Self, F>
205    where
206        F: FnOnce(&str) -> Result<T, E>,
207    {
208        ConvertString { arg: self, f }
209    }
210    fn option_convert_string<F, T, E>(self, f: F) -> OptionConvertString<Self, F>
211    where
212        F: FnOnce(&str) -> Result<T, E>,
213    {
214        OptionConvertString { arg: self, f }
215    }
216    fn vec_convert_string<F, T, E>(self, f: F) -> VecConvertString<Self, F>
217    where
218        F: FnMut(&str) -> Result<T, E>,
219    {
220        VecConvertString { arg: self, f }
221    }
222    fn vec_singleton(self) -> VecSingleton<Self> {
223        VecSingleton { arg: self }
224    }
225    fn depend<O>(self, other: O) -> Depend<Self, O>
226    where
227        O: Arg,
228    {
229        Depend { a: self, b: other }
230    }
231    fn some_if<T>(self, t: T) -> SomeIf<Self, T> {
232        SomeIf { arg: self, t }
233    }
234}
235
236pub struct Flag {
237    common: SwitchCommon,
238}
239
240impl Flag {
241    pub fn new(short: &str, long: &str, doc: &str) -> Self {
242        Self {
243            common: SwitchCommon::new(short, long, doc),
244        }
245    }
246}
247impl Arg for Flag {
248    type Item = bool;
249    type Error = Never;
250    fn update_switches<S: Switches>(&self, switches: &mut S) {
251        switches.add(self.common.clone(), SwitchShape::Flag);
252    }
253    fn name(&self) -> String {
254        self.common.long.clone()
255    }
256    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
257        Ok(matches.opt_present(self.common.key_to_search_in_matches()))
258    }
259}
260
261pub struct Opt {
262    common: SwitchCommon,
263    hint: String,
264}
265
266impl Opt {
267    pub fn new(short: &str, long: &str, doc: &str, hint: &str) -> Self {
268        Self {
269            common: SwitchCommon::new(short, long, doc),
270            hint: hint.to_string(),
271        }
272    }
273}
274
275impl Arg for Opt {
276    type Item = Option<String>;
277    type Error = Never;
278    fn update_switches<S: Switches>(&self, switches: &mut S) {
279        switches.add(
280            self.common.clone(),
281            SwitchShape::Opt {
282                hint: self.hint.clone(),
283            },
284        );
285    }
286    fn name(&self) -> String {
287        self.common.long.clone()
288    }
289    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
290        Ok(matches.opt_str(self.common.key_to_search_in_matches()))
291    }
292}
293
294pub struct Free;
295
296impl Arg for Free {
297    type Item = Vec<String>;
298    type Error = Never;
299    fn update_switches<S: Switches>(&self, _switches: &mut S) {}
300    fn name(&self) -> String {
301        "ARGS".to_string()
302    }
303    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
304        Ok(matches.free.clone())
305    }
306}
307
308pub struct WithHelp<A> {
309    arg: A,
310    help_flag: Flag,
311}
312
313pub enum OrHelp<T> {
314    Value(T),
315    Help,
316}
317
318impl<A> Arg for WithHelp<A>
319where
320    A: Arg,
321{
322    type Item = OrHelp<A::Item>;
323    type Error = A::Error;
324    fn update_switches<S: Switches>(&self, switches: &mut S) {
325        self.arg.update_switches(switches);
326        self.help_flag.update_switches(switches);
327    }
328    fn name(&self) -> String {
329        format!("({}) with help", self.arg.name())
330    }
331    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
332        if Never::result_ok(self.help_flag.get(matches)) {
333            Ok(OrHelp::Help)
334        } else {
335            self.arg.get(matches).map(OrHelp::Value)
336        }
337    }
338}
339
340impl<A> WithHelp<A>
341where
342    A: Arg,
343{
344    pub fn parse_env_or_exit(self) -> A::Item {
345        let ParseResult { result, usage } = self.parse_env();
346        match result {
347            Ok(OrHelp::Value(a)) => a,
348            Ok(OrHelp::Help) => {
349                print!("{}", usage.render());
350                process::exit(0);
351            }
352            Err(e) => {
353                eprint!("{}\n\n", e);
354                eprint!("{}", usage.render());
355                process::exit(1);
356            }
357        }
358    }
359}
360
361pub struct OptionMap<A, F>
362where
363    A: Arg,
364{
365    arg: A,
366    f: F,
367}
368
369impl<A, F, T, U> Arg for OptionMap<A, F>
370where
371    A: Arg<Item = Option<T>>,
372    F: FnOnce(T) -> U,
373{
374    type Item = Option<U>;
375    type Error = A::Error;
376    fn update_switches<S: Switches>(&self, switches: &mut S) {
377        self.arg.update_switches(switches);
378    }
379    fn name(&self) -> String {
380        self.arg.name()
381    }
382    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
383        let Self { arg, f } = self;
384        arg.get(matches).map(|x| x.map(f))
385    }
386}
387
388pub struct WithDefault<A, T>
389where
390    A: Arg,
391{
392    arg: A,
393    default_value: T,
394}
395
396impl<A, T> Arg for WithDefault<A, T>
397where
398    A: Arg<Item = Option<T>>,
399{
400    type Item = T;
401    type Error = A::Error;
402    fn update_switches<S: Switches>(&self, switches: &mut S) {
403        self.arg.update_switches(switches);
404    }
405    fn name(&self) -> String {
406        self.arg.name()
407    }
408    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
409        let Self { arg, default_value } = self;
410        arg.get(matches).map(|x| x.unwrap_or(default_value))
411    }
412}
413
414pub struct WithDefaultLazy<A, F>
415where
416    A: Arg,
417{
418    arg: A,
419    default_value_f: F,
420}
421
422impl<A, F, T> Arg for WithDefaultLazy<A, F>
423where
424    A: Arg<Item = Option<T>>,
425    F: FnOnce() -> T,
426{
427    type Item = T;
428    type Error = A::Error;
429    fn update_switches<S: Switches>(&self, switches: &mut S) {
430        self.arg.update_switches(switches);
431    }
432    fn name(&self) -> String {
433        self.arg.name()
434    }
435    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
436        let Self {
437            arg,
438            default_value_f,
439        } = self;
440        arg.get(matches).map(|x| x.unwrap_or_else(default_value_f))
441    }
442}
443
444pub struct Choice<A, B>
445where
446    A: Arg,
447    B: Arg,
448{
449    a: A,
450    b: B,
451}
452
453#[derive(Debug)]
454pub enum ChoiceError<A, B> {
455    A(A),
456    B(B),
457    MultipleMutuallyExclusiveArgs { a: String, b: String },
458}
459
460impl<A, B> fmt::Display for ChoiceError<A, B>
461where
462    A: fmt::Display,
463    B: fmt::Display,
464{
465    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
466        match self {
467            Self::A(a) => a.fmt(f),
468            Self::B(b) => b.fmt(f),
469            Self::MultipleMutuallyExclusiveArgs { a, b } => {
470                write!(f, "({}) and ({}) are mutually exclusive", a, b)
471            }
472        }
473    }
474}
475
476impl<A, B, T> Arg for Choice<A, B>
477where
478    A: Arg<Item = Option<T>>,
479    B: Arg<Item = Option<T>>,
480{
481    type Item = Option<T>;
482    type Error = ChoiceError<A::Error, B::Error>;
483
484    fn update_switches<S: Switches>(&self, switches: &mut S) {
485        self.a.update_switches(switches);
486        self.b.update_switches(switches);
487    }
488    fn name(&self) -> String {
489        format!("choose ({}) or ({})", self.a.name(), self.b.name())
490    }
491    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
492        let Self { a, b } = self;
493        let multiple_mutually_exclusive_args =
494            ChoiceError::MultipleMutuallyExclusiveArgs {
495                a: a.name(),
496                b: b.name(),
497            };
498
499        if let Some(a_value) = a.get(matches).map_err(ChoiceError::A)? {
500            if b.get(matches).map_err(ChoiceError::B)?.is_some() {
501                Err(multiple_mutually_exclusive_args)
502            } else {
503                Ok(Some(a_value))
504            }
505        } else {
506            b.get(matches).map_err(ChoiceError::B)
507        }
508    }
509}
510
511#[derive(Debug)]
512pub enum BothError<A, B> {
513    A(A),
514    B(B),
515}
516
517impl<A, B> fmt::Display for BothError<A, B>
518where
519    A: fmt::Display,
520    B: fmt::Display,
521{
522    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
523        match self {
524            Self::A(a) => a.fmt(f),
525            Self::B(b) => b.fmt(f),
526        }
527    }
528}
529
530pub struct Both<A, B>
531where
532    A: Arg,
533    B: Arg,
534{
535    a: A,
536    b: B,
537}
538
539impl<A, B> Arg for Both<A, B>
540where
541    A: Arg,
542    B: Arg,
543{
544    type Item = (A::Item, B::Item);
545    type Error = BothError<A::Error, B::Error>;
546    fn update_switches<S: Switches>(&self, switches: &mut S) {
547        self.a.update_switches(switches);
548        self.b.update_switches(switches);
549    }
550    fn name(&self) -> String {
551        format!("({} and {})", self.a.name(), self.b.name())
552    }
553    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
554        Ok((
555            self.a.get(matches).map_err(BothError::A)?,
556            self.b.get(matches).map_err(BothError::B)?,
557        ))
558    }
559}
560
561pub struct Map<A, F>
562where
563    A: Arg,
564{
565    arg: A,
566    f: F,
567}
568impl<A, U, F> Arg for Map<A, F>
569where
570    A: Arg,
571    F: FnOnce(A::Item) -> U,
572{
573    type Item = U;
574    type Error = A::Error;
575    fn update_switches<S: Switches>(&self, switches: &mut S) {
576        self.arg.update_switches(switches);
577    }
578    fn name(&self) -> String {
579        self.arg.name()
580    }
581    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
582        let Self { arg, f } = self;
583        arg.get(matches).map(f)
584    }
585}
586
587pub struct Value<T> {
588    value: T,
589    name: String,
590}
591
592impl<T> Value<T> {
593    pub fn new(name: &str, value: T) -> Self {
594        Self {
595            name: name.to_string(),
596            value,
597        }
598    }
599}
600
601impl<T> Arg for Value<T> {
602    type Item = T;
603    type Error = Never;
604    fn update_switches<S: Switches>(&self, _switches: &mut S) {}
605    fn name(&self) -> String {
606        self.name.clone()
607    }
608    fn get(self, _matches: &Matches) -> Result<Self::Item, Self::Error> {
609        Ok(self.value)
610    }
611}
612
613pub struct Required<A>
614where
615    A: Arg,
616{
617    arg: A,
618}
619
620#[derive(Debug)]
621pub enum RequiredError<A> {
622    Arg(A),
623    MissingRequiredArg { name: String },
624}
625
626impl<A> fmt::Display for RequiredError<A>
627where
628    A: fmt::Display,
629{
630    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
631        match self {
632            Self::Arg(a) => a.fmt(f),
633            Self::MissingRequiredArg { name } => {
634                write!(f, "missing required argument ({})", name)
635            }
636        }
637    }
638}
639
640impl<A, T> Arg for Required<A>
641where
642    A: Arg<Item = Option<T>>,
643{
644    type Item = T;
645    type Error = RequiredError<A::Error>;
646    fn update_switches<S: Switches>(&self, switches: &mut S) {
647        self.arg.update_switches(switches);
648    }
649    fn name(&self) -> String {
650        self.arg.name()
651    }
652    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
653        let name = self.arg.name();
654        if let Some(x) = self.arg.get(matches).map_err(RequiredError::Arg)? {
655            Ok(x)
656        } else {
657            Err(RequiredError::MissingRequiredArg { name })
658        }
659    }
660}
661
662pub struct ConvertString<A, F>
663where
664    A: Arg,
665{
666    arg: A,
667    f: F,
668}
669
670#[derive(Debug)]
671pub enum ConvertStringError<A, E> {
672    Arg(A),
673    FailedToConvert {
674        name: String,
675        arg_string: String,
676        error: E,
677    },
678}
679
680impl<A, E> fmt::Display for ConvertStringError<A, E>
681where
682    A: fmt::Display,
683    E: fmt::Display,
684{
685    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
686        match self {
687            Self::Arg(a) => a.fmt(f),
688            Self::FailedToConvert {
689                name,
690                arg_string,
691                error,
692            } => write!(
693                f,
694                "failed to convert argument ({}). \"{}\" could not be parsed (error: {})",
695                name, arg_string, error
696            ),
697        }
698    }
699}
700
701impl<A, F, T, E> Arg for ConvertString<A, F>
702where
703    A: Arg<Item = String>,
704    F: FnOnce(&str) -> Result<T, E>,
705    E: fmt::Display + fmt::Debug,
706{
707    type Item = T;
708    type Error = ConvertStringError<A::Error, E>;
709    fn update_switches<S: Switches>(&self, switches: &mut S) {
710        self.arg.update_switches(switches);
711    }
712    fn name(&self) -> String {
713        self.arg.name()
714    }
715    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
716        let name = self.name();
717        let Self { arg, f } = self;
718        let arg_string = arg.get(matches).map_err(ConvertStringError::Arg)?;
719        f(arg_string.as_str()).map_err(|error| ConvertStringError::FailedToConvert {
720            name,
721            arg_string,
722            error,
723        })
724    }
725}
726
727pub struct OptionConvertString<A, F>
728where
729    A: Arg,
730{
731    arg: A,
732    f: F,
733}
734
735#[derive(Debug)]
736pub enum OptionConvertStringError<A, E> {
737    Arg(A),
738    FailedToConvert {
739        name: String,
740        arg_string: String,
741        error: E,
742    },
743}
744
745impl<A, E> fmt::Display for OptionConvertStringError<A, E>
746where
747    A: fmt::Display,
748    E: fmt::Display,
749{
750    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
751        match self {
752            Self::Arg(a) => a.fmt(f),
753            Self::FailedToConvert {
754                name,
755                arg_string,
756                error,
757            } => write!(
758                f,
759                "failed to convert argument ({}). \"{}\" could not be parsed (error: {})",
760                name, arg_string, error
761            ),
762        }
763    }
764}
765
766impl<A, F, T, E> Arg for OptionConvertString<A, F>
767where
768    A: Arg<Item = Option<String>>,
769    F: FnOnce(&str) -> Result<T, E>,
770    E: fmt::Display + fmt::Debug,
771{
772    type Item = Option<T>;
773    type Error = OptionConvertStringError<A::Error, E>;
774    fn update_switches<S: Switches>(&self, switches: &mut S) {
775        self.arg.update_switches(switches);
776    }
777    fn name(&self) -> String {
778        self.arg.name()
779    }
780    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
781        let name = self.name();
782        let Self { arg, f } = self;
783        match arg.get(matches).map_err(OptionConvertStringError::Arg)? {
784            None => Ok(None),
785            Some(arg_string) => f(arg_string.as_str()).map(Some).map_err(|error| {
786                OptionConvertStringError::FailedToConvert {
787                    name,
788                    arg_string,
789                    error,
790                }
791            }),
792        }
793    }
794}
795
796pub struct VecConvertString<A, F>
797where
798    A: Arg,
799{
800    arg: A,
801    f: F,
802}
803
804#[derive(Debug)]
805pub enum VecConvertStringError<A, E> {
806    Arg(A),
807    FailedToConvert {
808        name: String,
809        index: usize,
810        arg_string: String,
811        error: E,
812    },
813}
814
815impl<A, E> fmt::Display for VecConvertStringError<A, E>
816where
817    A: fmt::Display,
818    E: fmt::Display,
819{
820    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
821        match self {
822            Self::Arg(a) => a.fmt(f),
823            Self::FailedToConvert {
824                name,
825                index,
826                arg_string,
827                error,
828            } => write!(
829                f,
830                "failed to convert argument \"{}\" in position ({}). \"{}\" could not be parsed (error: {})",
831                name, index, arg_string, error
832            ),
833        }
834    }
835}
836
837impl<A, F, T, E> Arg for VecConvertString<A, F>
838where
839    A: Arg<Item = Vec<String>>,
840    F: FnMut(&str) -> Result<T, E>,
841    E: fmt::Display + fmt::Debug,
842{
843    type Item = Vec<T>;
844    type Error = VecConvertStringError<A::Error, E>;
845    fn update_switches<S: Switches>(&self, switches: &mut S) {
846        self.arg.update_switches(switches);
847    }
848    fn name(&self) -> String {
849        self.arg.name()
850    }
851    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
852        let name = self.name();
853        let Self { arg, mut f } = self;
854        let mut vec_string = arg.get(matches).map_err(VecConvertStringError::Arg)?;
855        let mut vec_t = Vec::with_capacity(vec_string.len());
856        for (index, arg_string) in vec_string.drain(..).enumerate() {
857            let t = f(arg_string.as_str()).map_err(|error| {
858                VecConvertStringError::FailedToConvert {
859                    name: name.clone(),
860                    index,
861                    error,
862                    arg_string,
863                }
864            })?;
865            vec_t.push(t);
866        }
867        Ok(vec_t)
868    }
869}
870
871pub struct VecSingleton<A>
872where
873    A: Arg,
874{
875    arg: A,
876}
877
878#[derive(Debug)]
879pub enum VecSingletonError<A> {
880    Arg(A),
881    IncorrectNumberOfArguments {
882        number_of_arguments: usize,
883        name: String,
884    },
885}
886
887impl<A> fmt::Display for VecSingletonError<A>
888where
889    A: fmt::Display,
890{
891    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
892        match self {
893            Self::Arg(a) => a.fmt(f),
894            Self::IncorrectNumberOfArguments {
895                number_of_arguments,
896                name,
897            } => write!(
898                f,
899                "at most one arguments was expected for {} ({} found)",
900                name, number_of_arguments
901            ),
902        }
903    }
904}
905
906impl<A, T> Arg for VecSingleton<A>
907where
908    A: Arg<Item = Vec<T>>,
909{
910    type Item = Option<T>;
911    type Error = VecSingletonError<A::Error>;
912    fn update_switches<S: Switches>(&self, switches: &mut S) {
913        self.arg.update_switches(switches);
914    }
915    fn name(&self) -> String {
916        self.arg.name()
917    }
918    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
919        let name = self.name();
920        let Self { arg } = self;
921        let mut args: Vec<T> = arg.get(matches).map_err(VecSingletonError::Arg)?;
922        if let Some(item) = args.pop() {
923            match args.len() {
924                0 => Ok(Some(item)),
925                number_of_arguments => {
926                    Err(VecSingletonError::IncorrectNumberOfArguments {
927                        number_of_arguments: number_of_arguments + 1,
928                        name: name.to_string(),
929                    })
930                }
931            }
932        } else {
933            Ok(None)
934        }
935    }
936}
937
938pub struct Depend<A, B>
939where
940    A: Arg,
941    B: Arg,
942{
943    a: A,
944    b: B,
945}
946
947#[derive(Debug)]
948pub enum DependError<A, B> {
949    A(A),
950    B(B),
951    MissingDependency { a: String, b: String },
952}
953
954impl<A, B> fmt::Display for DependError<A, B>
955where
956    A: fmt::Display,
957    B: fmt::Display,
958{
959    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
960        match self {
961            Self::A(a) => a.fmt(f),
962            Self::B(b) => b.fmt(f),
963            Self::MissingDependency { a, b } => {
964                write!(f, "({}) and ({}) must be specified together", a, b)
965            }
966        }
967    }
968}
969
970impl<T, U, A, B> Arg for Depend<A, B>
971where
972    A: Arg<Item = Option<T>>,
973    B: Arg<Item = Option<U>>,
974{
975    type Item = Option<(T, U)>;
976    type Error = DependError<A::Error, B::Error>;
977    fn update_switches<S: Switches>(&self, switches: &mut S) {
978        self.a.update_switches(switches);
979        self.b.update_switches(switches);
980    }
981    fn name(&self) -> String {
982        format!("({} and {})", self.a.name(), self.b.name())
983    }
984    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
985        let missing_dependency = DependError::MissingDependency {
986            a: self.a.name(),
987            b: self.b.name(),
988        };
989        let Self { a, b } = self;
990        if let Some(a) = a.get(matches).map_err(DependError::A)? {
991            if let Some(b) = b.get(matches).map_err(DependError::B)? {
992                Ok(Some((a, b)))
993            } else {
994                Err(missing_dependency)
995            }
996        } else if b.get(matches).map_err(DependError::B)?.is_some() {
997            Err(missing_dependency)
998        } else {
999            Ok(None)
1000        }
1001    }
1002}
1003
1004pub struct SomeIf<A, T>
1005where
1006    A: Arg,
1007{
1008    arg: A,
1009    t: T,
1010}
1011
1012impl<A, T> Arg for SomeIf<A, T>
1013where
1014    A: Arg<Item = bool>,
1015{
1016    type Item = Option<T>;
1017    type Error = A::Error;
1018    fn update_switches<S: Switches>(&self, switches: &mut S) {
1019        self.arg.update_switches(switches);
1020    }
1021    fn name(&self) -> String {
1022        self.arg.name()
1023    }
1024    fn get(self, matches: &Matches) -> Result<Self::Item, Self::Error> {
1025        if self.arg.get(matches)? {
1026            Ok(Some(self.t))
1027        } else {
1028            Ok(None)
1029        }
1030    }
1031}
1032
1033pub fn flag(short: &str, long: &str, doc: &str) -> impl Arg<Item = bool> {
1034    Flag::new(short, long, doc)
1035}
1036
1037pub fn opt<T>(
1038    short: &str,
1039    long: &str,
1040    doc: &str,
1041    hint: &str,
1042) -> impl Arg<Item = Option<T>>
1043where
1044    T: FromStr,
1045    <T as FromStr>::Err: fmt::Debug + fmt::Display,
1046{
1047    Opt::new(short, long, doc, hint).option_convert_string(|s| s.parse())
1048}
1049
1050pub fn free<T>() -> impl Arg<Item = Vec<T>>
1051where
1052    T: FromStr,
1053    <T as FromStr>::Err: fmt::Debug + fmt::Display,
1054{
1055    Free.vec_convert_string(|s| s.parse())
1056}
1057
1058#[macro_export]
1059macro_rules! unflatten_closure {
1060    ( $p:pat => $tup:expr ) => {
1061        |$p| $tup
1062    };
1063    ( $p:pat => ( $($tup:tt)* ), $head:expr $(, $tail:expr)* ) => {
1064        $crate::unflatten_closure!( ($p, a) => ( $($tup)*, a) $(, $tail )* )
1065    };
1066}
1067
1068#[macro_export]
1069macro_rules! args_all {
1070    ( $only:expr ) => {
1071        $only
1072    };
1073    ( $head:expr, $($tail:expr),* $(,)* ) => {
1074        $head $( .both($tail) )*
1075            .map(
1076                $crate::unflatten_closure!(a => (a) $(, $tail )*)
1077            )
1078    };
1079}
1080
1081#[macro_export]
1082macro_rules! args_choice {
1083    ( $only:expr ) => {
1084        $only
1085    };
1086    ( $head:expr, $($tail:expr),* $(,)* ) => {
1087        $head $( .choice($tail) )*
1088    };
1089}
1090
1091#[macro_export]
1092macro_rules! args_map {
1093    ( let { $var1:ident = $a1:expr; } in { $b:expr } ) => {
1094        $a1.map(|$var1| $b)
1095    };
1096    ( let { $var1:ident = $a1:expr; $($var:ident = $a:expr;)+ } in { $b:expr } ) => {
1097        { $crate::args_all! {
1098            $a1, $($a),*
1099        } } .map(|($var1, $($var),*)| $b)
1100    };
1101}
1102
1103#[macro_export]
1104macro_rules! args_depend {
1105    ( $only:expr ) => {
1106        $only
1107    };
1108    ( $head:expr, $($tail:expr),* $(,)* ) => {
1109        $head $( .depend($tail) )*
1110            .option_map(
1111                $crate::unflatten_closure!(a => (a) $(, $tail )*)
1112            )
1113    };
1114}
1115
1116#[cfg(test)]
1117mod tests {
1118    use super::*;
1119
1120    #[test]
1121    fn basic() {
1122        assert_eq!(
1123            opt::<u32>("f", "foo", "", "")
1124                .required()
1125                .parse_specified("".to_string(), &["--foo", "42"])
1126                .result
1127                .unwrap(),
1128            42
1129        );
1130    }
1131
1132    #[test]
1133    fn basic_macros() {
1134        assert_eq!(
1135            args_map! {
1136                let {
1137                    a = opt::<u32>("f", "foo", "", "").required();
1138                    b = opt::<u32>("b", "bar", "", "").required();
1139                } in {
1140                    a + b
1141                }
1142            }
1143            .parse_specified("".to_string(), &["--foo", "7", "--bar", "9"])
1144            .result
1145            .unwrap(),
1146            16
1147        );
1148    }
1149
1150    #[test]
1151    fn depend() {
1152        assert_eq!(
1153            args_depend! {
1154                opt::<u32>("f", "foo", "", ""),
1155                opt::<u32>("b", "bar", "", ""),
1156            }
1157            .required()
1158            .map(|(a, b)| a + b)
1159            .parse_specified("".to_string(), &["--foo", "7", "--bar", "9"])
1160            .result
1161            .unwrap(),
1162            16
1163        );
1164    }
1165
1166    #[test]
1167    fn choice() {
1168        #[derive(Debug, Clone, PartialEq, Eq)]
1169        enum E {
1170            A,
1171            B,
1172            C(String),
1173        }
1174        let choice = args_choice! {
1175            flag("a", "", "").some_if(E::A),
1176            flag("b", "", "").some_if(E::B),
1177            opt("c", "", "", "").option_map(|s| E::C(s)),
1178        }
1179        .required()
1180        .parse_specified("".to_string(), &["-c", "foo"])
1181        .result
1182        .unwrap();
1183        assert_eq!(choice, E::C("foo".to_string()));
1184    }
1185
1186    #[test]
1187    fn validate() {
1188        let has_empty_switch = args_all! {
1189            opt::<String>("", "", "doc", "hint"),
1190            opt::<String>("c", "control", "", ""),
1191        };
1192        assert_eq!(
1193            has_empty_switch.validate().unwrap_err(),
1194            Invalid {
1195                has_empty_switch: true,
1196                ..Default::default()
1197            }
1198        );
1199        let duplicate_shorts = args_all! {
1200            opt::<String>("a", "aa", "", ""),
1201            opt::<String>("a", "bb", "", ""),
1202            opt::<String>("c", "control", "", ""),
1203        };
1204        assert_eq!(
1205            duplicate_shorts.validate().unwrap_err(),
1206            Invalid {
1207                duplicate_shorts: vec!["a".to_string()],
1208                duplicate_longs: vec![],
1209                ..Default::default()
1210            }
1211        );
1212        let duplicate_longs = args_all! {
1213            opt::<String>("a", "aa", "", ""),
1214            opt::<String>("b", "aa", "", ""),
1215            opt::<String>("c", "control", "", ""),
1216        };
1217        assert_eq!(
1218            duplicate_longs.validate().unwrap_err(),
1219            Invalid {
1220                duplicate_shorts: vec![],
1221                duplicate_longs: vec!["aa".to_string()],
1222                ..Default::default()
1223            }
1224        );
1225        let invalid_switches = args_all! {
1226            opt::<String>("aa", "", "", ""),
1227            opt::<String>("", "a", "", ""),
1228            opt::<String>("a", "b", "", ""),
1229            opt::<String>("bb", "aa", "", ""),
1230            opt::<String>("c", "control", "", ""),
1231        };
1232        assert_eq!(
1233            invalid_switches.validate().unwrap_err(),
1234            Invalid {
1235                one_char_longs: vec!["a".to_string(), "b".to_string()],
1236                multi_char_shorts: vec!["aa".to_string(), "bb".to_string()],
1237                ..Default::default()
1238            }
1239        );
1240    }
1241}