-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generic type for an incomplete builder? #21
Comments
Indeed. right now the builder type signature is unstable. You can see that it references types from a Lines 5 to 7 in 3a67fdf
Unfortunately, I don't see any good convenient syntax to expose the type states of the builder. As you can see today the builder's Also, when specifying the type state for the builder one needs to always specify states for all members. This is very-very inconvenient. Another way to do this could be abusing the dyn trait Rust feature with the syntax I think this may be simplified if default associated types in traits are stable rust-lang/rust#29661. Another thing. Do you have an immediate example real use case for this feature? Some keywords for this issue: partial builder type, builder type state syntax, stable builder type signature |
I'm not sure how this could be useful in general. One use case that I can think of is to prepare the parameters for a function without actually calling it and then storing the these parameters in the "complete" builder somewhere to lazily invoke the If so, as a compromise solution Note that the builder captures all the lifetimes and generic type parameters from the function and impl block (if it is under an impl block). These generic params need to be part of the "complete" builder type alias. This is already the case today for the "initial" builder state today though. That type name is kinda public, although not advertised in the docs. |
Some more thoughts on this issue: There isn't just one terminal state for the builder where you can call the finishing functions ( For example: #[builder]
struct Foo {
a: Option<String>,
b: Option<String>,
}
// `FooBuilder<(Optional<Option<String>>, Optional<String>)>`
Foo::builder().build();
// `FooBuilder<(Set<Option<String>>, Optional<String>)>`
Foo::builder().a("a").build();
// `FooBuilder<(Optional<String>, Set<Option<String>>)>`
Foo::builder().b("b").build();
// `FooBuilder<(Set<Option<String>>, Set<Option<String>>)>`
Foo::builder().a("a").b("b").build(); In the generated code the terminal states are covered by the Here is how the generated impl block for the impl<__State: __FooBuilderState> FooBuilder<__State>
where
__State::A: bon::private::IntoSet<Option<String>>,
__State::B: bon::private::IntoSet<Option<String>>,
{
#[doc = r" Finishes building and performs the requested action."]
fn build(self) -> Foo {
Foo {
a: ::bon::private::IntoSet::into_set(self.__private_impl.a).into_inner(),
b: ::bon::private::IntoSet::into_set(self.__private_impl.b).into_inner(),
}
}
} This means there is no single trait TBuilderComplete {
fn build(self) -> T;
} And that impl block higher can be turned into this trait impl instead. Then we can make the trait name exposed from the generated code. Unfortunatelly this trait isn't object-safe, unless maybe there could be a method that takes |
I've implemented a way to denote the incomplete builder type (with some members set). See #145 for details. It should close this issue once ready |
Appreciate this might be quite difficult to do:
If you want to pass around a builder you have to specify the state of the builder:
For complete structs it would make sense to type alias completeness to
However what would be really useful would be some generic way of passing incomplete builders around.
A note for the community from the maintainers
Please vote on this issue by adding a 👍 reaction to help the maintainers with prioritizing it. You may add a comment describing your real use case related to this issue for us to better understand the problem domain.
The text was updated successfully, but these errors were encountered: