You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Colin Kiegel 2a027fcd36 Merge pull request #50 from colin-kiegel/feature/derive_builder_core_rebased 4 years ago
derive_builder move `derive_builder` to a subdirectory 4 years ago
derive_builder_core move `derive_builder` to a subdirectory 4 years ago
derive_builder_test move `derive_builder` to a subdirectory 4 years ago
.gitignore gitignore: hide .* files 5 years ago
.travis-run-all.sh move `derive_builder` to a subdirectory 4 years ago
.travis.yml move `derive_builder` to a subdirectory 4 years ago
CHANGELOG.md move `derive_builder` to a subdirectory 4 years ago
Cargo.toml move `derive_builder` to a subdirectory 4 years ago
LICENSE-APACHE Add MIT/Apache2 License, Readme (#1) 5 years ago
LICENSE-MIT Add MIT/Apache2 License, Readme (#1) 5 years ago
README.md move `derive_builder` to a subdirectory 4 years ago

README.md

Build status Documentation Latest version All downloads Downloads of latest version

Builder Pattern Derive

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.

This requires Rust 1.15, due to the usage of Macros 1.1.

How it Works

#[macro_use]
extern crate derive_builder;

#[derive(Default, Builder, Debug)]
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, String> {
        Ok(Channel {
            token: Clone::clone(self.token
                .as_ref()
                .ok_or(
                       "token must be initialized")?),
            special_info: Clone::clone(self.special_info
                .as_ref()
                .ok_or("special_info must be initialized")?),
        })
    }
}

Get Started

It's as simple as two steps:

  1. Add derive_builder to your Cargo.toml either manually or with cargo-edit:
  • cargo add derive_builder
  1. Annotate your struct with #[derive(Builder)]

Usage and Features

  • Chaining: The setter calls can be chained, because they consume and return &mut self by default.
  • Builder patterns: You can opt into other builder patterns by preceding your struct (or field) with #[builder(pattern="owned")] or #[builder(pattern="immutable")].
  • Extensible: You can still define your own implementations for the builder struct and define additional methods. Just make sure to name them differently than the setter and build methods.
  • Documentation and attributes: Setter methods can be documented by simply documenting the corresponding field. Similarly #[cfg(...)] and #[allow(...)] attributes are also applied to the setter methods.
  • Hidden fields: You can skip setters via #[builder(setter(skip))] on each field individually.
  • Setter visibility: You can opt into private setter by preceding your struct with #[builder(private)].
  • Setter type conversions: Setter methods are generic over the input types – you can supply every argument that implements the Into trait for the field type.
  • Generic structs: Are also supported, but you must not use a type parameter named VALUE, because this is already reserved for the setter-methods.
  • Logging: If anything works unexpectedly you can enable detailed logs by setting this environment variable before calling cargo RUST_LOG=derive_builder=trace.

For more information and examples please take a look at our documentation.

This is a work in progress. So expect even more features in the future. :-)

Gotchas

  • Tuple structs and unit structs are not supported as they have no field names. We do not intend to support them.
  • When defining a generic struct, you cannot use VALUE as a generic parameter as this is what all setters are using.

Documentation

Detailed explaination of all features and tips for troubleshooting. You'll also find a discussion of different builder patterns.

Changelog

Yes, we keep a changelog.

License

Licensed under either of

at your option.

Contribution

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.