use syn::spanned::Spanned;
use syn::{Attribute, Error as SynError, Ident, ItemStruct, Result as SynResult, Type};
use super::FieldParams;
pub struct StructField {
pub params: Option<FieldParams>,
pub name: String,
pub ty: Type,
pub ident: Ident,
}
impl StructField {
pub fn from_struct(item: &ItemStruct) -> SynResult<Vec<Self>> {
let mut fields = Vec::new();
for field in &item.fields {
let ident = field
.ident
.as_ref()
.ok_or_else(|| SynError::new(field.span(), "Unnamed field not supported"))?;
fields.push(Self {
name: ident.to_string(),
ident: ident.clone(),
ty: field
.ty
.clone(),
params: field
.attrs
.iter()
.find(|attr| is_field_attr(attr))
.map(|attr| attr.parse_args::<FieldParams>())
.transpose()?,
});
}
Ok(fields)
}
}
fn is_field_attr(attr: &Attribute) -> bool {
let allowed_attrs =
["env_override", "arg_override", "name", "insensitive", "default", "description", "field"];
attr.path()
.get_ident()
.is_some_and(|ident| {
allowed_attrs
.iter()
.any(|allowed| ident == allowed)
})
}
pub fn remove_field_attrs(item: &mut ItemStruct) {
item.fields
.iter_mut()
.for_each(|field| {
field
.attrs
.retain(|attr| !is_field_attr(attr));
});
}