rust-typed-builder
rust-typed-builder copied to clipboard
Type level `field_defaults` that only effect `Option<T>` fields
Reason
-
Option
semantics in rust are naturally "optional", and ideally wouldn't have to set them on the builder. - It would also remove the need to
strip_default
on non-optional fields
Desired behavior
- Optional fields optional by default. Note: the standard
field_attributes(default)
would fail here becauseWrapper
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) })
}
-
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 }
Maybe this should just be the default behavior for Option
fields, unless the field has a new attribute - #[builder(explicit_option)]
?
Yes - I think that clarifies the suggestions.
-
Option<T>
becomes default optional. -
Option<T>
specific setter attributes only get applied toOption<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."
This may be, but I still wouldn't want to just block this use case.