Skip to content

Commit

Permalink
Restrict default_expr to a compile-time feature
Browse files Browse the repository at this point in the history
* Reduces compile time when the `default_expr` attribute is not used
  • Loading branch information
murarth committed Jul 25, 2019
1 parent d5354fd commit 86e4c64
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 7 deletions.
6 changes: 6 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ notifications:

branches:
only: master

script:
- cargo build --verbose
- cargo test --verbose
- cargo build --verbose --all-features
- cargo test --verbose --all-features
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ keywords = ["args", "command-line", "flag", "getopts", "option"]
license = "MIT/Apache-2.0"
readme = "README.md"

[features]
default = []
default_expr = ["gumdrop_derive/default_expr"]

[dependencies]
gumdrop_derive = { version = "0.6", path = "gumdrop_derive" }

Expand Down
6 changes: 5 additions & 1 deletion gumdrop_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ license = "MIT/Apache-2.0"
name = "gumdrop_derive"
proc-macro = true

[features]
default = []
default_expr = ["syn/full"]

[dependencies]
proc-macro2 = "0.4.4"
quote = "0.6"
syn = { version = "0.15", features = ["full"] }
syn = { version = "0.15" }
35 changes: 29 additions & 6 deletions gumdrop_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
//! The value of this field is parsed in the same way as argument values.
//! * `default_expr` provides a default value for the option field.
//! The value of this field is parsed at compile time as a Rust expression
//! and is evaluated before any argument values are processed.
//! and is evaluated before any argument values are processed.
//! The `default_expr` feature must be enabled to use this attribute.
//! * `required` will cause an error if the option is not present,
//! unless at least one `help_flag` option is also present.
//! * `multi = "..."` will allow parsing an option multiple times,
Expand Down Expand Up @@ -80,12 +81,15 @@ use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};

use syn::{
parse::Error, spanned::Spanned, Expr,
parse::Error, spanned::Spanned,
Attribute, AttrStyle, Data, DataEnum, DataStruct, DeriveInput, Fields,
GenericArgument, Ident, Lit, Meta, NestedMeta, Path, PathArguments, Type,
parse_str,
};

#[cfg(feature = "default_expr")]
use syn::Expr;

#[proc_macro_derive(Options, attributes(options))]
pub fn derive_options(input: TokenStream) -> TokenStream {
let ast: DeriveInput = match syn::parse(input) {
Expand Down Expand Up @@ -275,10 +279,18 @@ fn derive_options_struct(ast: &DeriveInput, fields: &Fields)
default.push(opts.parse.as_ref()
.unwrap_or(&ParseFn::Default)
.make_parse_default_action(ident, &expr));
} else if let Some(expr) = &opts.default_expr {
default.push(quote!{ #expr });
} else {
#[cfg(not(feature = "default_expr"))]
default.push(default_expr.clone());

#[cfg(feature = "default_expr")]
{
if let Some(expr) = &opts.default_expr {
default.push(quote!{ #expr });
} else {
default.push(default_expr.clone());
}
}
}

if opts.command {
Expand Down Expand Up @@ -675,6 +687,7 @@ struct AttrOpts {
meta: Option<String>,
parse: Option<ParseFn>,
default: Option<String>,
#[cfg(feature = "default_expr")]
default_expr: Option<Expr>,

command: bool,
Expand Down Expand Up @@ -885,8 +898,11 @@ impl AttrOpts {
if self.count { err!("`count` and `parse` are mutually exclusive"); }
}

if self.default.is_some() && self.default_expr.is_some() {
err!("`default` and `default_expr` are mutually exclusive");
#[cfg(feature = "default_expr")]
{
if self.default.is_some() && self.default_expr.is_some() {
err!("`default` and `default_expr` are mutually exclusive");
}
}

Ok(())
Expand Down Expand Up @@ -966,10 +982,17 @@ impl AttrOpts {
Meta::NameValue(nv) => {
match &nv.ident.to_string()[..] {
"default" => self.default = Some(lit_str(&nv.lit)?),
#[cfg(feature = "default_expr")]
"default_expr" => {
let expr = parse_str(&lit_str(&nv.lit)?)?;
self.default_expr = Some(expr);
}
#[cfg(not(feature = "default_expr"))]
"default_expr" => {
return Err(Error::new(nv.ident.span(),
"compile gumdrop with the `default_expr` \
feature to enable this attribute"));
}
"long" => self.long = Some(lit_str(&nv.lit)?),
"short" => self.short = Some(lit_char(&nv.lit)?),
"help" => self.help = Some(lit_str(&nv.lit)?),
Expand Down
1 change: 1 addition & 0 deletions tests/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,7 @@ fn test_failed_parse_free() {
|e| e.starts_with("invalid argument to option `baz`: "));
}

#[cfg(feature = "default_expr")]
#[test]
fn test_default_expr() {
#[derive(Options)]
Expand Down

0 comments on commit 86e4c64

Please sign in to comment.