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

Type level field_defaults that only effect Option<T> fields #70

Open
Michael-J-Ward opened this issue Sep 14, 2022 · 3 comments
Open

Type level field_defaults that only effect Option<T> fields #70

Michael-J-Ward opened this issue Sep 14, 2022 · 3 comments

Comments

@Michael-J-Ward
Copy link

Michael-J-Ward commented Sep 14, 2022

Reason

  1. Option semantics in rust are naturally "optional", and ideally wouldn't have to set them on the builder.
  2. It would also remove the need to strip_default on non-optional fields

Desired behavior

  1. Optional fields optional by default. Note: the standard field_attributes(default) would fail here because Wrapper has no default.
#[derive(PartialEq)]
struct Wrapper(i32);


#[derive(PartialEq, TypedBuilder)]
struct Bar {
    // Mandatory Field
    x: i32,

    // Should be optional
    y: Option<i32>,

    z: Wrapper,
}

fn main() {
    assert!(Bar::builder().x(1).z(Wrapper(3)).build() == Foo { x: 1, y: None, z: Wrapper(3) })
    assert!(Bar::builder().x(1).y(2).z(Wrapper(3)).build() == Foo { x: 1, y: Some(2), z: Wrapper(3) })
}
  1. Option specific builder attributes set on the type don't have to be stripped out (modifying the example from the docs)
use typed_builder::TypedBuilder;

#[derive(TypedBuilder)]
#[builder(field_defaults(default, setter(strip_option)))]
struct Foo {
    // Defaults to None, options-stripping is performed:
    x: Option<i32>,

   // Don't need to set `!strip_option` because it isn't an option field to begin with
   // #[builder(setter(!strip_option))]
    y: i32,

    // Defaults to Some(13), option-stripping is performed:
    #[builder(default = Some(13))]
    z: Option<i32>,

    // Accepts params `(x: f32, y: f32)`
    // Similarly, the `!strip_option` attribute is removed
    #[builder(setter(transform = |x: f32, y: f32| Point { x, y }))]
    w: Point,
}

#[derive(Default)]
struct Point { x: f32, y: f32 }
@idanarye
Copy link
Owner

Maybe this should just be the default behavior for Option fields, unless the field has a new attribute - #[builder(explicit_option)]?

@Michael-J-Ward
Copy link
Author

Michael-J-Ward commented Sep 15, 2022

Yes - I think that clarifies the suggestions.

  1. Option<T> becomes default optional.
  2. Option<T> specific setter attributes only get applied to Option<T> fields, removing the need for explicit negation on non-option fields.

#[builder(explicit_option)] might then be useful, but my first reaction is "If I need to explicitly set something to None, then there is probably real application-logic meaning behind that choice that would be better as a named enum variant."

@idanarye
Copy link
Owner

This may be, but I still wouldn't want to just block this use case.

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