2020-02-08 19:36:00 +00:00
|
|
|
//! This module contains traits that are usable with `#[derive(...)].`
|
|
|
|
|
|
|
|
use crate::{App, ArgMatches, Error};
|
2020-04-27 18:47:08 +00:00
|
|
|
|
2020-02-08 19:36:00 +00:00
|
|
|
use std::ffi::OsString;
|
|
|
|
|
|
|
|
/// This trait is just a convenience on top of FromArgMatches + IntoApp
|
|
|
|
pub trait Clap: FromArgMatches + IntoApp + Sized {
|
|
|
|
/// Parse from `std::env::args()`, exit on error
|
|
|
|
fn parse() -> Self {
|
|
|
|
let matches = <Self as IntoApp>::into_app().get_matches();
|
|
|
|
<Self as FromArgMatches>::from_arg_matches(&matches)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parse from `std::env::args()`, return Err on error.
|
|
|
|
fn try_parse() -> Result<Self, Error> {
|
|
|
|
let matches = <Self as IntoApp>::into_app().try_get_matches()?;
|
|
|
|
Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Parse from iterator, exit on error
|
|
|
|
fn parse_from<I, T>(itr: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item = T>,
|
|
|
|
// TODO (@CreepySkeleton): discover a way to avoid cloning here
|
|
|
|
T: Into<OsString> + Clone,
|
|
|
|
{
|
|
|
|
let matches = <Self as IntoApp>::into_app().get_matches_from(itr);
|
|
|
|
<Self as FromArgMatches>::from_arg_matches(&matches)
|
|
|
|
}
|
|
|
|
|
2020-02-25 16:50:47 +00:00
|
|
|
/// Parse from iterator, return Err on error.
|
2020-02-08 19:36:00 +00:00
|
|
|
fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item = T>,
|
|
|
|
// TODO (@CreepySkeleton): discover a way to avoid cloning here
|
|
|
|
T: Into<OsString> + Clone,
|
|
|
|
{
|
|
|
|
let matches = <Self as IntoApp>::into_app().try_get_matches_from(itr)?;
|
|
|
|
Ok(<Self as FromArgMatches>::from_arg_matches(&matches))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Build an App according to the struct
|
|
|
|
///
|
|
|
|
/// Also serves for flattening
|
|
|
|
pub trait IntoApp: Sized {
|
|
|
|
/// @TODO @release @docs
|
2020-07-19 17:11:29 +00:00
|
|
|
fn into_app<'help>() -> App<'help>;
|
2020-02-08 19:36:00 +00:00
|
|
|
/// @TODO @release @docs
|
|
|
|
fn augment_clap(app: App<'_>) -> App<'_>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Extract values from ArgMatches into the struct.
|
|
|
|
pub trait FromArgMatches: Sized {
|
|
|
|
/// @TODO @release @docs
|
|
|
|
fn from_arg_matches(matches: &ArgMatches) -> Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @TODO @release @docs
|
|
|
|
pub trait Subcommand: Sized {
|
|
|
|
/// @TODO @release @docs
|
2020-08-05 12:14:22 +00:00
|
|
|
fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option<Self>;
|
2020-02-08 19:36:00 +00:00
|
|
|
/// @TODO @release @docs
|
|
|
|
fn augment_subcommands(app: App<'_>) -> App<'_>;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// @TODO @release @docs
|
2020-04-22 07:25:41 +00:00
|
|
|
pub trait ArgEnum: Sized {
|
|
|
|
/// @TODO @release @docs
|
|
|
|
const VARIANTS: &'static [&'static str];
|
|
|
|
|
|
|
|
/// @TODO @release @docs
|
|
|
|
fn from_str(input: &str, case_insensitive: bool) -> Result<Self, String>;
|
|
|
|
}
|
2020-02-13 15:21:01 +00:00
|
|
|
|
|
|
|
impl<T: Clap> Clap for Box<T> {
|
|
|
|
fn parse() -> Self {
|
|
|
|
Box::new(<T as Clap>::parse())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try_parse() -> Result<Self, Error> {
|
|
|
|
<T as Clap>::try_parse().map(Box::new)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn parse_from<I, It>(itr: I) -> Self
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item = It>,
|
|
|
|
// TODO (@CreepySkeleton): discover a way to avoid cloning here
|
|
|
|
It: Into<OsString> + Clone,
|
|
|
|
{
|
|
|
|
Box::new(<T as Clap>::parse_from(itr))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn try_parse_from<I, It>(itr: I) -> Result<Self, Error>
|
|
|
|
where
|
|
|
|
I: IntoIterator<Item = It>,
|
|
|
|
// TODO (@CreepySkeleton): discover a way to avoid cloning here
|
|
|
|
It: Into<OsString> + Clone,
|
|
|
|
{
|
|
|
|
<T as Clap>::try_parse_from(itr).map(Box::new)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: IntoApp> IntoApp for Box<T> {
|
2020-07-19 17:11:29 +00:00
|
|
|
fn into_app<'help>() -> App<'help> {
|
2020-02-13 15:21:01 +00:00
|
|
|
<T as IntoApp>::into_app()
|
|
|
|
}
|
|
|
|
fn augment_clap(app: App<'_>) -> App<'_> {
|
|
|
|
<T as IntoApp>::augment_clap(app)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: FromArgMatches> FromArgMatches for Box<T> {
|
|
|
|
fn from_arg_matches(matches: &ArgMatches) -> Self {
|
|
|
|
Box::new(<T as FromArgMatches>::from_arg_matches(matches))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Subcommand> Subcommand for Box<T> {
|
2020-08-05 12:14:22 +00:00
|
|
|
fn from_subcommand(subcommand: Option<(&str, &ArgMatches)>) -> Option<Self> {
|
|
|
|
<T as Subcommand>::from_subcommand(subcommand).map(Box::new)
|
2020-02-13 15:21:01 +00:00
|
|
|
}
|
|
|
|
fn augment_subcommands(app: App<'_>) -> App<'_> {
|
|
|
|
<T as Subcommand>::augment_subcommands(app)
|
|
|
|
}
|
|
|
|
}
|