use std::{borrow::Cow, vec::IntoIter};
use crate::BuildMethod;
use darling::util::{Flag, PathList};
use darling::{self, Error, FromMeta};
use proc_macro2::{Span, TokenStream};
use syn::parse::{ParseStream, Parser};
use syn::Meta;
use syn::{self, spanned::Spanned, Attribute, Generics, Ident, Path};
use crate::{
BlockContents, Builder, BuilderField, BuilderFieldType, BuilderPattern, DefaultExpression,
DeprecationNotes, Each, FieldConversion, Initializer, Setter,
};
trait Visibility {
fn public(&self) -> &Flag;
fn private(&self) -> &Flag;
fn explicit(&self) -> Option<&syn::Visibility>;
fn as_expressed_vis(&self) -> Option<Cow<syn::Visibility>> {
let declares_public = self.public().is_present();
let declares_private = self.private().is_present();
let declares_explicit = self.explicit().is_some();
if declares_private {
assert!(!declares_public && !declares_explicit);
Some(Cow::Owned(syn::Visibility::Inherited))
} else if let Some(vis) = self.explicit() {
assert!(!declares_public);
Some(Cow::Borrowed(vis))
} else if declares_public {
Some(Cow::Owned(syn::parse_quote!(pub)))
} else {
None
}
}
}
fn no_visibility_conflict<T: Visibility>(v: &T) -> darling::Result<()> {
let declares_public = v.public().is_present();
let declares_private = v.private().is_present();
if let Some(vis) = v.explicit() {
if declares_public || declares_private {
Err(
Error::custom(r#"`vis="..."` cannot be used with `public` or `private`"#)
.with_span(vis),
)
} else {
Ok(())
}
} else if declares_public && declares_private {
Err(
Error::custom(r#"`public` and `private` cannot be used together"#)
.with_span(v.public()),
)
} else {
Ok(())
}
}
#[derive(Debug, Clone, FromMeta)]
#[darling(default)]
pub struct BuildFn {
skip: bool,
name: Ident,
validate: Option<Path>,
public: Flag,
private: Flag,
vis: Option<syn::Visibility>,
error: Option<Path>,
}
impl Default for BuildFn {
fn default() -> Self {
BuildFn {
skip: false,
name: Ident::new("build", Span::call_site()),
validate: None,
public: Default::default(),
private: Default::default(),
vis: None,
error: None,
}
}
}
impl Visibility for BuildFn {
fn public(&self) -> &Flag {
&self.public
}
fn private(&self) -> &Flag {
&self.private
}
fn explicit(&self) -> Option<&syn::Visibility> {
self.vis.as_ref()
}
}
#[derive(Debug, Clone, Default, FromMeta)]
pub struct StructLevelFieldMeta {
public: Flag,
private: Flag,
vis: Option<syn::Visibility>,
}
impl Visibility for StructLevelFieldMeta {
fn public(&self) -> &Flag {
&self.public
}
fn private(&self) -> &Flag {
&self.private
}
fn explicit(&self) -> Option<&syn::Visibility> {
self.vis.as_ref()
}
}
#[derive(Debug, Clone, Default, FromMeta)]
pub struct FieldLevelFieldMeta {
public: Flag,
private: Flag,
vis: Option<syn::Visibility>,
#[darling(rename = "type")]
builder_type: Option<syn::Type>,
build: Option<BlockContents>,
}
impl Visibility for FieldLevelFieldMeta {
fn public(&self) -> &Flag {
&self.public
}
fn private(&self) -> &Flag {
&self.private
}
fn explicit(&self) -> Option<&syn::Visibility> {
self.vis.as_ref()
}
}
#[derive(Debug, Clone, Default, FromMeta)]
pub struct StructLevelSetter {
prefix: Option<Ident>,
into: Option<bool>,
strip_option: Option<bool>,
skip: Option<bool>,
}
impl StructLevelSetter {
pub fn enabled(&self) -> Option<bool> {
self.skip.map(|x| !x)
}
}
fn parse_each(meta: &Meta) -> darling::Result<Option<Each>> {
if let Meta::NameValue(mnv) = meta {
if let syn::Lit::Str(v) = &mnv.lit {
v.parse::<Ident>()
.map(Each::from)
.map(Some)
.map_err(|_| darling::Error::unknown_value(&v.value()).with_span(v))
} else {
Err(darling::Error::unexpected_lit_type(&mnv.lit))
}
} else {
Each::from_meta(meta).map(Some)
}
}
#[derive(Debug, Clone, Default, FromMeta)]
pub struct FieldLevelSetter {
prefix: Option<Ident>,
name: Option<Ident>,
into: Option<bool>,
strip_option: Option<bool>,
skip: Option<bool>,
custom: Option<bool>,
#[darling(with = "parse_each")]
each: Option<Each>,
}
impl FieldLevelSetter {
pub fn setter_enabled(&self) -> Option<bool> {
if self.custom.is_some() {
return self.custom.map(|x| !x);
}
self.field_enabled()
}
pub fn field_enabled(&self) -> Option<bool> {
if self.skip.is_some() {
return self.skip.map(|x| !x);
}
if self.prefix.is_some()
|| self.name.is_some()
|| self.into.is_some()
|| self.strip_option.is_some()
|| self.each.is_some()
{
return Some(true);
}
None
}
}
fn field_setter(meta: &Meta) -> darling::Result<FieldLevelSetter> {
if let Meta::Path(_) = meta {
Ok(FieldLevelSetter {
skip: Some(false),
..Default::default()
})
} else {
FieldLevelSetter::from_meta(meta)
}
}
#[derive(Debug, Clone, FromField)]
#[darling(
attributes(builder),
forward_attrs(doc, cfg, allow, builder_field_attr, builder_setter_attr),
and_then = "Self::resolve"
)]
pub struct Field {
ident: Option<Ident>,
attrs: Vec<syn::Attribute>,
ty: syn::Type,
pattern: Option<BuilderPattern>,
public: Flag,
private: Flag,
#[darling(rename = "vis")]
visibility: Option<syn::Visibility>,
#[darling(default, with = "field_setter")]
setter: FieldLevelSetter,
default: Option<DefaultExpression>,
try_setter: Flag,
#[darling(default)]
field: FieldLevelFieldMeta,
#[darling(skip)]
field_attrs: Vec<Attribute>,
#[darling(skip)]
setter_attrs: Vec<Attribute>,
}
impl Field {
fn no_visibility_conflicts(&self) -> darling::Result<()> {
let mut errors = Error::accumulator();
errors.handle(no_visibility_conflict(&self.field));
errors.handle(no_visibility_conflict(self));
errors.finish()
}
fn resolve(mut self) -> darling::Result<Self> {
let mut errors = darling::Error::accumulator();
if let Field {
default: Some(field_default),
..
} = &self
{
if self.field.build.is_some() {
errors.push(
darling::Error::custom(
r#"#[builder(default)] and #[builder(field(build="..."))] cannot be used together"#,
)
.with_span(field_default),
);
}
if self.field.builder_type.is_some() {
errors.push(
darling::Error::custom(
r#"#[builder(default)] and #[builder(field(type="..."))] cannot be used together"#,
)
.with_span(field_default)
)
}
};
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)
}
}
fn distribute_and_unnest_attrs(
input: &mut Vec<Attribute>,
outputs: &mut [(&'static str, &mut Vec<Attribute>)],
) -> darling::Result<()> {
let mut errors = vec![];
for (name, list) in &*outputs {
assert!(list.is_empty(), "Output Vec for '{}' was not empty", name);
}
for attr in input.drain(..) {
let destination = outputs
.iter_mut()
.find(|(ptattr, _)| attr.path.is_ident(ptattr));
if let Some((_, destination)) = destination {
match unnest_from_one_attribute(attr) {
Ok(n) => destination.push(n),
Err(e) => errors.push(e),
}
} else {
for (_, output) in outputs.iter_mut() {
output.push(attr.clone());
}
}
}
if !errors.is_empty() {
return Err(darling::Error::multiple(errors));
}
Ok(())
}
fn unnest_from_one_attribute(attr: syn::Attribute) -> darling::Result<Attribute> {
match &attr.style {
syn::AttrStyle::Outer => (),
syn::AttrStyle::Inner(bang) => {
return Err(darling::Error::unsupported_format(&format!(
"{} must be an outer attribute",
attr.path
.get_ident()
.map(Ident::to_string)
.unwrap_or_else(|| "Attribute".to_string())
))
.with_span(bang));
}
};
#[derive(Debug)]
struct ContainedAttribute(syn::Attribute);
impl syn::parse::Parse for ContainedAttribute {
fn parse(input: ParseStream) -> syn::Result<Self> {
let content;
let paren_token = parenthesized!(content in input);
let wrap_span = paren_token.span;
let pound = Token; let content: TokenStream = content.parse()?;
let content = quote_spanned!(wrap_span=> #pound [ #content ]);
let parser = syn::Attribute::parse_outer;
let mut attrs = parser.parse2(content)?.into_iter();
let attr = match (attrs.next(), attrs.next()) {
(Some(attr), None) => attr,
_ => return Err(input.error("expected exactly one attribute")),
};
Ok(Self(attr))
}
}
let ContainedAttribute(attr) = syn::parse2(attr.tokens)?;
Ok(attr)
}
impl Visibility for Field {
fn public(&self) -> &Flag {
&self.public
}
fn private(&self) -> &Flag {
&self.private
}
fn explicit(&self) -> Option<&syn::Visibility> {
self.visibility.as_ref()
}
}
fn default_crate_root() -> Path {
parse_quote!(::derive_builder)
}
fn default_create_empty() -> Ident {
Ident::new("create_empty", Span::call_site())
}
#[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"
)]
pub struct Options {
ident: Ident,
attrs: Vec<Attribute>,
#[darling(skip)]
struct_attrs: Vec<Attribute>,
#[darling(skip)]
impl_attrs: Vec<Attribute>,
vis: syn::Visibility,
generics: Generics,
name: Option<Ident>,
#[darling(rename = "crate", default = "default_crate_root")]
crate_root: Path,
#[darling(default)]
pattern: BuilderPattern,
#[darling(default)]
build_fn: BuildFn,
#[darling(default)]
derive: PathList,
custom_constructor: Flag,
#[darling(default = "default_create_empty")]
create_empty: Ident,
#[darling(default)]
setter: StructLevelSetter,
default: Option<DefaultExpression>,
public: Flag,
private: Flag,
#[darling(rename = "vis")]
visibility: Option<syn::Visibility>,
data: darling::ast::Data<darling::util::Ignored, Field>,
no_std: Flag,
try_setter: Flag,
#[darling(default)]
field: StructLevelFieldMeta,
#[darling(skip, default)]
deprecation_notes: DeprecationNotes,
}
impl Visibility for Options {
fn public(&self) -> &Flag {
&self.public
}
fn private(&self) -> &Flag {
&self.private
}
fn explicit(&self) -> Option<&syn::Visibility> {
self.visibility.as_ref()
}
}
impl Options {
fn unnest_attrs(mut self) -> darling::Result<Self> {
let mut errors = Error::accumulator();
errors.handle(distribute_and_unnest_attrs(
&mut self.attrs,
&mut [
("builder_struct_attr", &mut self.struct_attrs),
("builder_impl_attr", &mut self.impl_attrs),
],
));
errors.handle(no_visibility_conflict(&self.field));
errors.handle(no_visibility_conflict(&self.build_fn));
self.data
.as_ref()
.map_struct_fields(|f| errors.handle(f.no_visibility_conflicts()));
errors.handle(no_visibility_conflict(&self));
errors.finish_with(self)
}
}
impl Options {
pub fn builder_ident(&self) -> Ident {
if let Some(ref custom) = self.name {
return custom.clone();
}
format_ident!("{}Builder", self.ident)
}
pub fn builder_error_ident(&self) -> Path {
if let Some(existing) = self.build_fn.error.as_ref() {
existing.clone()
} else if let Some(ref custom) = self.name {
format_ident!("{}Error", custom).into()
} else {
format_ident!("{}BuilderError", self.ident).into()
}
}
pub fn builder_vis(&self) -> Cow<syn::Visibility> {
self.as_expressed_vis().unwrap_or(Cow::Borrowed(&self.vis))
}
pub fn build_method_vis(&self) -> Cow<syn::Visibility> {
self.build_fn
.as_expressed_vis()
.unwrap_or_else(|| self.builder_vis())
}
pub fn raw_fields(&self) -> Vec<&Field> {
self.data
.as_ref()
.take_struct()
.expect("Only structs supported")
.fields
}
pub fn requires_clone(&self) -> bool {
self.pattern.requires_clone() || self.fields().any(|f| f.pattern().requires_clone())
}
pub fn fields(&self) -> FieldIter {
FieldIter(self, self.raw_fields().into_iter())
}
pub fn field_count(&self) -> usize {
self.raw_fields().len()
}
}
impl Options {
pub fn as_builder(&self) -> Builder {
Builder {
crate_root: &self.crate_root,
enabled: true,
ident: self.builder_ident(),
pattern: self.pattern,
derives: &self.derive,
struct_attrs: &self.struct_attrs,
impl_attrs: &self.impl_attrs,
impl_default: !self.custom_constructor.is_present(),
create_empty: self.create_empty.clone(),
generics: Some(&self.generics),
visibility: self.builder_vis(),
fields: Vec::with_capacity(self.field_count()),
field_initializers: Vec::with_capacity(self.field_count()),
functions: Vec::with_capacity(self.field_count()),
generate_error: self.build_fn.error.is_none(),
must_derive_clone: self.requires_clone(),
doc_comment: None,
deprecation_notes: Default::default(),
std: !self.no_std.is_present(),
}
}
pub fn as_build_method(&self) -> BuildMethod {
let (_, ty_generics, _) = self.generics.split_for_impl();
BuildMethod {
crate_root: &self.crate_root,
enabled: !self.build_fn.skip,
ident: &self.build_fn.name,
visibility: self.build_method_vis(),
pattern: self.pattern,
target_ty: &self.ident,
target_ty_generics: Some(ty_generics),
error_ty: self.builder_error_ident(),
initializers: Vec::with_capacity(self.field_count()),
doc_comment: None,
default_struct: self.default.as_ref(),
validate_fn: self.build_fn.validate.as_ref(),
}
}
}
pub struct FieldWithDefaults<'a> {
parent: &'a Options,
field: &'a Field,
}
impl<'a> FieldWithDefaults<'a> {
pub fn setter_enabled(&self) -> bool {
self.field
.setter
.setter_enabled()
.or_else(|| self.parent.setter.enabled())
.unwrap_or(true)
}
pub fn field_enabled(&self) -> bool {
self.field
.setter
.field_enabled()
.or_else(|| self.parent.setter.enabled())
.unwrap_or(true)
}
pub fn try_setter(&self) -> bool {
self.field.try_setter.is_present() || self.parent.try_setter.is_present()
}
pub fn setter_prefix(&self) -> Option<&Ident> {
self.field
.setter
.prefix
.as_ref()
.or(self.parent.setter.prefix.as_ref())
}
pub fn setter_ident(&self) -> syn::Ident {
if let Some(ref custom) = self.field.setter.name {
return custom.clone();
}
let ident = &self.field.ident;
if let Some(ref prefix) = self.setter_prefix() {
return format_ident!("{}_{}", prefix, ident.as_ref().unwrap());
}
ident.clone().unwrap()
}
pub fn setter_into(&self) -> bool {
self.field
.setter
.into
.or(self.parent.setter.into)
.unwrap_or_default()
}
pub fn setter_strip_option(&self) -> bool {
self.field
.setter
.strip_option
.or(self.parent.setter.strip_option)
.unwrap_or_default()
}
pub fn setter_vis(&self) -> Cow<syn::Visibility> {
self.field
.as_expressed_vis()
.or_else(|| self.parent.as_expressed_vis())
.unwrap_or_else(|| Cow::Owned(syn::parse_quote!(pub)))
}
pub fn field_ident(&self) -> &syn::Ident {
self.field
.ident
.as_ref()
.expect("Tuple structs are not supported")
}
pub fn field_vis(&self) -> Cow<syn::Visibility> {
self.field
.field
.as_expressed_vis()
.or_else(
|| {
if self.field_enabled() {
None
} else {
Some(Cow::Owned(syn::Visibility::Inherited))
}
},
)
.or_else(|| self.parent.field.as_expressed_vis())
.unwrap_or(Cow::Owned(syn::Visibility::Inherited))
}
pub fn field_type(&'a self) -> BuilderFieldType<'a> {
if !self.field_enabled() {
BuilderFieldType::Phantom(&self.field.ty)
} else if let Some(custom_ty) = self.field.field.builder_type.as_ref() {
BuilderFieldType::Precise(custom_ty)
} else {
BuilderFieldType::Optional(&self.field.ty)
}
}
pub fn conversion(&'a self) -> FieldConversion<'a> {
match (&self.field.field.builder_type, &self.field.field.build) {
(_, Some(block)) => FieldConversion::Block(block),
(Some(_), None) => FieldConversion::Move,
(None, None) => FieldConversion::OptionOrDefault,
}
}
pub fn pattern(&self) -> BuilderPattern {
self.field.pattern.unwrap_or(self.parent.pattern)
}
pub fn use_parent_default(&self) -> bool {
self.field.default.is_none() && self.parent.default.is_some()
}
pub fn deprecation_notes(&self) -> &DeprecationNotes {
&self.parent.deprecation_notes
}
}
impl<'a> FieldWithDefaults<'a> {
pub fn as_setter(&'a self) -> Setter<'a> {
Setter {
crate_root: &self.parent.crate_root,
setter_enabled: self.setter_enabled(),
try_setter: self.try_setter(),
visibility: self.setter_vis(),
pattern: self.pattern(),
attrs: &self.field.setter_attrs,
ident: self.setter_ident(),
field_ident: self.field_ident(),
field_type: self.field_type(),
generic_into: self.setter_into(),
strip_option: self.setter_strip_option(),
deprecation_notes: self.deprecation_notes(),
each: self.field.setter.each.as_ref(),
}
}
pub fn as_initializer(&'a self) -> Initializer<'a> {
Initializer {
crate_root: &self.parent.crate_root,
field_enabled: self.field_enabled(),
field_ident: self.field_ident(),
builder_pattern: self.pattern(),
default_value: self.field.default.as_ref(),
use_default_struct: self.use_parent_default(),
conversion: self.conversion(),
custom_error_type_span: self
.parent
.build_fn
.error
.as_ref()
.map(|err_ty| err_ty.span()),
}
}
pub fn as_builder_field(&'a self) -> BuilderField<'a> {
BuilderField {
crate_root: &self.parent.crate_root,
field_ident: self.field_ident(),
field_type: self.field_type(),
field_visibility: self.field_vis(),
attrs: &self.field.field_attrs,
}
}
}
pub struct FieldIter<'a>(&'a Options, IntoIter<&'a Field>);
impl<'a> Iterator for FieldIter<'a> {
type Item = FieldWithDefaults<'a>;
fn next(&mut self) -> Option<Self::Item> {
self.1.next().map(|field| FieldWithDefaults {
parent: self.0,
field,
})
}
}