use syn::spanned::Spanned as _;
use crate::ir::VariantDefinition;
use crate::ir::VariantFields;
use crate::parse::PartitionedAttrs;
use crate::parse::parse_named_field;
use crate::parse::partition_attrs;
#[derive(Default)]
struct VariantArgs {
is_default: bool,
}
fn parse_config_attribute(attr: &syn::Attribute) -> syn::Result<VariantArgs> {
let mut args = VariantArgs::default();
if let syn::Meta::Path(_) = &attr.meta {
return Ok(args);
}
attr.parse_nested_meta(|meta| {
let ident = meta.path.require_ident()?;
match ident.to_string().as_str() {
"default" => {
args.is_default = true;
}
_ => return Err(meta.error("unrecognized config attribute for variant")),
}
Ok(())
})?;
Ok(args)
}
pub(crate) fn parse_variant(input: syn::Variant) -> syn::Result<VariantDefinition> {
let syn::Variant {
attrs,
ident,
fields,
discriminant: _,
} = input;
let PartitionedAttrs {
config: config_attrs,
cfg: cfg_attrs,
other: attrs,
} = partition_attrs(attrs);
let args = match config_attrs.as_slice() {
[] => Default::default(),
[attr] => parse_config_attribute(attr)?,
[_attr, extra, ..] => {
return Err(syn::Error::new(
extra.span(),
"only one #[config] attribute is allowed per variant",
));
}
};
let parsed_fields = match fields {
syn::Fields::Unit => VariantFields::Unit,
syn::Fields::Unnamed(fields) => VariantFields::Tuple(fields),
syn::Fields::Named(fields) => {
let field_definitions = fields
.named
.into_iter()
.map(parse_named_field)
.collect::<Result<Vec<_>, _>>()?;
VariantFields::Struct(field_definitions)
}
};
Ok(VariantDefinition {
name: ident,
attrs,
cfg_attrs,
fields: parsed_fields,
is_default: args.is_default,
})
}