Skip to content

Commit 200654b

Browse files
Default value for default_value (yeah, sounds awkward)
1 parent cf407a0 commit 200654b

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

structopt-derive/src/attrs.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use heck::{CamelCase, KebabCase, MixedCase, ShoutySnakeCase, SnakeCase};
1515
use proc_macro2::{Span, TokenStream};
1616
use proc_macro_error::abort;
1717
use quote::{quote, quote_spanned, ToTokens};
18-
use syn::{self, ext::IdentExt, spanned::Spanned, Attribute, Expr, Ident, LitStr, MetaNameValue};
18+
use syn::{
19+
self, ext::IdentExt, spanned::Spanned, Attribute, Expr, Ident, LitStr, MetaNameValue, Type,
20+
};
1921

2022
#[derive(Clone)]
2123
pub enum Kind {
@@ -75,6 +77,7 @@ pub struct Attrs {
7577
name: Name,
7678
casing: Sp<CasingStyle>,
7779
env_casing: Sp<CasingStyle>,
80+
ty: Option<Type>,
7881
doc_comment: Vec<Method>,
7982
methods: Vec<Method>,
8083
parser: Sp<Parser>,
@@ -215,11 +218,13 @@ impl Attrs {
215218
fn new(
216219
default_span: Span,
217220
name: Name,
221+
ty: Option<Type>,
218222
casing: Sp<CasingStyle>,
219223
env_casing: Sp<CasingStyle>,
220224
) -> Self {
221225
Self {
222226
name,
227+
ty,
223228
casing,
224229
env_casing,
225230
doc_comment: vec![],
@@ -285,6 +290,31 @@ impl Attrs {
285290

286291
VerbatimDocComment(ident) => self.verbatim_doc_comment = Some(ident),
287292

293+
DefaultValue(ident, lit) => {
294+
let val = if let Some(lit) = lit {
295+
quote!(#lit)
296+
} else {
297+
let ty = if let Some(ty) = self.ty.as_ref() {
298+
ty
299+
} else {
300+
abort!(
301+
ident.span(),
302+
"#[structopt(default_value)] (without an argument) can be used \
303+
only on field level";
304+
305+
note = "see \
306+
https://docs.rs/structopt/0.3.5/structopt/#magical-methods")
307+
};
308+
quote_spanned!(ident.span()=> {
309+
let val = <#ty as ::std::default::Default>::default();
310+
let s = ::std::string::ToString::to_string(&val);
311+
::std::boxed::Box::leak(s.into_boxed_str())
312+
})
313+
};
314+
315+
self.methods.push(Method::new(ident, val));
316+
}
317+
288318
About(ident, about) => {
289319
self.about = Method::from_lit_or_env(ident, about, "CARGO_PKG_DESCRIPTION");
290320
}
@@ -350,7 +380,7 @@ impl Attrs {
350380
argument_casing: Sp<CasingStyle>,
351381
env_casing: Sp<CasingStyle>,
352382
) -> Self {
353-
let mut res = Self::new(span, name, argument_casing, env_casing);
383+
let mut res = Self::new(span, name, None, argument_casing, env_casing);
354384
res.push_attrs(attrs);
355385
res.push_doc_comment(attrs, "about");
356386

@@ -377,6 +407,7 @@ impl Attrs {
377407
let mut res = Self::new(
378408
field.span(),
379409
Name::Derived(name.clone()),
410+
Some(field.ty.clone()),
380411
struct_casing,
381412
env_casing,
382413
);

structopt-derive/src/parse.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub enum StructOptAttr {
3939
// ident [= "string literal"]
4040
About(Ident, Option<LitStr>),
4141
Author(Ident, Option<LitStr>),
42+
DefaultValue(Ident, Option<LitStr>),
4243

4344
// ident = "string literal"
4445
Version(Ident, LitStr),
@@ -88,6 +89,7 @@ impl Parse for StructOptAttr {
8889
match &*name_str.to_string() {
8990
"rename_all" => Ok(RenameAll(name, lit)),
9091
"rename_all_env" => Ok(RenameAllEnv(name, lit)),
92+
"default_value" => Ok(DefaultValue(name, Some(lit))),
9193

9294
"version" => {
9395
check_empty_lit("version");
@@ -186,6 +188,7 @@ impl Parse for StructOptAttr {
186188
"no_version" => Ok(NoVersion(name)),
187189
"verbatim_doc_comment" => Ok(VerbatimDocComment(name)),
188190

191+
"default_value" => Ok(DefaultValue(name, None)),
189192
"about" => (Ok(About(name, None))),
190193
"author" => (Ok(Author(name, None))),
191194

tests/default_value.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use structopt::StructOpt;
2+
3+
#[test]
4+
fn auto_default_value() {
5+
#[derive(StructOpt, PartialEq, Debug)]
6+
struct Opt {
7+
#[structopt(default_value)]
8+
arg: i32,
9+
}
10+
assert_eq!(Opt { arg: 0 }, Opt::from_iter(&["test"]));
11+
assert_eq!(Opt { arg: 1 }, Opt::from_iter(&["test", "1"]));
12+
}

0 commit comments

Comments
 (0)