Skip to content

Support #[builder(derive(Into))] to generate From<Builder<impl IsComplete>> for T #247

@luveti

Description

@luveti

The following shows a macro I use heavily in my code to mostly remove the need to call the finish fn.

macro_rules! builder_to_built_impl {
    ($name:ident) => {
        paste::paste! {
            impl<S: [<$name:snake _builder>]::State + [<$name:snake _builder>]::IsComplete> From<[<$name Builder>]<S>> for $name {
                fn from(value: [<$name Builder>]<S>) -> Self {
                    value.call()
                }
            }
        }
    };
}

struct Foo {
    bar: Option<u32>,
    bazz: bool,
}

#[bon::builder]
fn foo(bar: Option<u32>, bazz: bool) -> Foo {
    Foo { bar, bazz }
}

builder_to_built_impl!(Foo);

fn test(foo: impl Into<Foo>) {}

fn main() {
    test(foo().bazz(false).call());
    test(foo().bazz(true)); // call not required

    // one can now just call `into` instead of `call`
    let test1: Foo = foo().bazz(true).into();

    // `into` is better than calling `call`, as we can support more than just builders
    macro_rules! foos {
        ($($foo:expr),* $(,)?) => {
            vec![$($foo.into(),)*]
        };
    }
    let foos: Vec<Foo> = foos![foo().bazz(true), foo().bazz(false)];
}

I believe this could be better handled by bon directly, as it knows the name of the top-level finish_fn (call in this case). This of course can't be used when a member-level finish_fn is used, since Into can't take arguments.

The proposed syntax change would be:

#[bon::builder(into)]
fn foo(bar: Option<u32>, bazz: bool) -> Foo {
    Foo { bar, bazz }
}

Which would generate:

impl<S: foo_builder::State + foo_builder::IsComplete> From<FooBuilder<S>> for Foo {
    fn from(value: FooBuilder<S>) -> Self {
        value.call()
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions