Closed jonas-x closed 2 years ago
After 7 months' intermittent consideration, I don't see a way for this to be predictable for all permutations of builder options. Skipped fields and custom setters are the two most immediate places of danger, but I suspect custom build, validation, and defaulting functions would also produce surprising behavior in as-yet-unexplored edge cases.
Happily, derive_builder
doesn't need native support for this: It's easy to write a custom From
impl where the compiler will help make sure all fields are accounted for in the conversion.
impl From<Foo> for FooBuilder {
fn from(v: Foo) -> Self {
let Foo {
first,
second
} = v;
// OPTION A: Use setters
let mut builder = FooBuilder::default();
builder.first(first);
builder.second(second);
builder
// OPTION B: Don't use setters
FooBuilder {
first: Some(first),
second: Some(second),
}
}
}
By destructuring Foo
and avoiding the use of ..
, the compiler will now 1) error if any field is left behind in Foo
, and 2) will warn about an unused variable if a field is extracted from Foo
but not passed through to FooBuilder
.
If a particular project is making heavy use of this impl From<Foo> for FooBuilder
pattern, it could define a crate-private hygienic macro to further reduce boilerplate. For example:
macro_rules! into_builder {
($builder:ty : $base:ident => $($field:ident),* ) => {
impl From<$base> for $builder {
fn from(__base: $base) -> Self {
let $base {
$($field),*
} = __base;
Self {
$($field: Some($field)),*
}
}
}
}
}
into_builder!(FooBuilder : Foo => first, second);
This has the same drift protection as the more-explicit version, so adding a field to the base struct without updating the macro invocation would cause a compile error.
Given the lack of a single right behavior, the low demonstrated demand, and the availability of safe and explicit workarounds, I'm closing this and #170 as "Won't Do."
Implement
From<Foo> for FooBuilder
to allow creating a builder from an instance. This is useful when you want to create a new, modified, instance from an existing one.Issue: https://github.com/colin-kiegel/rust-derive-builder/issues/170