Skip to content
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

Add helper macros for matching on and transforming the generic parameter of the builder type #23

Open
idanarye opened this issue Dec 12, 2019 · 5 comments

Comments

@idanarye
Copy link
Owner

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)
    }
}
@idanarye
Copy link
Owner Author

Problem - it doesn't look like we can use macros in trait bounds position yet...

idanarye added a commit that referenced this issue Dec 12, 2019
Allowing different builder names would be a problem for #23...
@mwilliammyers
Copy link
Contributor

mwilliammyers commented Dec 12, 2019

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...

@idanarye
Copy link
Owner Author

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/

@idanarye
Copy link
Owner Author

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::***]?

@idanarye
Copy link
Owner Author

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)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants