builder_macro 0.1.0

A macro to generate structs and a corresponding builder
Documentation

Builder Macro

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.

Include the macro inside your crate's lib.rs or main.rs.

#[macro_use]
extern crate builder_macro;

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
});

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),
});

The generated builder and struct will be:

struct StructName {
    value: i32,
}

#[doc = "Generated struct 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)]
    /// Specify a value for the $F_NAME field
    pub fn value(&mut self, value: i32) -> &mut Self {
        self.value = Some(value);
        self
    }
}

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);

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);

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 default

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");

License

The MIT License