clap_v3/
derive.rs

1//! This module contains traits that are usable with `#[derive(...)].`
2
3use crate::{App, ArgMatches, Error};
4use std::ffi::OsString;
5
6/// This trait is just a convenience on top of FromArgMatches + IntoApp
7pub trait Clap: FromArgMatches + IntoApp + Sized {
8    /// Parse from `std::env::args()`, exit on error
9    fn parse() -> Self {
10        let matches = <Self as IntoApp>::into_app().get_matches();
11        <Self as FromArgMatches>::from_arg_matches(&matches)
12    }
13
14    /// Parse from `std::env::args()`, return Err on error.
15    fn try_parse() -> Result<Self, Error> {
16        let matches = <Self as IntoApp>::into_app().try_get_matches()?;
17        Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
18    }
19
20    /// Parse from iterator, exit on error
21    fn parse_from<I, T>(itr: I) -> Self
22    where
23        I: IntoIterator<Item = T>,
24        // TODO (@CreepySkeleton): discover a way to avoid cloning here
25        T: Into<OsString> + Clone,
26    {
27        let matches = <Self as IntoApp>::into_app().get_matches_from(itr);
28        <Self as FromArgMatches>::from_arg_matches(&matches)
29    }
30
31    /// Parse from iterator, return Err on error.
32    fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
33    where
34        I: IntoIterator<Item = T>,
35        // TODO (@CreepySkeleton): discover a way to avoid cloning here
36        T: Into<OsString> + Clone,
37    {
38        let matches = <Self as IntoApp>::into_app().try_get_matches_from(itr)?;
39        Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
40    }
41}
42
43/// Build an App according to the struct
44///
45/// Also serves for flattening
46pub trait IntoApp: Sized {
47    /// @TODO @release @docs
48    fn into_app<'b>() -> App<'b>;
49    /// @TODO @release @docs
50    fn augment_clap(app: App<'_>) -> App<'_>;
51}
52
53/// Extract values from ArgMatches into the struct.
54pub trait FromArgMatches: Sized {
55    /// @TODO @release @docs
56    fn from_arg_matches(matches: &ArgMatches) -> Self;
57}
58
59/// @TODO @release @docs
60pub trait Subcommand: Sized {
61    /// @TODO @release @docs
62    fn from_subcommand(name: &str, matches: Option<&ArgMatches>) -> Option<Self>;
63    /// @TODO @release @docs
64    fn augment_subcommands(app: App<'_>) -> App<'_>;
65}
66
67/// @TODO @release @docs
68pub trait ArgEnum {}
69
70impl<T: Clap> Clap for Box<T> {
71    fn parse() -> Self {
72        Box::new(<T as Clap>::parse())
73    }
74
75    fn try_parse() -> Result<Self, Error> {
76        <T as Clap>::try_parse().map(Box::new)
77    }
78
79    fn parse_from<I, It>(itr: I) -> Self
80    where
81        I: IntoIterator<Item = It>,
82        // TODO (@CreepySkeleton): discover a way to avoid cloning here
83        It: Into<OsString> + Clone,
84    {
85        Box::new(<T as Clap>::parse_from(itr))
86    }
87
88    fn try_parse_from<I, It>(itr: I) -> Result<Self, Error>
89    where
90        I: IntoIterator<Item = It>,
91        // TODO (@CreepySkeleton): discover a way to avoid cloning here
92        It: Into<OsString> + Clone,
93    {
94        <T as Clap>::try_parse_from(itr).map(Box::new)
95    }
96}
97
98impl<T: IntoApp> IntoApp for Box<T> {
99    fn into_app<'b>() -> App<'b> {
100        <T as IntoApp>::into_app()
101    }
102    fn augment_clap(app: App<'_>) -> App<'_> {
103        <T as IntoApp>::augment_clap(app)
104    }
105}
106
107impl<T: FromArgMatches> FromArgMatches for Box<T> {
108    fn from_arg_matches(matches: &ArgMatches) -> Self {
109        Box::new(<T as FromArgMatches>::from_arg_matches(matches))
110    }
111}
112
113impl<T: Subcommand> Subcommand for Box<T> {
114    fn from_subcommand(name: &str, matches: Option<&ArgMatches>) -> Option<Self> {
115        <T as Subcommand>::from_subcommand(name, matches).map(Box::new)
116    }
117    fn augment_subcommands(app: App<'_>) -> App<'_> {
118        <T as Subcommand>::augment_subcommands(app)
119    }
120}