Closed marlon-sousa closed 2 years ago
This is simple to implement without a change to the crate:
build_fn(private, name = "...")
build_fn
.The result is indistinguishable to the caller from this attribute, and the implementation is virtually identical.
The advice given was very concise, and I had a hard time following it. For others in this situation, here's a working sample:
#[derive(Builder)]
#[builder(build_fn(private, name = "build_from_builder"))]
struct MyStruct {
a: i16,
b: i16,
#[builder(setter(skip))]
sum: i16, // this is to be computed internally rather than set
}
impl MyStruct {
fn calculate(&mut self) {
self.sum = self.a + self.b;
}
}
impl MyStructBuilder {
pub fn build(&self) -> Result<MyStruct, MyStructBuilderError> {
let mut s = self.build_from_builder();
if let Ok(st) = s.as_mut() {
st.calculate();
}
s
}
}
Use scenarius
some times, one or more fields of your struct need to be built according to other field’s values. May be you have a layout which needs tpo know all other field’s values to be built, or that you have some field that needs to be calculated only once for the struct and you don’t want to recalculate it every time one of the fields are set in the builder. There are several situations in which a post build event might be useful.
The classical ways to solve this problem would be:
Customize the setters of all fields affecting the field to be calculated and update it accordingly. The main issue with this strategy is that This would make room for repeated code, might run an expensive calculation on all calls to affected setters and would couple the set of the calculated field with the setters of all the affected fields, all things we want to avoid.
Proposed solution
The post_build parameter of #[derive(builder(build_fn))] allows you to provide a function or a method which gets called by the build() method of the builder struct as soon as the target struct is built. this solves the proposed problem, creates great ergonomics and decouples the set of the calculated field and all other side effects you might want to add from the setters of other fields In order to use post_build functionality, you can declare #[builder(build_fn(postbuild = “path::to::fn”))] to specify a post build function which will be called as soon as the target struct is built, still inside the builder function. The path does not need to be fully-qualified, and will consider use statements made at module level. It must be accessible from the scope where the target struct is declared. The provided function must have the signature (&mut Foo) -> Result<, String>; the Ok variant is not used by the build method.
Implementation example
Implementation
A reference implementation can be found at #258