Skip to content

Commit 92187bd

Browse files
committed
Close #10 - add default_code syntax.
1 parent 5007926 commit 92187bd

File tree

6 files changed

+47
-17
lines changed

6 files changed

+47
-17
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [Unreleased]
8+
### Added
9+
- `#[builder(default_code = "...")]` syntax for defaults that cannot be parsed
10+
as attributes no matter what.
11+
712
## 0.2.0 - 2019-02-06
813
### Changed
914
- Upgraded `syn` version to support Rust 2018.

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@ struct Foo {
2222
// Or you can set the default
2323
#[builder(default=20)]
2424
z: i32,
25+
26+
// If the default cannot be parsed, you must encode it as a string:
27+
#[builder(default_code="vec![30, 40]")]
28+
w: Vec<u32>,
2529
}
2630
```
2731

2832
Build in any order:
2933
```rust
30-
Foo::builder().x(1).y(2).z(3).build();
31-
Foo::builder().z(1).x(2).y(3).build();
34+
Foo::builder().x(1).y(2).z(3).w(vec![4, 5]).build();
35+
Foo::builder().z(1).x(2).w(vec![4, 5]).y(3).build();
3236
```
3337

3438
Omit optional fields(the one marked with `#[default]`):

examples/example.rs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,29 @@ struct Foo {
1111
#[builder(default)]
1212
y: Option<i32>,
1313

14-
// Or you can set the default(encoded as string)
14+
// Or you can set the default
1515
#[builder(default=20)]
1616
z: i32,
17+
18+
// If the default cannot be parsed, you must encode it as a string
19+
#[builder(default_code="vec![30, 40]")]
20+
w: Vec<u32>,
1721
}
1822

1923
fn main() {
2024
assert!(
21-
Foo::builder().x(1).y(2).z(3).build()
22-
== Foo { x: 1, y: Some(2), z: 3 });
25+
Foo::builder().x(1).y(2).z(3).w(vec![4, 5]).build()
26+
== Foo { x: 1, y: Some(2), z: 3, w: vec![4, 5] });
2327

2428
// Change the order of construction:
2529
assert!(
26-
Foo::builder().z(1).x(2).y(3).build()
27-
== Foo { x: 2, y: Some(3), z: 1 });
30+
Foo::builder().z(1).x(2).w(vec![4, 5]).y(3).build()
31+
== Foo { x: 2, y: Some(3), z: 1, w: vec![4, 5] });
2832

2933
// Optional fields are optional:
3034
assert!(
3135
Foo::builder().x(1).build()
32-
== Foo { x: 1, y: None, z: 20 });
36+
== Foo { x: 1, y: None, z: 20, w: vec![30, 40] });
3337

3438
// This will not compile - because we did not set x:
3539
// Foo::builder().build();

src/builder_attr.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ impl BuilderAttr {
4848
self.default = Some(*assign.right);
4949
Ok(())
5050
}
51+
"default_code" => {
52+
if let syn::Expr::Lit(syn::ExprLit{lit: syn::Lit::Str(code), ..}) = *assign.right {
53+
use std::str::FromStr;
54+
let tokenized_code = TokenStream::from_str(&code.value())?;
55+
self.default = Some(syn::parse(tokenized_code.into()).map_err(|e| Error::new_spanned(code, format!("{}", e)))?);
56+
} else {
57+
return Err(Error::new_spanned(assign.right, "Expected string"));
58+
}
59+
Ok(())
60+
},
5161
_ => {
5262
Err(Error::new_spanned(&assign, format!("Unknown parameter {:?}", name)))
5363
}

src/lib.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,26 @@
3030
//! // Or you can set the default
3131
//! #[builder(default=20)]
3232
//! z: i32,
33+
//!
34+
//! // If the default cannot be parsed, you must encode it as a string
35+
//! #[builder(default_code="vec![30, 40]")]
36+
//! w: Vec<u32>,
3337
//! }
3438
//!
3539
//! fn main() {
3640
//! assert!(
37-
//! Foo::builder().x(1).y(2).z(3).build()
38-
//! == Foo { x: 1, y: Some(2), z: 3 });
41+
//! Foo::builder().x(1).y(2).z(3).w(vec![4, 5]).build()
42+
//! == Foo { x: 1, y: Some(2), z: 3, w: vec![4, 5] });
3943
//!
4044
//! // Change the order of construction:
4145
//! assert!(
42-
//! Foo::builder().z(1).x(2).y(3).build()
43-
//! == Foo { x: 2, y: Some(3), z: 1 });
46+
//! Foo::builder().z(1).x(2).w(vec![4, 5]).y(3).build()
47+
//! == Foo { x: 2, y: Some(3), z: 1, w: vec![4, 5] });
4448
//!
4549
//! // Optional fields are optional:
4650
//! assert!(
4751
//! Foo::builder().x(1).build()
48-
//! == Foo { x: 1, y: None, z: 20 });
52+
//! == Foo { x: 1, y: None, z: 20, w: vec![30, 40] });
4953
//!
5054
//! // This will not compile - because we did not set x:
5155
//! // Foo::builder().build();

tests/tests.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,13 @@ fn test_default() {
5454
x: Option<i32>,
5555
#[builder(default=10)]
5656
y: i32,
57+
#[builder(default_code="vec![20, 30, 40]")]
58+
z: Vec<i32>
5759
}
5860

59-
assert!(Foo::builder().build() == Foo { x: None, y: 10 });
60-
assert!(Foo::builder().x(1).build() == Foo { x: Some(1), y: 10 });
61-
assert!(Foo::builder().y(2).build() == Foo { x: None, y: 2 });
62-
assert!(Foo::builder().x(1).y(2).build() == Foo { x: Some(1), y: 2 });
61+
assert!(Foo::builder().build() == Foo { x: None, y: 10, z: vec![20, 30, 40] });
62+
assert!(Foo::builder().x(1).build() == Foo { x: Some(1), y: 10, z: vec![20, 30, 40] });
63+
assert!(Foo::builder().y(2).build() == Foo { x: None, y: 2, z: vec![20, 30, 40] });
64+
assert!(Foo::builder().x(1).y(2).build() == Foo { x: Some(1), y: 2, z: vec![20, 30, 40] });
65+
assert!(Foo::builder().z(vec![1, 2, 3]).build() == Foo { x: None, y: 10, z: vec![1, 2, 3] });
6366
}

0 commit comments

Comments
 (0)