Crate builder_macro [−] [src]
This crate contains a builder!
macro to declare a struct and a corresponding builder.
The macro is inspired from jadpole/builder-macro, and is designed to remove duplication of field declaration, as well as generating appropriate setter methods.
Specify the dependency in your crate's Cargo.toml
:
[dependencies]
builder_macro = "0.1.1" # check https://crates.io/crates/builder_macro for the latest version
Include the macro inside your crate's lib.rs
or main.rs
.
#[macro_use] extern crate builder_macro;Run
Examples
Non-consuming Builder
The simplest usage of the builder macro to generate a non-consuming builder is:
builder!(BuilderName -> StructName { fieldname: Type = Some(default_value), // or None if there is no sensible default });Run
The above will generate a module private struct and a non-consuming builder with a single private field.
For example, given the following declaration:
builder!(BuilderName -> StructName { value: i32 = Some(1), });Run
The generated code will function as follows:
struct StructName { value: i32, } /// Auto-generated builder struct BuilderName { value: Option<i32>, } impl BuilderName { /// Construct the builder pub fn new() -> BuilderName { BuilderName { value: Some(1), } } /// Build the struct pub fn build(&self) -> StructName { let value = self.value.clone().unwrap(); StructName{value: value,} } #[allow(dead_code)] /// Auto-generated setter pub fn value(&mut self, value: i32) -> &mut Self { self.value = Some(value); self } }Run
To generate public structs and builders, see visbility.
Consuming Builder
To generate a consuming builder, instead of using ->
, use =>
between the builder name and the target struct
name.
trait Magic { fn abracadabra(&mut self) -> i32; } struct Dust { value: i32, } impl Magic for Dust { fn abracadabra(&mut self) -> i32 { self.value } } // Note: we use => instead of -> for the consuming variant of the builder builder!(MyStructBuilder => MyStruct { field_trait: Box<Magic> = Some(Box::new(Dust { value: 1 })), field_vec: Vec<Box<Magic>> = Some(vec![Box::new(Dust { value: 2 })]), }); let mut my_struct = MyStructBuilder::new().build(); assert_eq!(my_struct.field_trait.abracadabra(), 1); assert_eq!(my_struct.field_vec[0].abracadabra(), 2);Run
Visibility
Generate a builder and struct with module private visibility:
builder!(MyStructBuilder -> MyStruct { field_i32: i32 = Some(123), field_str: &'static str = Some("abc"), }); let my_struct = MyStructBuilder::new() .field_i32(456) .build(); assert_eq!(my_struct.field_i32, 456); assert_eq!(my_struct.field_str, "abc"); // uses defaultRun
Generate a builder and struct with public visibility:
mod inner { builder!(pub MyStructBuilder -> MyStruct { pub field_i32: i32 = Some(123), field_str: &'static str = Some("abc"), }); } let my_struct = inner::MyStructBuilder::new() .field_i32(456) .build(); assert_eq!(my_struct.field_i32, 456); // The next line will fail compilation if uncommented as field_str is private // assert_eq!(my_struct.field_str, "abc");Run
Full Usage Format
The full macro usage format is:
// We declare the builder insider a module simply to demonstrate scope mod inner { builder! { /// StructName is an example struct. /// These docs are copied over to the generated struct. pub BuilderName -> StructName { /// a_field is an i32 which must be between 0 and 100 inclusive // the trailing comma is mandatory due to how the macro is parsed pub a_field: i32 = Some(50), // None means no default value, a value must be specified when building // meta attributes are copied over to the struct's fields #[allow(dead_code)] a_private_field: &'static str = None, }, assertions: { assert!(a_field >= 0); assert!(a_field <= 100); // Yes you can assert on private fields assert!(!a_private_field.is_empty()); } } } let my_struct = inner::BuilderName::new() .a_private_field("I must set this to a non-empty string") .build(); assert_eq!(50, my_struct.a_field);Run
The above will be similar to writing the following:
mod inner { /// StructName is an example struct. /// These docs are copied over to the generated struct. pub struct StructName { /// a_field is an i32 which must be between 0 and 100 inclusive pub a_field: i32, #[allow(dead_code)] a_private_field: &'static str, } /// Auto-generated builder pub struct BuilderName { /// a_field is an i32 which must be between 0 and 100 inclusive a_field: Option<i32>, #[allow(dead_code)] a_private_field: Option<&'static str>, } impl BuilderName { /// Construct the builder pub fn new() -> BuilderName { BuilderName{a_field: Some(50), a_private_field: None,} } /// Build the struct pub fn build(&self) -> StructName { let a_field = self.a_field.clone().unwrap(); let a_private_field = self.a_private_field.clone().unwrap(); assert!(a_field >= 0); assert!(a_field <= 100); assert!(!a_private_field.is_empty()); StructName { a_field: a_field, a_private_field: a_private_field, } } #[allow(dead_code)] /// Auto-generated setter pub fn a_field(&mut self, value: i32) -> &mut Self { self.a_field = Some(value); self } #[allow(dead_code)] /// Auto-generated setter pub fn a_private_field(&mut self, value: &'static str) -> &mut Self { self.a_private_field = Some(value); self } } } let my_struct = inner::BuilderName::new() .a_private_field("I must set this to a non-empty string") .build(); assert_eq!(50, my_struct.a_field);Run
Macros
builder |
Macro to declare a struct and a corresponding builder. See the module documentation for more. |