A handy utility to generate "safe" builders for your rust types.
The issue with the builder pattern usually is some fields are required. If those fields are not provided before calling build then a run time error will be thrown. The builders generated by this package do not have this issue as the build
method will not be available unless all required fields are set. Trying to call build
before all required fields are set will result in a compile time error š„³.
Don't actually use this package... There's a better ones:
- https://crates.io/crates/const_typed_builder
- https://github.com/idanarye/rust-typed-builder
- https://crates.io/crates/safe-builder-derive
use auto_builder_derive::Builder;
#[derive(Builder)]
struct A {
x: i32,
y: i32,
z: String,
}
// Compiler error - missing `y`
let a = A::builder()
.set_x(1)
.set_z("abc")
.build();
// Success!
let a = A::builder()
.set_x(1)
.set_y(2)
.set_z("abc")
.build();
When a type derives Builder
the following is generated:
- A struct with the name + Builder is generated. E.g. for struct
Foo
,FooBuilder
is created. - A new method is implemented for that builder and a
builder
method is implemented for the original type in-order. These can both be used to created a new builder. - A setter method is implement on the builder for each field in the struct. The names are setter_ the field name. E.g. for field
bar
the method would beset_bar
. - A build method is implement for the builder when all required types are set.
Optional fields work as expected. If a field's type is Option<T>
then the setter is not required to be called before build. If the setter is not called the field will be assigned to None
.
A required field can have a default value set. The field type must implement the Default
trait and then the attribute [auto_builder(default)]
can be set on the field. If the setter is not called the value from the default method will be assigned to the field.
use auto_builder_derive::Builder;
struct A {
x: i32,
y: String,
}
impl Default for A {
fn default() -> Self {
A { x: 10, y: String::from("Hello world") }
}
}
#[derive(Builder)]
struct B {
#[auto_builder(default)]
a: A,
b: String,
}
let b = B::builder()
.set_b("Hello world").build();
In order to only make the build
method available when all required fields are set we track which fields are set using generics. For more details see https://www.youtube.com/watch?v=k8kd22jNcps