makeit icon indicating copy to clipboard operation
makeit copied to clipboard

Expose the builder type publicly

Open lilyball opened this issue 3 years ago • 3 comments

It looks like the generated code puts everything into a private module named after the builder type. For example, looking at the sample code from the README:

use makeit::Builder;

#[derive(Builder)]
struct Foo<'a, T: std::fmt::Debug> {
    bar: &'a T,
    #[default(42)]
    baz: i32,
}

This produces an expansion like

mod FooBuilderFields {
    pub struct FooBuilder<…> { … }
    pub struct BarSet;
    pub struct BazSet;
    pub struct BarUnset;
    pub struct BazUnset;
    // impls …
}

And the generated documentation does not include the FooBuilder type:

screenshot of the generated documentation for Foo, in which the <Foo as Buildable>::Builder type is listed as FooBuilder but with no link to see the documentation for FooBuilder

If I know the module name I can write pub use FooBuilderFields::FooBuilder, but it feels like I shouldn't have to do that. The builder should just be available by default.

I can imagine a scenario in which someone might want to move the builder into a separate module, like pub mod builder { pub use super::FooBuilderFields::FooBuilder; } but that is a bit of an edge case and should require opt-in behavior.

Proposed behavior

The macro expansion should simply declare the FooBuilder type in the current module instead of inside the FooBuilderFields module, and it should mark it as pub if the decorated type itself is pub. Also see #7 in which I argue that the Buildable type should be removed and propose a #[builder(…)] attribute for renaming the builder() method and FooBuilder type as needed.

If I have an edge case where I want Foo to be public but I want the FooBuilder type to be moved into a different module, I can deal with that using existing visibility rules by writing something like:

mod foo {
    #[derive(makeit::Builder)]
    pub struct Foo<'a, T: std::fmt::Debug> {
        bar: &'a T,
        #[default(42)]
        baz: i32,
    }
}
pub use foo::Foo;
pub mod builder {
    pub use super::foo::FooBuilder;
}

I don't see any reason to make the BarSet/BarUnset/… types public by default so they can stay as they are.

lilyball avatar Mar 25 '22 23:03 lilyball

What's the benefit or the Builder type being available to begin with? What's the user benefit of that? I'm trying to understand the usecase, particularly because if the field types aren't then there's literally nothing that can be done with that type, right?

estebank avatar Mar 28 '22 02:03 estebank

For documentation reasons. Exposing the BarSet, BarUnset, etc types isn't necessary, they're just typestate and have no documentation, so they'll just show up without links in the generated documentation. But exposing the Builder type will generate documentation for that type and let me see what methods are available.

lilyball avatar Mar 29 '22 16:03 lilyball

I see, that makes sense.

estebank avatar Mar 29 '22 18:03 estebank