rust-typed-builder
rust-typed-builder copied to clipboard
Add helper macros for matching on and transforming the generic parameter of the builder type
In #22 we added traits for extending the builder type, but using several of them together (a common usecase for extending the builder type) can become very verbose:
#[derive(TypedStruct)]
pub struct Foo {
pub bar: u32,
pub baz: u32,
}
impl<F> FooBuilder
where F: FooBuilderWithoutBar,
<F as FooBuilderWithoutBar>::With: FooBuilderWithoutBaz
{
pub fn bar_and_baz(bar: u32, baz: u32) -> FooBuilder<
<<F as FooBuilderWithoutBar>::With as FooBuilderWithoutBaz>::With
> {
self.bar(bar).baz(baz)
}
}
To make this more doable, we want helper macros:
impl<F> FooBuilder
where typed_builder::can_set!(F: Foo; bar, baz)
{
pub fn bar_and_baz(bar: u32, baz: u32) -> FooBuilder<typed_builder::set_fields!(F: Foo; bar, baz)> {
self.bar(bar).baz(baz)
}
}
Problem - it doesn't look like we can use macros in trait bounds position yet...
Problem - it doesn't look like we can use macros in trait bounds position yet...
proc-macros
might be a good fit? I am thinking something along the lines of:
#[typed_builder::can_set(F = Foo, bar, baz)]
impl FooBuilder {
#[typed_builder::set_fields(F = Foo, bar, baz)]
pub fn bar_and_baz(bar: u32, baz: u32) -> FooBuilder {
self.bar(bar).baz(baz)
}
}
While I think this solution looks better, I don't like that it seems more "magical"/less explicit...
Proc macros can do anything - the problem is that you need to deal with all the edge cases yourself, and you don't know what all the edge cases are. So - they are dangerous.
I'm willing to do it with a proc macro if I have to, though I want to alert readers regarding where the magic happens, maybe by prefixing the replaced-by-magic parts with @
or something similar...
I opened a Reddit thread to see if someone there can come up with a better solution: https://www.reddit.com/r/rust/comments/e9q45i/how_can_i_use_macros_to_help_gluing_complex_trait/
With Rust 1.40.0 we can have macros emit macro_rules!
. I wonder if I can use that somehow to make #22 obsolete? Make #[derive(TypedBuidler)]
generate some that will be used by #[typed_builder::***]
?
With Rust 1.40.0 we can have macros emit macro_rules!. I wonder if I can use that somehow to make #22 obsolete? Make #[derive(TypedBuidler)] generate some that will be used by #[typed_builder::***]?
This seems possible: https://github.com/idanarye/rust-poc-macro-emit-data
This is a better solution than the trait-based one, because with traits we need to define the exact path of transformation, making the API more cumbersome to use.
This change may seem to make #21 redundant - but it doesn't really, because it's still helpful to have a single generic parameter (e.g. if you want to pass the builder to some other function that doesn't internally care about it's state)