use darling::{FromDeriveInput, FromField, util::Flag};
use syn::{Expr, Generics, Ident, Type};
#[derive(Debug, Clone)]
pub enum DefaultValue {
Bare,
Expression(Expr),
}
impl darling::FromMeta for DefaultValue {
fn from_word() -> darling::Result<Self> {
Ok(DefaultValue::Bare)
}
fn from_value(value: &syn::Lit) -> darling::Result<Self> {
match value {
syn::Lit::Str(s) => {
let expr: Expr = syn::parse_str(&s.value())?;
Ok(DefaultValue::Expression(expr))
}
_ => Err(darling::Error::unexpected_lit_type(value)),
}
}
}
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(builder), supports(struct_named))]
pub struct Input {
ident: Ident,
generics: Generics,
data: darling::ast::Data<(), InputField>,
#[darling(rename = "name")]
builder_name: Option<String>,
}
impl Input {
pub fn ident(&self) -> &Ident {
&self.ident
}
pub fn generics(&self) -> &Generics {
&self.generics
}
pub fn data(&self) -> darling::ast::Data<&(), &InputField> {
self.data.as_ref()
}
pub fn builder_name(&self) -> String {
self.builder_name
.clone()
.unwrap_or_else(|| format!("{}Builder", self.ident))
}
}
#[derive(Debug, FromField)]
#[darling(attributes(builder))]
pub struct InputField {
ident: Option<Ident>,
ty: Type,
#[darling(rename = "optional", default)]
optional_flag: Flag,
#[darling(rename = "required", default)]
required_flag: Flag,
#[darling(rename = "required_if", default)]
required_if: Option<String>,
#[darling(rename = "optional_if", default)]
optional_if: Option<String>,
#[darling(rename = "default", default)]
default: Option<DefaultValue>,
#[darling(rename = "into", default)]
into_flag: Flag,
}
impl InputField {
pub fn ident(&self) -> Option<&Ident> {
self.ident.as_ref()
}
pub fn ty(&self) -> &Type {
&self.ty
}
pub fn requirement(&self) -> syn::Result<Requirement> {
let attribute_count = self.optional_flag.is_present() as u8
+ self.required_flag.is_present() as u8
+ self.required_if.is_some() as u8
+ self.optional_if.is_some() as u8
+ self.default.is_some() as u8;
if attribute_count > 1 {
return Err(syn::Error::new(
self.ident.as_ref().unwrap().span(),
"Multiple builder attributes specified. Only one of required, optional, required_if, optional_if, default is allowed",
));
}
if self.default.is_some() {
Ok(Requirement::Default)
} else if let Some(opt_if) = &self.optional_if {
let expr_result: Result<Expr, _> = syn::parse_str(opt_if);
let expr: Expr = expr_result?;
Ok(Requirement::OptionalIf(expr))
} else if let Some(req_if) = &self.required_if {
let expr_result: Result<Expr, _> = syn::parse_str(req_if);
let expr: Expr = expr_result?;
Ok(Requirement::Conditional(expr))
} else if self.required_flag.is_present() {
Ok(Requirement::Always)
} else if self.optional_flag.is_present() {
Ok(Requirement::Optional)
} else {
Err(syn::Error::new(
self.ident.as_ref().unwrap().span(),
"missing required field",
))
}
}
pub fn default(&self) -> Option<&DefaultValue> {
self.default.as_ref()
}
pub fn into(&self) -> bool {
self.into_flag.is_present()
}
}
pub enum Requirement {
Always,
Optional,
Conditional(Expr),
OptionalIf(Expr),
Default,
}