use quote::{ToTokens, Tokens};
use syn;
use Bindings;
#[derive(Debug, Clone)]
pub struct BuilderField<'a> {
pub field_ident: &'a syn::Ident,
pub field_type: &'a syn::Type,
pub setter_enabled: bool,
pub field_visibility: syn::Visibility,
pub attrs: &'a [syn::Attribute],
pub bindings: Bindings,
}
impl<'a> ToTokens for BuilderField<'a> {
fn to_tokens(&self, tokens: &mut Tokens) {
if self.setter_enabled {
trace!("Deriving builder field for `{}`.", self.field_ident);
let vis = &self.field_visibility;
let ident = self.field_ident;
let ty = self.field_type;
let attrs = self.attrs;
let option = self.bindings.option_ty();
tokens.append_all(quote!(
#(#attrs)* #vis #ident: #option<#ty>,
));
} else {
trace!(
"Skipping builder field for `{}`, fallback to PhantomData.",
self.field_ident
);
let ident = self.field_ident;
let ty = self.field_type;
let attrs = self.attrs;
let phantom_data = self.bindings.phantom_data_ty();
tokens.append_all(quote!(
#(#attrs)* #ident: #phantom_data<#ty>,
));
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! default_builder_field {
() => {{
use syn::synom::Parser;
named!(outer_attrs -> Vec<syn::Attribute>, many0!(syn::Attribute::parse_outer));
BuilderField {
field_ident: &syn::Ident::from("foo"),
field_type: &syn::parse_str("String").unwrap(),
setter_enabled: true,
field_visibility: syn::parse_str("pub").unwrap(),
attrs: &outer_attrs.parse_str("#[some_attr]").unwrap(),
bindings: Default::default(),
}
}};
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use super::*;
#[test]
fn setter_enabled() {
let field = default_builder_field!();
assert_eq!(
quote!(#field),
quote!(
#[some_attr] pub foo: ::std::option::Option<String>,
)
);
}
#[test]
fn setter_disabled() {
let mut field = default_builder_field!();
field.setter_enabled = false;
assert_eq!(
quote!(#field),
quote!(
#[some_attr]
foo: ::std::marker::PhantomData<String>,
)
);
}
#[test]
fn no_std_setter_enabled() {
let mut field = default_builder_field!();
field.bindings.no_std = true;
assert_eq!(
quote!(#field),
quote!(
#[some_attr] pub foo: ::core::option::Option<String>,
)
);
}
#[test]
fn no_std_setter_disabled() {
let mut field = default_builder_field!();
field.bindings.no_std = true;
field.setter_enabled = false;
assert_eq!(
quote!(#field),
quote!(
#[some_attr]
foo: ::core::marker::PhantomData<String>,
)
);
}
#[test]
fn private_field() {
let private = syn::Visibility::Inherited;
let mut field = default_builder_field!();
field.field_visibility = private;
assert_eq!(
quote!(#field),
quote!(
#[some_attr]
foo: ::std::option::Option<String>,
)
);
}
}