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

Use darling's with to handle unnesting attrs #313

Merged
merged 1 commit into from
Feb 23, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion derive_builder_core/Cargo.toml
Expand Up @@ -21,7 +21,7 @@ clippy = []
lib_has_std = []

[dependencies]
darling = "0.20.7"
darling = "0.20.8"
proc-macro2 = "1.0.37"
quote = "1.0.35"
syn = { version = "2.0.15", features = ["full", "extra-traits"] }
Expand Down
107 changes: 57 additions & 50 deletions derive_builder_core/src/macro_options/darling_opts.rs
@@ -1,3 +1,4 @@
use std::convert::TryFrom;
use std::{borrow::Cow, vec::IntoIter};

use crate::BuildMethod;
Expand Down Expand Up @@ -305,6 +306,28 @@ fn field_setter(meta: &Meta) -> darling::Result<FieldLevelSetter> {
}
}

#[derive(Debug, Clone, Default)]
struct FieldForwardedAttrs {
pub field: Vec<Attribute>,
pub setter: Vec<Attribute>,
}

impl TryFrom<Vec<Attribute>> for FieldForwardedAttrs {
type Error = Error;

fn try_from(value: Vec<Attribute>) -> Result<Self, Self::Error> {
let mut result = Self::default();
distribute_and_unnest_attrs(
value,
&mut [
("builder_field_attr", &mut result.field),
("builder_setter_attr", &mut result.setter),
],
)?;
Ok(result)
}
}

/// Data extracted from the fields of the input struct.
#[derive(Debug, Clone, FromField)]
#[darling(
Expand All @@ -314,8 +337,8 @@ fn field_setter(meta: &Meta) -> darling::Result<FieldLevelSetter> {
)]
pub struct Field {
ident: Option<Ident>,
/// Raw input attributes, for consumption by Field::unnest_attrs. Do not use elsewhere.
attrs: Vec<syn::Attribute>,
#[darling(with = TryFrom::try_from)]
attrs: FieldForwardedAttrs,
ty: syn::Type,
/// Field-level override for builder pattern.
/// Note that setting this may force the builder to derive `Clone`.
Expand All @@ -340,18 +363,13 @@ pub struct Field {
try_setter: Flag,
#[darling(default)]
field: FieldLevelFieldMeta,
#[darling(skip)]
field_attrs: Vec<Attribute>,
#[darling(skip)]
setter_attrs: Vec<Attribute>,
}

impl Field {
/// Resolve and check (post-parsing) options which come from multiple darling options
///
/// * Check that we don't have a custom field type or builder *and* a default value
/// * Populate `self.field_attrs` and `self.setter_attrs` by draining `self.attrs`
fn resolve(mut self) -> darling::Result<Self> {
fn resolve(self) -> darling::Result<Self> {
let mut errors = darling::Error::accumulator();

// `default` can be preempted by properties in `field`. Silently ignoring a
Expand Down Expand Up @@ -388,14 +406,6 @@ impl Field {
}
};

errors.handle(distribute_and_unnest_attrs(
&mut self.attrs,
&mut [
("builder_field_attr", &mut self.field_attrs),
("builder_setter_attr", &mut self.setter_attrs),
],
));

errors.finish_with(self)
}
}
Expand All @@ -416,7 +426,7 @@ impl Field {
/// Attributes whose path matches any value in `outputs` will be added only to the first matching one, and will be "unnested".
/// Other attributes are not unnested, and simply copied for each decoratee.
fn distribute_and_unnest_attrs(
input: &mut Vec<Attribute>,
mut input: Vec<Attribute>,
outputs: &mut [(&'static str, &mut Vec<Attribute>)],
) -> darling::Result<()> {
let mut errors = vec![];
Expand Down Expand Up @@ -487,28 +497,40 @@ fn default_create_empty() -> Ident {
Ident::new("create_empty", Span::call_site())
}

#[derive(Debug, Clone, Default)]
struct StructForwardedAttrs {
struct_attrs: Vec<Attribute>,
impl_attrs: Vec<Attribute>,
}

impl TryFrom<Vec<Attribute>> for StructForwardedAttrs {
type Error = Error;

fn try_from(value: Vec<Attribute>) -> Result<Self, Self::Error> {
let mut result = Self::default();
distribute_and_unnest_attrs(
value,
&mut [
("builder_struct_attr", &mut result.struct_attrs),
("builder_impl_attr", &mut result.impl_attrs),
],
)?;

Ok(result)
}
}

#[derive(Debug, Clone, FromDeriveInput)]
#[darling(
attributes(builder),
forward_attrs(cfg, allow, builder_struct_attr, builder_impl_attr),
supports(struct_named),
and_then = Self::unnest_attrs
supports(struct_named)
)]
pub struct Options {
ident: Ident,

/// DO NOT USE.
///
/// Initial receiver for forwarded attributes from the struct; these are split
/// into `Options::struct_attrs` and `Options::impl_attrs` before `FromDeriveInput`
/// returns.
attrs: Vec<Attribute>,

#[darling(skip)]
struct_attrs: Vec<Attribute>,

#[darling(skip)]
impl_attrs: Vec<Attribute>,
#[darling(with = TryFrom::try_from)]
attrs: StructForwardedAttrs,

/// The visibility of the deriving struct. Do not confuse this with `#[builder(vis = "...")]`,
/// which is received by `Options::visibility`.
Expand Down Expand Up @@ -570,21 +592,6 @@ pub struct Options {
deprecation_notes: DeprecationNotes,
}

impl Options {
/// Populate `self.struct_attrs` and `self.impl_attrs` by draining `self.attrs`
fn unnest_attrs(mut self) -> darling::Result<Self> {
distribute_and_unnest_attrs(
&mut self.attrs,
&mut [
("builder_struct_attr", &mut self.struct_attrs),
("builder_impl_attr", &mut self.impl_attrs),
],
)?;

Ok(self)
}
}

/// Accessors for parsed properties.
impl Options {
pub fn builder_ident(&self) -> Ident {
Expand Down Expand Up @@ -657,8 +664,8 @@ impl Options {
ident: self.builder_ident(),
pattern: self.pattern,
derives: &self.derive,
struct_attrs: &self.struct_attrs,
impl_attrs: &self.impl_attrs,
struct_attrs: &self.attrs.struct_attrs,
impl_attrs: &self.attrs.impl_attrs,
impl_default: !self.custom_constructor.is_present(),
create_empty: self.create_empty.clone(),
generics: Some(&self.generics),
Expand Down Expand Up @@ -864,7 +871,7 @@ impl<'a> FieldWithDefaults<'a> {
try_setter: self.try_setter(),
visibility: self.setter_vis(),
pattern: self.pattern(),
attrs: &self.field.setter_attrs,
attrs: &self.field.attrs.setter,
ident: self.setter_ident(),
field_ident: self.field_ident(),
field_type: self.field_type(),
Expand Down Expand Up @@ -904,7 +911,7 @@ impl<'a> FieldWithDefaults<'a> {
field_ident: self.field_ident(),
field_type: self.field_type(),
field_visibility: self.field_vis(),
attrs: &self.field.field_attrs,
attrs: &self.field.attrs.field,
}
}
}
Expand Down