idanarye/rust-typed-builder

Calling some methods on the builder type directly without calling `.build()`

Opened this issue · 1 comments

I use the builder pattern mainly to emulate named arguments. But I don't want to have to call build.

What I must do currently

DoSomething::builder()
    .foo(foo)
    .bar(bar)
    .build() // <- I want to remove this
    .run()
    .await // the `into` attribute cannot handle opaque type such as `impl Future`, which was why calling `build` is the only way

What I hope for

DoSomething::builder()
    .foo(foo)
    .bar(bar)
    .run() // this function captures DoSomethingBuilder by move
    .await

buildstructor might work for you?

  1. You impl a constructor (new() is fronted by generated builder()), with the supported fields that you want to set.
  2. Then during usage, when you're done call the build() (the "exit" method, which has been renamed to run) to indicate that you're done supplying mandatory params and that will then call the annotated new() method with those values.
  3. In this example we create an instance of self with those method params in new() and call the structs .run() method on it which we can do since the builders own .run() is from the generated builder struct thus no conflict 👍
struct MyStruct {
    foo: usize,
    bar: usize,
}

#[buildstructor::buildstructor]
impl MyStruct {
    #[builder(exit = "run")]
    async fn new(foo: usize, bar: usize) -> bool {
        (Self { foo, bar }).run()
    }

    fn run(self) -> bool {
        self.foo == self.bar
    }
}

#[tokio::main]
async fn main() {
    let result = MyStruct::builder().foo(4).bar(2).run().await;
    assert_eq!(result, false);
}