colin-kiegel / rust-derive-builder

derive builder implementation for rust structs
https://colin-kiegel.github.io/rust-derive-builder/
Apache License 2.0
1.28k stars 82 forks source link

(too niche?) Custom build method / pub(crate) builder methods #219

Closed blagovestb2c2 closed 2 years ago

blagovestb2c2 commented 3 years ago

Hello,

I am wondering if i can fit this crate into my use case. Essentially, i am in a situation where i have an enum

pub enum Variants {
   Variant1(Data),
   Variant2(Data),
   Variant3(Data),
}

where the Data struct has the same fields, but the values satisfy different invariants for each of the variants.

Ideally, i'd like the interface to be something like

VariantsBuilder::default().data_field1(..).data_field(2)...variant3()

I could leverage this crate if i put a builder on Data, but then i have two problems:

  1. the builder constructs Data which i want to be read-only for the outside world
  2. there is no way for me to hide some fields from the builder and only set them based on the build method called (i.e. variant1, variant2, variant3)

A possible solution would allow me to mark certain builder methods as pub(crate), including build, and i will then expose additional methods via an impl block on the Builder that will set them everything per the requirement. Is there a way to do this right now? Can it be added?

Extra points if I could control the name of the Builder/BuilderError structs too.

blagovestb2c2 commented 3 years ago

i found out about builder(skip_fn). sorry, i might have been too quick to post

EDIT: I just read that the defaults won't work if i skip the build fn. So I guess i really do want a way to control its visibility instead and optionally be able to set the builder struct/error names

TedDriggs commented 2 years ago

You can make DataBuilder::build private using #[builder(build_fn(private))]. You'd then expose your public variant-specific methods and have those internally call DataBuilder::build() and do their checks on the results.

That said, I feel obliged to point out that as-written nothing stops someone from taking a variant-2 Data and putting it into Variant3. Your code may have other ways of doing this (e.g. use of #[non_exhaustive]) but enum fields are not private.