From 6acf182e45d30407f454546b2dafed86bf9ec8aa Mon Sep 17 00:00:00 2001 From: Veetaha Date: Fri, 8 Nov 2024 01:38:11 +0000 Subject: [PATCH] Rename `#[builder(transparent)]` -> `required` --- .../builder/builder_gen/member/config/mod.rs | 10 ++-- .../builder_gen/member/config/with/closure.rs | 2 +- .../src/builder/builder_gen/member/named.rs | 24 +++++----- .../src/builder/builder_gen/setters/mod.rs | 2 +- .../builder_gen/top_level_config/mod.rs | 14 +++--- .../builder_gen/top_level_config/on.rs | 12 ++--- bon-macros/src/util/ide.rs | 2 +- bon/src/__/ide.rs | 2 +- .../{attr_transparent.rs => attr_required.rs} | 48 +++++++++---------- .../integration/builder/attr_with/some.rs | 38 +++++++-------- bon/tests/integration/builder/mod.rs | 2 +- .../integration/ui/compile_fail/attr_on.rs | 14 +++--- .../ui/compile_fail/attr_on.stderr | 12 ++--- .../{attr_transparent.rs => attr_required.rs} | 12 ++--- ...ransparent.stderr => attr_required.stderr} | 36 +++++++------- .../ui/compile_fail/attr_setters.rs | 8 ++-- .../ui/compile_fail/attr_setters.stderr | 20 ++++---- .../ui/compile_fail/attr_with.stderr | 10 ++-- e2e-tests/src/state_mod_pub.rs | 4 +- website/.vitepress/config.mts | 8 ++-- website/src/changelog.md | 2 +- website/src/guide/basics/optional-members.md | 2 +- website/src/reference/builder.md | 2 +- .../src/reference/builder/member/default.md | 2 +- .../member/{transparent.md => required.md} | 45 ++++++++++++++++- website/src/reference/builder/member/with.md | 8 ++-- website/src/reference/builder/top-level/on.md | 10 ++-- 27 files changed, 196 insertions(+), 155 deletions(-) rename bon/tests/integration/builder/{attr_transparent.rs => attr_required.rs} (83%) rename bon/tests/integration/ui/compile_fail/{attr_transparent.rs => attr_required.rs} (80%) rename bon/tests/integration/ui/compile_fail/{attr_transparent.stderr => attr_required.stderr} (65%) rename website/src/reference/builder/member/{transparent.md => required.md} (66%) diff --git a/bon-macros/src/builder/builder_gen/member/config/mod.rs b/bon-macros/src/builder/builder_gen/member/config/mod.rs index ebe0455d..2b0ff9e6 100644 --- a/bon-macros/src/builder/builder_gen/member/config/mod.rs +++ b/bon-macros/src/builder/builder_gen/member/config/mod.rs @@ -63,7 +63,7 @@ pub(crate) struct MemberConfig { /// member no longer has the default of `None`. It also becomes a required /// member unless a separate `#[builder(default = ...)]` attribute is /// also specified. - pub(crate) transparent: darling::util::Flag, + pub(crate) required: darling::util::Flag, } #[derive(PartialEq, Eq, Clone, Copy)] @@ -76,7 +76,7 @@ enum ParamName { Setters, Skip, StartFn, - Transparent, + Required, With, } @@ -91,7 +91,7 @@ impl fmt::Display for ParamName { Self::Setters => "setters", Self::Skip => "skip", Self::StartFn => "start_fn", - Self::Transparent => "transparent", + Self::Required => "required", Self::With => "with", }; f.write_str(str) @@ -154,7 +154,7 @@ impl MemberConfig { setters, skip, start_fn, - transparent, + required, with, } = self; @@ -167,7 +167,7 @@ impl MemberConfig { (setters.is_some(), ParamName::Setters), (skip.is_some(), ParamName::Skip), (start_fn.is_present(), ParamName::StartFn), - (transparent.is_present(), ParamName::Transparent), + (required.is_present(), ParamName::Required), (with.is_some(), ParamName::With), ]; diff --git a/bon-macros/src/builder/builder_gen/member/config/with/closure.rs b/bon-macros/src/builder/builder_gen/member/config/with/closure.rs index e93e5102..1404bca4 100644 --- a/bon-macros/src/builder/builder_gen/member/config/with/closure.rs +++ b/bon-macros/src/builder/builder_gen/member/config/with/closure.rs @@ -22,7 +22,7 @@ expected one of the following: `ApiResult<_>`, then it'll work fine; (*) underlying type is the type of the member stripped from the `Option` wrapper - if this member is of `Option` type and no `#[builder(transparent)]` annotation + if this member is of `Option` type and no `#[builder(required)]` annotation is present"; #[derive(Debug)] diff --git a/bon-macros/src/builder/builder_gen/member/named.rs b/bon-macros/src/builder/builder_gen/member/named.rs index ce5c8beb..215926ef 100644 --- a/bon-macros/src/builder/builder_gen/member/named.rs +++ b/bon-macros/src/builder/builder_gen/member/named.rs @@ -133,10 +133,10 @@ impl NamedMember { self.validate_setters_config()?; - if self.config.transparent.is_present() && !self.ty.norm.is_option() { + if self.config.required.is_present() && !self.ty.norm.is_option() { bail!( - &self.config.transparent.span(), - "`#[builder(transparent)]` can only be applied to members of \ + &self.config.required.span(), + "`#[builder(required)]` can only be applied to members of \ type `Option` to disable their special handling", ); } @@ -159,7 +159,7 @@ impl NamedMember { bail!( &setter.key, "`{}` setter function applies only to members with `#[builder(default)]` \ - or members of `Option` type (if #[builder(transparent)] is not set)", + or members of `Option` type (if #[builder(required)] is not set)", setter.key ); } @@ -215,9 +215,9 @@ impl NamedMember { } /// Returns `true` if this member is of `Option<_>` type, but returns `false` - /// if `#[builder(transparent)]` is set. + /// if `#[builder(required)]` is set. pub(crate) fn is_special_option_ty(&self) -> bool { - !self.config.transparent.is_present() && self.ty.norm.is_option() + !self.config.required.is_present() && self.ty.norm.is_option() } /// Returns `false` if the member has a default value. It means this member @@ -235,19 +235,19 @@ impl NamedMember { } /// Returns the normalized type of the member stripping the `Option<_>` - /// wrapper if it's present unless `#[builder(transparent)]` is set. + /// wrapper if it's present unless `#[builder(required)]` is set. pub(crate) fn underlying_norm_ty(&self) -> &syn::Type { self.underlying_ty(&self.ty.norm) } /// Returns the original type of the member stripping the `Option<_>` - /// wrapper if it's present unless `#[builder(transparent)]` is set. + /// wrapper if it's present unless `#[builder(required)]` is set. pub(crate) fn underlying_orig_ty(&self) -> &syn::Type { self.underlying_ty(&self.ty.orig) } fn underlying_ty<'m>(&'m self, ty: &'m syn::Type) -> &'m syn::Type { - if self.config.transparent.is_present() || self.config.default.is_some() { + if self.config.required.is_present() || self.config.default.is_some() { ty } else { ty.option_type_param().unwrap_or(ty) @@ -259,12 +259,12 @@ impl NamedMember { } pub(crate) fn merge_on_config(&mut self, on: &[OnConfig]) -> Result { - // This is a temporary hack. We only allow `on(_, transparent)` as the + // This is a temporary hack. We only allow `on(_, required)` as the // first `on(...)` clause. Instead we should implement the extended design: // https://github.com/elastio/bon/issues/152 - if let Some(on) = on.first().filter(|on| on.transparent.is_present()) { + if let Some(on) = on.first().filter(|on| on.required.is_present()) { if self.is_special_option_ty() { - self.config.transparent = on.transparent; + self.config.required = on.required; } } diff --git a/bon-macros/src/builder/builder_gen/setters/mod.rs b/bon-macros/src/builder/builder_gen/setters/mod.rs index b21897b8..1b4592ab 100644 --- a/bon-macros/src/builder/builder_gen/setters/mod.rs +++ b/bon-macros/src/builder/builder_gen/setters/mod.rs @@ -197,7 +197,7 @@ impl<'a> SettersCtx<'a> { "the underlying type of this member is not `Option`; \ by default, members of type `Option` are optional and their \ 'underlying type' is the type under the `Option`; \ - you might be missing #[builder(transparent)]` annotation \ + you might be missing #[builder(required)]` annotation \ for this member" ) } else { diff --git a/bon-macros/src/builder/builder_gen/top_level_config/mod.rs b/bon-macros/src/builder/builder_gen/top_level_config/mod.rs index 84f1a47f..2b755938 100644 --- a/bon-macros/src/builder/builder_gen/top_level_config/mod.rs +++ b/bon-macros/src/builder/builder_gen/top_level_config/mod.rs @@ -101,7 +101,7 @@ impl TopLevelConfig { } fn parse_for_any(meta_list: &[darling::ast::NestedMeta]) -> Result { - // This is a temporary hack. We only allow `on(_, transparent)` as the + // This is a temporary hack. We only allow `on(_, required)` as the // first `on(...)` clause. Instead we should implement an extended design: // https://github.com/elastio/bon/issues/152 let mut on_configs = meta_list @@ -132,20 +132,20 @@ impl TopLevelConfig { let me = Self::from_list(meta_list)?; - if let Some(on) = me.on.iter().skip(1).find(|on| on.transparent.is_present()) { + if let Some(on) = me.on.iter().skip(1).find(|on| on.required.is_present()) { bail!( - &on.transparent.span(), - "`transparent` can only be specified in the first `on(...)` clause; \ + &on.required.span(), + "`required` can only be specified in the first `on(...)` clause; \ this restriction may be lifted in the future", ); } - if let Some(first_on) = me.on.first().filter(|on| on.transparent.is_present()) { + if let Some(first_on) = me.on.first().filter(|on| on.required.is_present()) { if !matches!(first_on.type_pattern, syn::Type::Infer(_)) { bail!( &first_on.type_pattern, - "`transparent` can only be used with the wildcard type pattern \ - i.e. `on(_, transparent)`; this restriction may be lifted in the future", + "`required` can only be used with the wildcard type pattern \ + i.e. `on(_, required)`; this restriction may be lifted in the future", ); } } diff --git a/bon-macros/src/builder/builder_gen/top_level_config/on.rs b/bon-macros/src/builder/builder_gen/top_level_config/on.rs index 23118e50..6fb598b6 100644 --- a/bon-macros/src/builder/builder_gen/top_level_config/on.rs +++ b/bon-macros/src/builder/builder_gen/top_level_config/on.rs @@ -9,7 +9,7 @@ pub(crate) struct OnConfig { pub(crate) type_pattern: syn::Type, pub(crate) into: darling::util::Flag, pub(crate) overwritable: darling::util::Flag, - pub(crate) transparent: darling::util::Flag, + pub(crate) required: darling::util::Flag, } impl Parse for OnConfig { @@ -23,7 +23,7 @@ impl Parse for OnConfig { struct Parsed { into: darling::util::Flag, overwritable: darling::util::Flag, - transparent: darling::util::Flag, + required: darling::util::Flag, } let parsed = Parsed::from_meta(&syn::parse_quote!(on(#rest)))?; @@ -50,12 +50,12 @@ impl Parse for OnConfig { let Parsed { into, overwritable, - transparent, + required, } = &parsed; let flags = [ ("into", into), ("overwritable", overwritable), - ("transparent", transparent), + ("required", required), ]; if flags.iter().all(|(_, flag)| !flag.is_present()) { @@ -103,14 +103,14 @@ impl Parse for OnConfig { let Parsed { into, overwritable, - transparent, + required, } = parsed; Ok(Self { type_pattern, into, overwritable, - transparent, + required, }) } } diff --git a/bon-macros/src/util/ide.rs b/bon-macros/src/util/ide.rs index 5d5ab87d..a393efc5 100644 --- a/bon-macros/src/util/ide.rs +++ b/bon-macros/src/util/ide.rs @@ -156,7 +156,7 @@ pub(crate) fn generate_completion_triggers(meta: Vec) -> TokenStream { if let Some(first) = meta.first() { if let Meta::Path(path) = first { if path.is_ident("into") - || path.is_ident("transparent") + || path.is_ident("required") || path.is_ident("overwritable") { return; diff --git a/bon/src/__/ide.rs b/bon/src/__/ide.rs index 59ddcb50..5683a686 100644 --- a/bon/src/__/ide.rs +++ b/bon/src/__/ide.rs @@ -83,7 +83,7 @@ pub mod builder_top_level { pub const into: Flag = Flag; /// See the docs at - pub const transparent: Flag = Flag; + pub const required: Flag = Flag; /// See the docs at pub const overwritable: Flag = Flag; diff --git a/bon/tests/integration/builder/attr_transparent.rs b/bon/tests/integration/builder/attr_required.rs similarity index 83% rename from bon/tests/integration/builder/attr_transparent.rs rename to bon/tests/integration/builder/attr_required.rs index 6e84dcbf..d37fb41c 100644 --- a/bon/tests/integration/builder/attr_transparent.rs +++ b/bon/tests/integration/builder/attr_required.rs @@ -7,19 +7,19 @@ mod member_level { #[derive(Debug, Builder)] #[allow(dead_code)] struct Sut { - #[builder(transparent)] + #[builder(required)] regular: Option, - #[builder(transparent)] + #[builder(required)] generic: Option, - #[builder(transparent, into)] + #[builder(required, into)] with_into: Option, - #[builder(transparent, default = Some(99))] + #[builder(required, default = Some(99))] with_default: Option, - #[builder(transparent, default = Some(10))] + #[builder(required, default = Some(10))] with_default_2: Option, } @@ -55,11 +55,11 @@ mod member_level { fn test_free_fn() { #[builder] fn sut( - #[builder(transparent)] regular: Option, - #[builder(transparent)] generic: Option, - #[builder(transparent, into)] with_into: Option, - #[builder(transparent, default = Some(99))] with_default: Option, - #[builder(transparent, default = Some(10))] with_default_2: Option, + #[builder(required)] regular: Option, + #[builder(required)] generic: Option, + #[builder(required, into)] with_into: Option, + #[builder(required, default = Some(99))] with_default: Option, + #[builder(required, default = Some(10))] with_default_2: Option, ) -> impl fmt::Debug { (regular, generic, with_into, with_default, with_default_2) } @@ -83,11 +83,11 @@ mod member_level { impl Sut { #[builder] fn sut( - #[builder(transparent)] regular: Option, - #[builder(transparent)] generic: Option, - #[builder(transparent, into)] with_into: Option, - #[builder(transparent, default = Some(99))] with_default: Option, - #[builder(transparent, default = Some(10))] with_default_2: Option, + #[builder(required)] regular: Option, + #[builder(required)] generic: Option, + #[builder(required, into)] with_into: Option, + #[builder(required, default = Some(99))] with_default: Option, + #[builder(required, default = Some(10))] with_default_2: Option, ) -> impl fmt::Debug { (regular, generic, with_into, with_default, with_default_2) } @@ -95,11 +95,11 @@ mod member_level { #[builder] fn with_self( &self, - #[builder(transparent)] regular: Option, - #[builder(transparent)] generic: Option, - #[builder(transparent, into)] with_into: Option, - #[builder(transparent, default = Some(99))] with_default: Option, - #[builder(transparent, default = Some(10))] with_default_2: Option, + #[builder(required)] regular: Option, + #[builder(required)] generic: Option, + #[builder(required, into)] with_into: Option, + #[builder(required, default = Some(99))] with_default: Option, + #[builder(required, default = Some(10))] with_default_2: Option, ) -> impl fmt::Debug { let _ = self; (regular, generic, with_into, with_default, with_default_2) @@ -135,7 +135,7 @@ mod attr_on { #[test] fn test_struct() { #[derive(Debug, Builder)] - #[builder(on(_, transparent))] + #[builder(on(_, required))] #[allow(dead_code)] struct Sut { #[builder(start_fn)] @@ -185,7 +185,7 @@ mod attr_on { #[test] fn test_free_fn() { - #[builder(on(_, transparent))] + #[builder(on(_, required))] fn sut( #[builder(start_fn)] start_fn: u32, regular: Option, @@ -221,7 +221,7 @@ mod attr_on { #[bon] impl Sut { - #[builder(on(_, transparent))] + #[builder(on(_, required))] fn sut( #[builder(start_fn)] start_fn: u32, regular: Option, @@ -240,7 +240,7 @@ mod attr_on { ) } - #[builder(on(_, transparent))] + #[builder(on(_, required))] fn with_self( &self, #[builder(start_fn)] start_fn: u32, diff --git a/bon/tests/integration/builder/attr_with/some.rs b/bon/tests/integration/builder/attr_with/some.rs index c7b160d2..fdec06f1 100644 --- a/bon/tests/integration/builder/attr_with/some.rs +++ b/bon/tests/integration/builder/attr_with/some.rs @@ -6,16 +6,16 @@ fn test_struct() { #[derive(Debug, Builder)] #[builder(derive(Clone))] struct Sut { - #[builder(transparent, with = Some)] + #[builder(required, with = Some)] _required: Option, - #[builder(transparent, with = Some, default = Some(()))] + #[builder(required, with = Some, default = Some(()))] _optional: Option<()>, - #[builder(transparent, with = Some)] + #[builder(required, with = Some)] _generic: Option, - #[builder(transparent, with = Some, default = None)] + #[builder(required, with = Some, default = None)] _optional_generic: Option, } @@ -58,10 +58,10 @@ fn test_free_fn() { { #[builder(derive(Clone))] fn sut( - #[builder(transparent, with = Some)] required: Option, - #[builder(transparent, with = Some, default = Some(()))] optional: Option<()>, - #[builder(transparent, with = Some)] generic: Option, - #[builder(transparent, with = Some, default = None)] optional_generic: Option, + #[builder(required, with = Some)] required: Option, + #[builder(required, with = Some, default = Some(()))] optional: Option<()>, + #[builder(required, with = Some)] generic: Option, + #[builder(required, with = Some, default = None)] optional_generic: Option, ) -> impl fmt::Debug { (required, optional, generic, optional_generic) } @@ -85,7 +85,7 @@ fn test_free_fn() { { #[builder] fn sut( - #[builder(transparent, with = Some)] impl_trait: Option, + #[builder(required, with = Some)] impl_trait: Option, ) -> impl fmt::Debug { impl_trait } @@ -105,10 +105,10 @@ fn test_assoc_method() { impl Sut { #[builder(derive(Clone))] fn sut( - #[builder(transparent, with = Some)] required: Option, - #[builder(transparent, with = Some, default = Some(()))] optional: Option<()>, - #[builder(transparent, with = Some)] generic: Option, - #[builder(transparent, with = Some, default = None)] optional_generic: Option, + #[builder(required, with = Some)] required: Option, + #[builder(required, with = Some, default = Some(()))] optional: Option<()>, + #[builder(required, with = Some)] generic: Option, + #[builder(required, with = Some, default = None)] optional_generic: Option, ) -> impl fmt::Debug { (required, optional, generic, optional_generic) } @@ -116,10 +116,10 @@ fn test_assoc_method() { #[builder(derive(Clone))] fn with_self( &self, - #[builder(transparent, with = Some)] required: Option, - #[builder(transparent, with = Some, default = Some(()))] optional: Option<()>, - #[builder(transparent, with = Some)] generic: Option, - #[builder(transparent, with = Some, default = None)] optional_generic: Option, + #[builder(required, with = Some)] required: Option, + #[builder(required, with = Some, default = Some(()))] optional: Option<()>, + #[builder(required, with = Some)] generic: Option, + #[builder(required, with = Some, default = None)] optional_generic: Option, ) -> impl fmt::Debug { let _ = self; (required, optional, generic, optional_generic) @@ -127,7 +127,7 @@ fn test_assoc_method() { #[builder] fn sut_impl_trait( - #[builder(transparent, with = Some)] impl_trait: Option, + #[builder(required, with = Some)] impl_trait: Option, ) -> impl fmt::Debug { impl_trait } @@ -135,7 +135,7 @@ fn test_assoc_method() { #[builder] fn with_self_impl_trait( &self, - #[builder(transparent, with = Some)] impl_trait: Option, + #[builder(required, with = Some)] impl_trait: Option, ) -> impl fmt::Debug { let _ = self; impl_trait diff --git a/bon/tests/integration/builder/mod.rs b/bon/tests/integration/builder/mod.rs index c0663186..3f351f6e 100644 --- a/bon/tests/integration/builder/mod.rs +++ b/bon/tests/integration/builder/mod.rs @@ -5,10 +5,10 @@ mod attr_derive; mod attr_into; mod attr_on; mod attr_overwritable; +mod attr_required; mod attr_setters; mod attr_skip; mod attr_top_level_start_fn; -mod attr_transparent; mod attr_with; mod cfgs; mod generics; diff --git a/bon/tests/integration/ui/compile_fail/attr_on.rs b/bon/tests/integration/ui/compile_fail/attr_on.rs index d66e6da3..7e8dbbdd 100644 --- a/bon/tests/integration/ui/compile_fail/attr_on.rs +++ b/bon/tests/integration/ui/compile_fail/attr_on.rs @@ -25,7 +25,7 @@ fn incomplete_on3() {} fn incomplete_on4() {} #[builder( - on(_, transparent), + on(_, required), finish_fn = finish, on(String, into), )] @@ -33,7 +33,7 @@ fn non_consecutive_on1() {} #[builder( start_fn = start, - on(_, transparent), + on(_, required), finish_fn = finish, on(String, into), )] @@ -41,17 +41,17 @@ fn non_consecutive_on2() {} #[builder( start_fn = start, - on(_, transparent), + on(_, required), finish_fn = finish, on(String, into), builder_type = Builder, )] fn non_consecutive_on3() {} -#[builder(on(_, into), on(_, transparent))] -fn non_first_transparent() {} +#[builder(on(_, into), on(_, required))] +fn non_first_required() {} -#[builder(on(u8, transparent))] -fn non_wildcard_transparent() {} +#[builder(on(u8, required))] +fn non_wildcard_required() {} fn main() {} diff --git a/bon/tests/integration/ui/compile_fail/attr_on.stderr b/bon/tests/integration/ui/compile_fail/attr_on.stderr index cd3baa51..3ad2768a 100644 --- a/bon/tests/integration/ui/compile_fail/attr_on.stderr +++ b/bon/tests/integration/ui/compile_fail/attr_on.stderr @@ -42,7 +42,7 @@ error: expected `,` | = note: this error originates in the attribute macro `builder` (in Nightly builds, run with -Z macro-backtrace for more info) -error: this #[builder(on(type_pattern, ...))] contains no options to override the default behavior for the selected setters like `into`, `overwritable`, `transparent`, so it does nothing +error: this #[builder(on(type_pattern, ...))] contains no options to override the default behavior for the selected setters like `into`, `overwritable`, `required`, so it does nothing --> tests/integration/ui/compile_fail/attr_on.rs:24:1 | 24 | #[builder(on(_,))] @@ -68,14 +68,14 @@ error: this `on(...)` clause is out of order; all `on(...)` clauses must be cons 46 | on(String, into), | ^^ -error: `transparent` can only be specified in the first `on(...)` clause; this restriction may be lifted in the future +error: `required` can only be specified in the first `on(...)` clause; this restriction may be lifted in the future --> tests/integration/ui/compile_fail/attr_on.rs:51:30 | -51 | #[builder(on(_, into), on(_, transparent))] - | ^^^^^^^^^^^ +51 | #[builder(on(_, into), on(_, required))] + | ^^^^^^^^ -error: `transparent` can only be used with the wildcard type pattern i.e. `on(_, transparent)`; this restriction may be lifted in the future +error: `required` can only be used with the wildcard type pattern i.e. `on(_, required)`; this restriction may be lifted in the future --> tests/integration/ui/compile_fail/attr_on.rs:54:14 | -54 | #[builder(on(u8, transparent))] +54 | #[builder(on(u8, required))] | ^^ diff --git a/bon/tests/integration/ui/compile_fail/attr_transparent.rs b/bon/tests/integration/ui/compile_fail/attr_required.rs similarity index 80% rename from bon/tests/integration/ui/compile_fail/attr_transparent.rs rename to bon/tests/integration/ui/compile_fail/attr_required.rs index 733ab844..f198969f 100644 --- a/bon/tests/integration/ui/compile_fail/attr_transparent.rs +++ b/bon/tests/integration/ui/compile_fail/attr_required.rs @@ -2,34 +2,34 @@ use bon::Builder; #[derive(Builder)] struct InvalidOnRequiredMember { - #[builder(transparent)] + #[builder(required)] member: i32, } #[derive(Builder)] struct InvalidOnStartFnMember { - #[builder(start_fn, transparent)] + #[builder(start_fn, required)] member: Option, } #[derive(Builder)] struct InvalidOnFnMember { - #[builder(finish_fn, transparent)] + #[builder(finish_fn, required)] member: Option, } #[derive(Builder)] struct InvalidOnSkippedMember { - #[builder(skip, transparent)] + #[builder(skip, required)] member: Option, } #[derive(Builder)] struct Valid { - #[builder(transparent)] + #[builder(required)] member: Option, - #[builder(transparent, with = Some)] + #[builder(required, with = Some)] some_member: Option<()>, } diff --git a/bon/tests/integration/ui/compile_fail/attr_transparent.stderr b/bon/tests/integration/ui/compile_fail/attr_required.stderr similarity index 65% rename from bon/tests/integration/ui/compile_fail/attr_transparent.stderr rename to bon/tests/integration/ui/compile_fail/attr_required.stderr index 44a38390..66e4f32f 100644 --- a/bon/tests/integration/ui/compile_fail/attr_transparent.stderr +++ b/bon/tests/integration/ui/compile_fail/attr_required.stderr @@ -1,29 +1,29 @@ -error: `#[builder(transparent)]` can only be applied to members of type `Option` to disable their special handling - --> tests/integration/ui/compile_fail/attr_transparent.rs:5:15 +error: `#[builder(required)]` can only be applied to members of type `Option` to disable their special handling + --> tests/integration/ui/compile_fail/attr_required.rs:5:15 | -5 | #[builder(transparent)] - | ^^^^^^^^^^^ +5 | #[builder(required)] + | ^^^^^^^^ -error: `start_fn` attribute can't be specified together with `transparent` - --> tests/integration/ui/compile_fail/attr_transparent.rs:11:15 +error: `start_fn` attribute can't be specified together with `required` + --> tests/integration/ui/compile_fail/attr_required.rs:11:15 | -11 | #[builder(start_fn, transparent)] +11 | #[builder(start_fn, required)] | ^^^^^^^^ -error: `finish_fn` attribute can't be specified together with `transparent` - --> tests/integration/ui/compile_fail/attr_transparent.rs:17:15 +error: `finish_fn` attribute can't be specified together with `required` + --> tests/integration/ui/compile_fail/attr_required.rs:17:15 | -17 | #[builder(finish_fn, transparent)] +17 | #[builder(finish_fn, required)] | ^^^^^^^^^ -error: `skip` attribute can't be specified together with `transparent` - --> tests/integration/ui/compile_fail/attr_transparent.rs:23:15 +error: `skip` attribute can't be specified together with `required` + --> tests/integration/ui/compile_fail/attr_required.rs:23:15 | -23 | #[builder(skip, transparent)] +23 | #[builder(skip, required)] | ^^^^ error[E0599]: no method named `maybe_member` found for struct `ValidBuilder` in the current scope - --> tests/integration/ui/compile_fail/attr_transparent.rs:38:30 + --> tests/integration/ui/compile_fail/attr_required.rs:38:30 | 27 | #[derive(Builder)] | ------- method `maybe_member` not found for this struct @@ -37,7 +37,7 @@ help: there is a method `member` with a similar name | ~~~~~~ error[E0599]: no method named `maybe_some_member` found for struct `ValidBuilder` in the current scope - --> tests/integration/ui/compile_fail/attr_transparent.rs:39:30 + --> tests/integration/ui/compile_fail/attr_required.rs:39:30 | 27 | #[derive(Builder)] | ------- method `maybe_some_member` not found for this struct @@ -51,7 +51,7 @@ help: there is a method `some_member` with a similar name | ~~~~~~~~~~~ error[E0277]: the member `Unset` was not set, but this method requires it to be set - --> tests/integration/ui/compile_fail/attr_transparent.rs:51:32 + --> tests/integration/ui/compile_fail/attr_required.rs:51:32 | 51 | let _ = Sut::builder().build(); | ^^^^^ the member `Unset` was not set, but this method requires it to be set @@ -59,12 +59,12 @@ error[E0277]: the member `Unset` was not set, but this method requires it = help: the trait `IsSet` is not implemented for `Unset`, which is required by `sut_builder::Empty: sut_builder::IsComplete` = help: the trait `IsSet` is implemented for `Set` note: required for `sut_builder::Empty` to implement `sut_builder::IsComplete` - --> tests/integration/ui/compile_fail/attr_transparent.rs:45:18 + --> tests/integration/ui/compile_fail/attr_required.rs:45:18 | 45 | #[derive(Builder)] | ^^^^^^^ unsatisfied trait bound introduced in this `derive` macro note: required by a bound in `SutBuilder::::build` - --> tests/integration/ui/compile_fail/attr_transparent.rs:45:18 + --> tests/integration/ui/compile_fail/attr_required.rs:45:18 | 45 | #[derive(Builder)] | ^^^^^^^ required by this bound in `SutBuilder::::build` diff --git a/bon/tests/integration/ui/compile_fail/attr_setters.rs b/bon/tests/integration/ui/compile_fail/attr_setters.rs index 697f61bc..fb88c3f6 100644 --- a/bon/tests/integration/ui/compile_fail/attr_setters.rs +++ b/bon/tests/integration/ui/compile_fail/attr_setters.rs @@ -55,14 +55,14 @@ struct OptionFnSetterOnRequiredMember { } #[derive(Builder)] -struct SomeFnSetterWithTransparent { - #[builder(transparent, setters(some_fn = foo))] +struct SomeFnSetterWithrequired { + #[builder(required, setters(some_fn = foo))] member: Option, } #[derive(Builder)] -struct OptionFnSetterWithTransparent { - #[builder(transparent, setters(option_fn = bar))] +struct OptionFnSetterWithrequired { + #[builder(required, setters(option_fn = bar))] member: Option, } diff --git a/bon/tests/integration/ui/compile_fail/attr_setters.stderr b/bon/tests/integration/ui/compile_fail/attr_setters.stderr index bf027f56..4a266b8c 100644 --- a/bon/tests/integration/ui/compile_fail/attr_setters.stderr +++ b/bon/tests/integration/ui/compile_fail/attr_setters.stderr @@ -22,29 +22,29 @@ error: this `doc` configuration is unused because all of the `some_fn`, `option_ 32 | doc { | ^^^ -error: `some_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(transparent)] is not set) +error: `some_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(required)] is not set) --> tests/integration/ui/compile_fail/attr_setters.rs:47:23 | 47 | #[builder(setters(some_fn = foo))] | ^^^^^^^ -error: `option_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(transparent)] is not set) +error: `option_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(required)] is not set) --> tests/integration/ui/compile_fail/attr_setters.rs:53:23 | 53 | #[builder(setters(option_fn = bar))] | ^^^^^^^^^ -error: `some_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(transparent)] is not set) - --> tests/integration/ui/compile_fail/attr_setters.rs:59:36 +error: `some_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(required)] is not set) + --> tests/integration/ui/compile_fail/attr_setters.rs:59:33 | -59 | #[builder(transparent, setters(some_fn = foo))] - | ^^^^^^^ +59 | #[builder(required, setters(some_fn = foo))] + | ^^^^^^^ -error: `option_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(transparent)] is not set) - --> tests/integration/ui/compile_fail/attr_setters.rs:65:36 +error: `option_fn` setter function applies only to members with `#[builder(default)]` or members of `Option` type (if #[builder(required)] is not set) + --> tests/integration/ui/compile_fail/attr_setters.rs:65:33 | -65 | #[builder(transparent, setters(option_fn = bar))] - | ^^^^^^^^^ +65 | #[builder(required, setters(option_fn = bar))] + | ^^^^^^^^^ error: expected parameters in parentheses --> tests/integration/ui/compile_fail/attr_setters.rs:71:22 diff --git a/bon/tests/integration/ui/compile_fail/attr_with.stderr b/bon/tests/integration/ui/compile_fail/attr_with.stderr index af42735b..11e0aa01 100644 --- a/bon/tests/integration/ui/compile_fail/attr_with.stderr +++ b/bon/tests/integration/ui/compile_fail/attr_with.stderr @@ -62,7 +62,7 @@ error: expected one of the following: `ApiResult<_>`, then it'll work fine; (*) underlying type is the type of the member stripped from the `Option` wrapper - if this member is of `Option` type and no `#[builder(transparent)]` annotation + if this member is of `Option` type and no `#[builder(required)]` annotation is present --> tests/integration/ui/compile_fail/attr_with.rs:47:34 | @@ -88,7 +88,7 @@ error: expected one of the following: `ApiResult<_>`, then it'll work fine; (*) underlying type is the type of the member stripped from the `Option` wrapper - if this member is of `Option` type and no `#[builder(transparent)]` annotation + if this member is of `Option` type and no `#[builder(required)]` annotation is present --> tests/integration/ui/compile_fail/attr_with.rs:67:38 | @@ -114,7 +114,7 @@ error: expected one of the following: `ApiResult<_>`, then it'll work fine; (*) underlying type is the type of the member stripped from the `Option` wrapper - if this member is of `Option` type and no `#[builder(transparent)]` annotation + if this member is of `Option` type and no `#[builder(required)]` annotation is present --> tests/integration/ui/compile_fail/attr_with.rs:73:38 | @@ -140,7 +140,7 @@ error: expected one of the following: `ApiResult<_>`, then it'll work fine; (*) underlying type is the type of the member stripped from the `Option` wrapper - if this member is of `Option` type and no `#[builder(transparent)]` annotation + if this member is of `Option` type and no `#[builder(required)]` annotation is present --> tests/integration/ui/compile_fail/attr_with.rs:79:38 | @@ -153,7 +153,7 @@ error: `with = Some` only works for members with the underlying type of `Option` 86 | value: u32, | ^^^ -error: the underlying type of this member is not `Option`; by default, members of type `Option` are optional and their 'underlying type' is the type under the `Option`; you might be missing #[builder(transparent)]` annotation for this member +error: the underlying type of this member is not `Option`; by default, members of type `Option` are optional and their 'underlying type' is the type under the `Option`; you might be missing #[builder(required)]` annotation for this member --> tests/integration/ui/compile_fail/attr_with.rs:91:22 | 91 | #[builder(with = Some)] diff --git a/e2e-tests/src/state_mod_pub.rs b/e2e-tests/src/state_mod_pub.rs index 3b593c12..21fc1db7 100644 --- a/e2e-tests/src/state_mod_pub.rs +++ b/e2e-tests/src/state_mod_pub.rs @@ -17,8 +17,8 @@ pub struct PubStateMod { #[builder(overwritable, default = 2 * 2 + 3)] overwritable_default_arg: u32, - #[builder(transparent)] - transparent_arg: Option, + #[builder(required)] + required_option_arg: Option, #[builder(with = |x: &str| -> Result<_, std::num::ParseIntError> { x.parse() })] with_arg: u32, diff --git a/website/.vitepress/config.mts b/website/.vitepress/config.mts index 11a6c523..4ee795a3 100644 --- a/website/.vitepress/config.mts +++ b/website/.vitepress/config.mts @@ -305,6 +305,10 @@ export default defineConfig({ text: "overwritable 🔬", link: "/reference/builder/member/overwritable", }, + { + text: "required", + link: "/reference/builder/member/required", + }, { text: "setters", link: "/reference/builder/member/setters", @@ -317,10 +321,6 @@ export default defineConfig({ text: "start_fn", link: "/reference/builder/member/start_fn", }, - { - text: "transparent", - link: "/reference/builder/member/transparent", - }, { text: "with", link: "/reference/builder/member/with", diff --git a/website/src/changelog.md b/website/src/changelog.md index 19d75447..b804ef57 100644 --- a/website/src/changelog.md +++ b/website/src/changelog.md @@ -62,7 +62,7 @@ All the breaking changes are very unlikely to actually break your code that was - Add `#[builder(with = Some)]`, `#[builder(with = FromIterator::from_iter)]`, `#[builder(with = <_>::from_iter)]` syntax support for two [well-known functions](https://bon-rs.com/reference/builder/member/with#well-known-functions) that will probably be used frequently ([#157](https://github.com/elastio/bon/pull/157)) -- Add [`#[builder(transparent)]`](https://bon-rs.com/reference/builder/member/transparent) for `Option` fields to opt out from their special handling which makes `bon` treat them as regular required fields. It's also available at the top-level via `#[builder(on(_, transparent))]` ([#145](https://github.com/elastio/bon/pull/145), [#155](https://github.com/elastio/bon/pull/155)) +- Add [`#[builder(required)]`](https://bon-rs.com/reference/builder/member/required) for `Option` fields to opt out from their special handling which makes `bon` treat them as regular required fields. It's also available at the top-level via `#[builder(on(_, required))]` ([#145](https://github.com/elastio/bon/pull/145), [#155](https://github.com/elastio/bon/pull/155)) - Add [`#[builder(crate = path::to::bon)]`](https://bon-rs.com/reference/builder/top-level/crate) and `#[bon(crate = path::to::bon)]` to allow overriding the path to `bon` crate used in the generated code, which is useful for the cases when `bon` macros are wrapped by other macros ([#153](https://github.com/elastio/bon/pull/153)) diff --git a/website/src/guide/basics/optional-members.md b/website/src/guide/basics/optional-members.md index 6fa277b5..9fc090ad 100644 --- a/website/src/guide/basics/optional-members.md +++ b/website/src/guide/basics/optional-members.md @@ -16,7 +16,7 @@ fn example(level: Option) {} example().call(); ``` -You can use [`#[builder(transparent)]`](../../reference/builder/member/transparent) to opt-out from this. +You can use [`#[builder(required)]`](../../reference/builder/member/required) to opt-out from this. ### Setters pair diff --git a/website/src/reference/builder.md b/website/src/reference/builder.md index a7e2e786..d6b97bb1 100644 --- a/website/src/reference/builder.md +++ b/website/src/reference/builder.md @@ -31,10 +31,10 @@ These attributes are placed on a `struct` field or `fn` argument. | [`into`](./builder/member/into) | Changes the signature of the setters to accept `impl Into` | | [`name`](./builder/member/name) | Overrides the name of the member used in the builder's API | | [`overwritable` 🔬](./builder/member/overwritable) | Allows calling setters for the same member repeatedly | +| [`required`](./builder/member/required) | Disables `Option` special handling, makes the member required | | [`setters`](./builder/member/setters) | Overrides name, visibility and docs for setters | | [`skip`](./builder/member/skip) | Skips generating setters for the member | | [`start_fn`](./builder/member/start_fn) | Makes the member a positional argument on the starting function | -| [`transparent`](./builder/member/transparent) | Disables `Option` special handling, makes the member required | | [`with`](./builder/member/with) | Overrides setters' signature and applies a custom conversion | ## Examples diff --git a/website/src/reference/builder/member/default.md b/website/src/reference/builder/member/default.md index e94ea142..db968bf8 100644 --- a/website/src/reference/builder/member/default.md +++ b/website/src/reference/builder/member/default.md @@ -240,4 +240,4 @@ The `self` parameter in associated method syntax is not available to the `defaul ## Compile errors -This attribute is incompatible with members of `Option` type, since `Option` already implies the default value of `None`. However, it can be used together with [`#[builder(transparent)]`](./transparent). +This attribute is incompatible with members of `Option` type, since `Option` already implies the default value of `None`. However, it can be used together with [`#[builder(required)]`](./required). diff --git a/website/src/reference/builder/member/transparent.md b/website/src/reference/builder/member/required.md similarity index 66% rename from website/src/reference/builder/member/transparent.md rename to website/src/reference/builder/member/required.md index fcbb23c2..27d29272 100644 --- a/website/src/reference/builder/member/transparent.md +++ b/website/src/reference/builder/member/required.md @@ -1,4 +1,4 @@ -# `transparent` +# `required` **Applies to:** @@ -19,7 +19,7 @@ use bon::Builder; #[derive(Builder)] struct Example { - #[builder(transparent)] + #[builder(required)] required: Option, optional: Option, @@ -31,6 +31,47 @@ Example::builder() .build(); ``` +```rust [Function] +use bon::builder; + +#[builder] +fn example( + #[builder(required)] + required: Option, + + optional: Option, +) {} + +example() + .required(Some(2)) + .optional(2) + .call(); +``` + +```rust [Method] +use bon::bon; + +struct Example; + +#[bon] +impl Example { + #[builder] + fn example( + #[builder(required)] + required: Option, + + optional: Option, + ) {} +} + +Example::example() + .required(Some(2)) + .optional(2) + .call(); +``` + +::: + Notice the difference: | Member name | Setters | Comment | diff --git a/website/src/reference/builder/member/with.md b/website/src/reference/builder/member/with.md index 9a76fd0b..684a7d2c 100644 --- a/website/src/reference/builder/member/with.md +++ b/website/src/reference/builder/member/with.md @@ -214,7 +214,7 @@ You can't declare new generic parameters. If `impl Trait` isn't enough for you, ### Optional members -For members of type `Option` without [`#[builder(transparent)]`](./transparent), the closure needs to return a value of type `T` or `Result`. +For members of type `Option` without [`#[builder(required)]`](./required), the closure needs to return a value of type `T` or `Result`. The `maybe_` setter's input type depends on the number of input parameters in the closure: @@ -373,14 +373,14 @@ Example::example() #[builder(with = |value: T| Some(value))] ``` -Makes the setter accept the value of type `T` assuming the member is of type `Option` with [`#[builder(transparent)]`](./transparent). +Makes the setter accept the value of type `T` assuming the member is of type `Option` with [`#[builder(required)]`](./required). ```rust use bon::Builder; #[derive(Builder)] struct Example { - #[builder(transparent, with = Some)] + #[builder(required, with = Some)] x1: Option, } @@ -391,6 +391,6 @@ Example::builder() ::: tip History -This attribute was added as a way to make setters required for structs generated by [`prost`](https://docs.rs/prost/latest/prost/) from the `proto3` syntax. Protobuf v3 doesn't take apart required and optional fields, so `prost` generates `Option` even for required fields ([original issue comment](https://github.com/elastio/bon/issues/35#issuecomment-2426991137)). However, you can use `#[builder(transparent, with = Some)]` to mark the fields required in the builder syntax. +This attribute was added as a way to make setters required for structs generated by [`prost`](https://docs.rs/prost/latest/prost/) from the `proto3` syntax. Protobuf v3 doesn't take apart required and optional fields, so `prost` generates `Option` even for required fields ([original issue comment](https://github.com/elastio/bon/issues/35#issuecomment-2426991137)). However, you can use `#[builder(required, with = Some)]` to mark the fields required in the builder syntax. ::: diff --git a/website/src/reference/builder/top-level/on.md b/website/src/reference/builder/top-level/on.md index a9ab6fd5..01c54421 100644 --- a/website/src/reference/builder/top-level/on.md +++ b/website/src/reference/builder/top-level/on.md @@ -96,10 +96,10 @@ For optional members, the underlying type is matched ignoring the `Option` wrapp There are several attributes supported in the `attributes` position listed below. - [`into`](../member/into) -- [`transparent`](../member/transparent) - currently, this attribute can only be used with the `_` type pattern as the first `on(...)` clause +- [`required`](../member/required) - currently, this attribute can only be used with the `_` type pattern as the first `on(...)` clause - [`overwritable`](../member/overwritable) - 🔬 **experimental**, this attribute is available under the cargo feature `"experimental-overwritable"` (see the issue [#149](https://github.com/elastio/bon/issues/149)) -A single `on(...)` clause can contain several of these separated by a comma e.g. `on(_, into, transparent)`. +A single `on(...)` clause can contain several of these separated by a comma e.g. `on(_, into, required)`. ## Examples @@ -128,11 +128,11 @@ Example::builder() .build(); ``` -```rust [transparent] +```rust [required] use bon::Builder; #[derive(Builder)] -#[builder(on(_, transparent))] // [!code highlight] +#[builder(on(_, required))] // [!code highlight] struct Example { name: String, level: Option, @@ -142,7 +142,7 @@ struct Example { Example::builder() .name("regular required member".to_owned()) .level(Some(99)) - .description(Some("transparent `Option`".to_owned())) + .description(Some("required `Option`".to_owned())) .build(); ```