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

Add support for positional params in start_fn and finish_fn #125

Merged
merged 21 commits into from
Sep 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 1 addition & 12 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,6 @@ jobs:
components: clippy
toolchain: 1.59.0

# We just test that `bon` crate compile fine. This is the main crate
# that needs to compile fine. We also make sure its tests compile
# fine as well. Therefore right now we use the MSRV specifically such
# that `trybuild` compiles as well (it's trybuild's MSRV).
- run: ./scripts/test-msrv.sh

test-unstable:
Expand Down Expand Up @@ -192,11 +188,4 @@ jobs:
cache-dependency-path: website/package-lock.json

- run: cd website && npm ci
- run: cd website && npm run build
- name: Validate for broken links (mostly broken anchors)
run: |
cd website && FORCE_COLOR=2 \
node \
--no-warnings=ExperimentalWarning \
--loader ts-node/esm \
./validate-links.mts
- run: scripts/validate-links.sh
2 changes: 1 addition & 1 deletion bon-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Simple CLI initially created to assits with upgrading to the new versions of
//! Simple CLI initially created to assist with upgrading to the new versions of
//! the `bon` crate.
#![allow(missing_docs)]

Expand Down
76 changes: 48 additions & 28 deletions bon-macros/src/builder/builder_gen/builder_derives.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::BuilderGenCtx;
use crate::builder::builder_gen::Member;
use crate::util::prelude::*;
use quote::quote;

Expand All @@ -22,28 +23,17 @@ impl BuilderGenCtx {
tokens
}

/// These bounds are required to ensure that all members of the,
/// builder (including the receiver) implement the target trait,
/// so that there is no possible state of the builder that cannot
/// implement the target trait.
fn builder_components_trait_bounds<'a>(
&'a self,
trait_path: &'a TokenStream2,
) -> impl Iterator<Item = TokenStream2> + 'a {
fn builder_component_types(&self) -> impl Iterator<Item = &'_ syn::Type> {
let receiver_ty = self
.receiver()
.map(|receiver| &receiver.without_self_keyword);

let member_types = self.regular_members().map(|member| &member.norm_ty);
let member_types = self.named_members().map(|member| &member.norm_ty);

std::iter::empty()
.chain(receiver_ty)
.chain(member_types)
.map(move |ty| {
quote! {
#ty: #trait_path
}
})
.map(Box::as_ref)
}

fn derive_clone(&self) -> TokenStream2 {
Expand All @@ -59,8 +49,15 @@ impl BuilderGenCtx {
}
});

let clone_start_fn_args = self.start_fn_args().next().map(|_| {
quote! {
__private_start_fn_args: #clone::clone(&self.__private_start_fn_args),
}
});

let builder_where_clause_predicates = self.generics.where_clause_predicates();
let components_where_clause_predicates = self.builder_components_trait_bounds(&clone);

let builder_component_types = self.builder_component_types();

quote! {
#[automatically_derived]
Expand All @@ -75,13 +72,14 @@ impl BuilderGenCtx {
where
#(#builder_where_clause_predicates,)*
___State: #clone,
#(#components_where_clause_predicates,)*
{
fn clone(&self) -> Self {
#(::bon::private::assert_clone::<#builder_component_types>();)*
Self {
__private_phantom: ::core::marker::PhantomData,
#clone_receiver
__private_members: self.__private_members.clone(),
#clone_start_fn_args
__private_named_members: self.__private_named_members.clone(),
}
}
}
Expand All @@ -102,24 +100,45 @@ impl BuilderGenCtx {
});

let builder_where_clause_predicates = self.generics.where_clause_predicates();
let components_where_clause_predicates = self.builder_components_trait_bounds(&debug);
let builder_component_types = self.builder_component_types();

let builder_ident_str = builder_ident.to_string();

let state_type_vars = self
.regular_members()
.named_members()
.map(|member| &member.generic_var_ident)
.collect::<Vec<_>>();

let format_members = self.regular_members().map(|member| {
let member_index = &member.index;
let member_ident_str = member.orig_ident.to_string();

quote! {
// Skip members that are not set to reduce noise
if self.__private_members.#member_index.is_set() {
output.field(#member_ident_str, &self.__private_members.#member_index);
let format_members = self.members.iter().filter_map(|member| {
match member {
Member::Named(member) => {
let member_index = &member.index;
let member_ident_str = member.orig_ident.to_string();
Some(quote! {
// Skip members that are not set to reduce noise
if self.__private_named_members.#member_index.is_set() {
output.field(
#member_ident_str,
&self.__private_named_members.#member_index
);
}
})
}
Member::StartFnArg(member) => {
let member_index = &member.index;
let member_ident_str = member.base.ident.to_string();
Some(quote! {
output.field(
#member_ident_str,
&self.__private_start_fn_args.#member_index
);
})
}

// The values for these members are computed only in the finishing
// function where the builder is consumed, and they aren't stored
// in the builder itself.
Member::FinishFnArg(_) | Member::Skipped(_) => None,
}
});

Expand All @@ -135,10 +154,11 @@ impl BuilderGenCtx {
>
where
#(#builder_where_clause_predicates,)*
#(#components_where_clause_predicates,)*
#(#state_type_vars: ::bon::private::MemberState + ::core::fmt::Debug,)*
{
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
#(::bon::private::assert_debug::<#builder_component_types>();)*

let mut output = f.debug_struct(#builder_ident_str);

#format_receiver
Expand Down
28 changes: 24 additions & 4 deletions bon-macros/src/builder/builder_gen/input_func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use super::{
generic_param_to_arg, AssocMethodCtx, AssocMethodReceiverCtx, BuilderGenCtx, FinishFunc,
FinishFuncBody, Generics, Member, MemberOrigin, RawMember, StartFunc,
};
use crate::builder::builder_gen::BuilderGenParams;
use crate::builder::params::BuilderParams;
use crate::normalization::NormalizeSelfTy;
use crate::util::prelude::*;
Expand Down Expand Up @@ -71,6 +70,11 @@ pub(crate) struct FuncInputCtx {
pub(crate) struct ImplCtx {
pub(crate) self_ty: Box<syn::Type>,
pub(crate) generics: syn::Generics,

/// Lint suppressions from the original item that will be inherited by all items
/// generated by the macro. If the original syntax used `#[expect(...)]`,
/// then it must be represented as `#[allow(...)]` here.
pub(crate) allow_attrs: Vec<syn::Attribute>,
}

impl FuncInputCtx {
Expand Down Expand Up @@ -341,6 +345,20 @@ impl FuncInputCtx {
docs: "Finishes building and performs the requested action.".to_owned(),
};

let fn_allows = self
.norm_func
.attrs
.iter()
.filter_map(syn::Attribute::to_allow);

let allow_attrs = self
.impl_ctx
.as_ref()
.into_iter()
.flat_map(|impl_ctx| impl_ctx.allow_attrs.iter().cloned())
.chain(fn_allows)
.collect();

let start_func = StartFunc {
ident: start_func_ident,

Expand All @@ -364,9 +382,11 @@ impl FuncInputCtx {
)),
};

let ctx = BuilderGenCtx::new(BuilderGenParams {
let ctx = BuilderGenCtx {
members,

allow_attrs,

conditional_params: self.params.base.on,
builder_derives: self.params.base.derive,

Expand All @@ -378,7 +398,7 @@ impl FuncInputCtx {

start_func,
finish_func,
});
};

Ok(ctx)
}
Expand Down Expand Up @@ -422,7 +442,7 @@ impl FinishFuncBody for FnCallBody {
let func_ident = &self.sig.ident;

// The variables with values of members are in scope for this expression.
let member_vars = members.iter().map(Member::ident);
let member_vars = members.iter().map(Member::orig_ident);

quote! {
#prefix #func_ident::<#(#generic_args,)*>(
Expand Down
16 changes: 12 additions & 4 deletions bon-macros/src/builder/builder_gen/input_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use super::{
AssocMethodCtx, BuilderGenCtx, FinishFunc, FinishFuncBody, Generics, Member, MemberOrigin,
RawMember, StartFunc,
};
use crate::builder::builder_gen::BuilderGenParams;
use crate::builder::params::{BuilderParams, ItemParams};
use crate::util::prelude::*;
use darling::FromMeta;
Expand Down Expand Up @@ -182,9 +181,18 @@ impl StructInputCtx {
receiver: None,
});

let ctx = BuilderGenCtx::new(BuilderGenParams {
let allow_attrs = self
.norm_struct
.attrs
.iter()
.filter_map(syn::Attribute::to_allow)
.collect();

let ctx = BuilderGenCtx {
members,

allow_attrs,

conditional_params: self.params.base.on,
builder_derives: self.params.base.derive,

Expand All @@ -196,7 +204,7 @@ impl StructInputCtx {

start_func,
finish_func,
});
};

Ok(ctx)
}
Expand All @@ -211,7 +219,7 @@ impl FinishFuncBody for StructLiteralBody {
let Self { struct_ident } = self;

// The variables with values of members are in scope for this expression.
let member_vars = member_exprs.iter().map(Member::ident);
let member_vars = member_exprs.iter().map(Member::orig_ident);

quote! {
#struct_ident {
Expand Down
Loading