Skip to content

Commit 510376b

Browse files
committed
Version 0.4.0 - add _code = style to fix #4
1 parent ca6f2b3 commit 510376b

File tree

6 files changed

+50
-10
lines changed

6 files changed

+50
-10
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
66

77
## [Unreleased]
88

9+
## 0.4.0 - 2019-02-19
10+
### Added
11+
- `#[default(_code = "...")]` syntax for defaults that cannot be parsed as
12+
attributes no matter what.
13+
914
## 0.3.0 - 2018-11-02
1015
### Changed
1116
- Require Rust 1.30+.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "smart-default"
33
description = "Rust custom-derive macro for Default with more control on the fields"
4-
version = "0.3.0"
4+
version = "0.4.0"
55
authors = ["IdanArye <[email protected]>"]
66
license = "MIT"
77
repository = "https://github.com/idanarye/rust-smart-default"
@@ -13,6 +13,6 @@ keywords = ["default"]
1313
proc-macro = true
1414

1515
[dependencies]
16-
syn = {version = "0.15.18", features = ["derive"]}
16+
syn = {version = "0.15.26", features = ["full"]}
1717
quote = "0.6.9"
1818
proc-macro2 = "0.4.20"

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ enum Foo {
1919
a: i32,
2020
b: i32,
2121
#[default(Some(Default::default()))]
22-
c: Option<i32>
22+
c: Option<i32>,
23+
#[default(_code = "vec![1, 2, 3]")]
24+
d: Vec<u32>,
2325
},
2426
Qux(i32),
2527
}
2628

27-
assert!(Foo::default() == Foo::Baz { a: 12, b: 0, c: Some(0) });
29+
assert!(Foo::default() == Foo::Baz { a: 12, b: 0, c: Some(0), d: vec![1, 2, 3] });
2830
```
2931

3032
Requires Rust 1.30+ (for non-string values in attributes)

examples/example.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
extern crate smart_default;
32

43
use smart_default::SmartDefault;
@@ -13,11 +12,13 @@ enum Foo {
1312
a: i32,
1413
b: i32,
1514
#[default(Some(Default::default()))]
16-
c: Option<i32>
15+
c: Option<i32>,
16+
#[default(_code = "vec![1, 2, 3]")]
17+
d: Vec<u32>,
1718
},
1819
Qux(i32),
1920
}
2021

2122
fn main() {
22-
assert!(Foo::default() == Foo::Baz { a: 12, b: 0, c: Some(0) });
23+
assert!(Foo::default() == Foo::Baz { a: 12, b: 0, c: Some(0), d: vec![1, 2, 3] });
2324
}

src/lib.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@ use quote::{quote, ToTokens};
4040
/// a: i32,
4141
/// b: i32,
4242
/// #[default(Some(Default::default()))]
43-
/// c: Option<i32>
43+
/// c: Option<i32>,
44+
/// #[default(_code = "vec![1, 2, 3]")]
45+
/// d: Vec<u32>,
4446
/// },
4547
/// Qux(i32),
4648
/// }
4749
///
48-
/// assert!(Foo::default() == Foo::Baz { a: 12, b: 0, c: Some(0) });
50+
/// assert!(Foo::default() == Foo::Baz { a: 12, b: 0, c: Some(0), d: vec![1, 2, 3] });
4951
/// # }
5052
/// ```
5153
///
@@ -57,6 +59,8 @@ use quote::{quote, ToTokens};
5759
/// * `c` is an `Option<i32>`, and it's default is `Some(Default::default())`. Rust cannot (currently)
5860
/// parse `#[default = Some(Default::default())]` and therefore we have to use a special syntax:
5961
/// `#[default(Some(Default::default))]`
62+
/// * `d` has the `!` token in it, which cannot (currently) be parsed even with `#[default(...)]`,
63+
/// so we have to encode it as a string and mark it as `_code = `.
6064
/// * Documentation for the `impl Default` section is generated automatically, specifying the
6165
/// default value returned from `::default()`.
6266
#[proc_macro_derive(SmartDefault, attributes(default))]
@@ -204,12 +208,29 @@ fn is_default_attr(attr: &syn::Attribute) -> Result<bool, Error> {
204208
Ok(segment.ident.to_string() == "default")
205209
}
206210

211+
fn parse_code_hack(meta: &syn::MetaList) -> Result<Option<TokenStream>, Error> {
212+
for meta in meta.nested.iter() {
213+
if let syn::NestedMeta::Meta(syn::Meta::NameValue(meta)) = meta {
214+
if meta.ident != "_code" {
215+
continue;
216+
}
217+
if let syn::Lit::Str(lit) = &meta.lit {
218+
use std::str::FromStr;
219+
return Ok(Some(TokenStream::from_str(&lit.value())?));
220+
}
221+
};
222+
}
223+
Ok(None)
224+
}
225+
207226
fn find_default_attr_value(attrs: &[syn::Attribute]) -> Result<Option<Option<TokenStream>>, Error> {
208227
if let Some(default_attr) = find_only(attrs.iter(), |attr| is_default_attr(attr))? {
209228
match default_attr.parse_meta() {
210229
Ok(syn::Meta::Word(_)) => Ok(Some(None)),
211230
Ok(syn::Meta::List(meta)) => {
212-
if let Some(field_value) = single_value(meta.nested.iter()) {
231+
if let Some (field_value) = parse_code_hack(&meta)? { // #[default(_code = "...")]
232+
Ok(Some(Some(field_value.into_token_stream())))
233+
} else if let Some(field_value) = single_value(meta.nested.iter()) { // #[default(...)]
213234
Ok(Some(Some(field_value.into_token_stream())))
214235
} else {
215236
return Err(Error::new(

tests/tests.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,14 @@ fn test_generics_lifetime_parameters() {
136136

137137
assert!(Foo::default() == Foo::Bar(0));
138138
}
139+
140+
#[test]
141+
fn test_code_hack() {
142+
#[derive(PartialEq, SmartDefault)]
143+
struct Foo {
144+
#[default(_code = "vec![1, 2, 3]")]
145+
v: Vec<u32>,
146+
}
147+
148+
assert!(Foo::default().v == [1, 2, 3]);
149+
}

0 commit comments

Comments
 (0)