Skip to content

Commit

Permalink
Break out distribute_and_unnest_attrs
Browse files Browse the repository at this point in the history
Replaces two copies of the same code, in Field::unnest_attrs and
Options::unnest_attrs.

Also, replaces the double specification of the output attributes list
variables in each of these functions (once when calculating unnest,
and once when copying the fields to every output).

Discussion was here, et seq:
  colin-kiegel#241 (comment)
  • Loading branch information
ijackson committed Mar 17, 2022
1 parent 0cc05c1 commit 1db242c
Showing 1 changed file with 49 additions and 53 deletions.
102 changes: 49 additions & 53 deletions derive_builder_core/src/macro_options/darling_opts.rs
Expand Up @@ -254,37 +254,52 @@ pub struct Field {
}

impl Field {
/// Remove the `builder_field_attr(...)` packaging around an attribute
/// Populate `self.field_attrs` and `self.setter_attrs` by draining `self.attrs`
fn unnest_attrs(mut self) -> darling::Result<Self> {
let mut errors = vec![];

for attr in self.attrs.drain(..) {
let unnest = {
if attr.path.is_ident("builder_field_attr") {
Some(&mut self.field_attrs)
} else if attr.path.is_ident("builder_setter_attr") {
Some(&mut self.setter_attrs)
} else {
None
}
};
if let Some(unnest) = unnest {
match unnest_from_one_attribute(attr) {
Ok(n) => unnest.push(n),
Err(e) => errors.push(e),
}
} else {
self.field_attrs.push(attr.clone());
self.setter_attrs.push(attr);
}
}
distribute_and_unnest_attrs(
&mut self.attrs,
&mut [
("builder_field_attr", &mut self.field_attrs),
("builder_setter_attr", &mut self.setter_attrs),
],
)?;
Ok(self)
}
}

if !errors.is_empty() {
return Err(darling::Error::multiple(errors));
/// Handles incoming attributes from darling and assigns them to decoratee attribute lists
///
/// `outputs` lists each pass-through attribute name, and the corresponding decoratee attribute list.
/// Matching atttributes are unnested and applied to the specific decoratee;
/// Other attributes are not unnested, and simply copied for each decoratee.
fn distribute_and_unnest_attrs(
input: &mut Vec<Attribute>,
outputs: &mut [(&'static str, &mut Vec<Attribute>)],
) -> darling::Result<()> {
let mut errors = vec![];

for attr in input.drain(..) {
let unnest = outputs
.iter_mut()
.find(|(ptattr, _)| attr.path.is_ident(ptattr));

if let Some((_, unnest)) = unnest {
match unnest_from_one_attribute(attr) {
Ok(n) => unnest.push(n),
Err(e) => errors.push(e),
}
} else {
for (_, output) in outputs.iter_mut() {
output.push(attr.clone());
}
}
}

Ok(self)
if !errors.is_empty() {
return Err(darling::Error::multiple(errors));
}

Ok(())
}

fn unnest_from_one_attribute(attr: syn::Attribute) -> darling::Result<Attribute> {
Expand Down Expand Up @@ -438,34 +453,15 @@ impl FlagVisibility for Options {
}

impl Options {
/// Remove the `builder_struct_attr(...)` packaging around an attribute
/// Populate `self.struct_attrs` and `self.impl_attrs` by draining `self.attrs`
fn unnest_attrs(mut self) -> darling::Result<Self> {
let mut errors = vec![];

for attr in self.attrs.drain(..) {
let unnest = {
if attr.path.is_ident("builder_struct_attr") {
Some(&mut self.struct_attrs)
} else if attr.path.is_ident("builder_impl_attr") {
Some(&mut self.impl_attrs)
} else {
None
}
};
if let Some(unnest) = unnest {
match unnest_from_one_attribute(attr) {
Ok(n) => unnest.push(n),
Err(e) => errors.push(e),
}
} else {
self.struct_attrs.push(attr.clone());
self.impl_attrs.push(attr);
}
}

if !errors.is_empty() {
return Err(darling::Error::multiple(errors));
}
distribute_and_unnest_attrs(
&mut self.attrs,
&mut [
("builder_struct_attr", &mut self.struct_attrs),
("builder_impl_attr", &mut self.impl_attrs),
],
)?;

Ok(self)
}
Expand Down

0 comments on commit 1db242c

Please sign in to comment.