Rust macro to automatically implement the builder pattern for arbitrary structs. A simple #[derive(Builder)]
will generate a FooBuilder
for your struct Foo
with all setter-methods and a build method.
#[macro_use] extern crate derive_builder; #[derive(Default, Builder, Debug)] #[builder(setter(into))] struct Channel { token: i32, special_info: i32, // .. a whole bunch of other fields .. } fn main() { // builder pattern, go, go, go!... let ch = ChannelBuilder::default() .special_info(42u8) .token(19124) .build() .unwrap(); println!("{:?}", ch); }
Note that we did not write any definition or implementation of ChannelBuilder
. Instead the derive_builder
crate acts on #[derive(Builder)]
and generates the necessary code at compile time.
This is the generated boilerplate code you didn't need to write. :-)
#[derive(Clone, Default)] struct ChannelBuilder { token: Option<i32>, special_info: Option<i32>, } #[allow(dead_code)] impl ChannelBuilder { pub fn token<VALUE: Into<i32>>(&mut self, value: VALUE) -> &mut Self { let mut new = self; new.token = Some(value.into()); new } pub fn special_info<VALUE: Into<i32>>(&mut self, value: VALUE) -> &mut Self { let mut new = self; new.special_info = Some(value.into()); new } fn build( &self, ) -> Result<Channel, ChannelBuilderError> { Ok(Channel { id: match self.id { Some(ref value) => Clone::clone(value), None => { return Err( Into::into( ::derive_builder::UninitializedFieldError::from("id"), ), ) } }, token: match self.token { Some(ref value) => Clone::clone(value), None => { return Err( Into::into( ::derive_builder::UninitializedFieldError::from("token"), ), ) } }, special_info: match self.special_info { Some(ref value) => Clone::clone(value), None => { return Err( Into::into( ::derive_builder::UninitializedFieldError::from("special_info"), ), ) } }, }) } }
Note: This is edited for readability. The generated code doesn't assume traits such as Into
are in-scope, and uses full paths to access them.
It's as simple as three steps:
derive_builder
to your Cargo.toml
either manually or with cargo-edit:cargo add derive_builder
use derive_builder::Builder;
#[derive(Builder)]
&mut self
by default.#[builder(pattern = "owned")]
or #[builder(pattern = "immutable")]
.#[cfg(...)]
and #[allow(...)]
attributes are also applied to the setter methods.#[builder(setter(skip))]
on each field individually.#[builder(private)]
.#[builder(setter(into))]
, setter methods will be generic over the input types – you can then supply every argument that implements the Into
trait for the field type.#[builder(setter(strip_option))]
, setter methods will take T
as parameter'type for field of type Option<T>
.#[builder(setter(each(name = "method_name")))]
to fields whose types implement Default
and Extend
will generate a setter which adds items to the builder collection for that field. It's possible for these setters to be generic over the Into<T>
trait too, like so: #[builder(setter(each(name = "foo", into)))]
.#[builder(field(private))]
or ..(public)
, to set field visibility of your builder.VALUE
, if you also activate setter type conversions.#[builder(default)]
to delegate to the Default
implementation or any explicit value via = ".."
. This works both on the struct and field level.#[builder(build_fn(validate = "path::to::fn"))]
to add your own validation before the target struct is generated.#[builder(build_fn(skip))]
to disable auto-implementation of the build method and provide your own.#[builder(build_fn(error = "path::to::Error"))]
to have your builder return an error type of your choosing. By default, the macro will emit an error type alongside the builder.#[builder(derive(Trait1, Trait2, ...))]
to have the builder derive additonal traits. All builders derive Default
and Clone
, so you should not declare those in this attribute.#[builder_struct_attr(...)]
, #[builder_impl_attr(...)]
, #[builder_field_attr(...)]
, and #[builder_setter_attr(...)]
to declare attributes that will be added to the relevant part of the generated builder.#[builder(no_std)]
to your struct and add extern crate alloc
to your crate.For more information and examples please take a look at our documentation.
derive_builder
in Cargo.toml
is not supported.VALUE
as a generic parameter as this is what all setters are using.Detailed explaination of all features and tips for troubleshooting. You'll also find a discussion of different builder patterns.
Yes, we keep a changelog.
Licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.