rust-typed-builder
rust-typed-builder copied to clipboard
Special Setter/Initializer
Is it possible to customize a setter for initializing a couple of fields? For example, I want the builder being able to accept a different struct that contains some information about some fields.
This is possible with mutator, but that will get rid of the compile time checking of those fields, which I do want the builder to be able to detect whether that setter is called.
Thanks for the very cool project!
How would it looks like? Something like this?
#[derive(TypedBuilder)]
#[builder(setters(
#[setter(sets = (bar, baz))]
fn bar_and_baz(&self, bar: i32, baz: i32) -> (i32, i32) {
(bar, baz)
}
))]
struct Foo {
bar: i32,
baz: i32,
}
This is possible outside of macros provided by typed-builder
, which means we have to write some hacky generic. But it's fine with the help of cargo expand
subcommand.
Say we have the following struct:
#[derive(TypedBuilder)]
struct Foo {
bar: i32,
baz: f64,
qux: i16
}
With cargo expand, we can see the generated builder and helper by typed-builder
. Here is the generated builder function for qux
field:
#[allow(dead_code, non_camel_case_types, missing_docs)]
#[automatically_derived]
impl<__bar, __baz> FooBuilder<(__bar, __baz, ())> {
#[allow(clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
pub fn qux(self, qux: i16) -> FooBuilder<(__bar, __baz, (i16,))> {
let qux = (qux,);
let (bar, baz, ()) = self.fields;
FooBuilder {
fields: (bar, baz, qux),
phantom: self.phantom,
}
}
}
So we can create our own functions, based on the above code from cargo expand
. Here is a hand written setter for setting bar
and baz
at once:
#[allow(dead_code, non_camel_case_types, missing_docs)]
#[automatically_derived]
impl<__qux> FooBuilder<((), (), __qux)> {
#[allow(clippy::used_underscore_binding, clippy::no_effect_underscore_binding)]
// function signature is fully customizible, like function name, params.
pub fn bar_and_baz(self, bar:i32, baz: f64) -> FooBuilder<((i32,), (f64,), __qux)> {
let baz = (baz,);
let bar = (bar,)
let ((), (), qux) = self.fields;
FooBuilder {
fields: (bar, baz, qux),
phantom: self.phantom,
}
}
}