use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
use syn;
pub struct Field {
pub id: FieldId,
pub ty: syn::Type,
}
pub enum FieldId {
Named(syn::Ident),
Unnamed(syn::Index),
}
impl Field {
fn from_syn(index: usize, orig: &syn::Field, span: Span) -> Self {
let id = orig.ident.clone().map(FieldId::Named).unwrap_or_else(|| {
FieldId::Unnamed(syn::Index {
index: index as u32,
span,
})
});
Field {
id,
ty: orig.ty.clone(),
}
}
}
impl ToTokens for FieldId {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
FieldId::Named(id) => id.to_tokens(tokens),
FieldId::Unnamed(idx) => idx.to_tokens(tokens),
}
}
}
pub struct StructData {
pub name: syn::Ident,
pub field_idents: Vec<Field>,
pub generics: syn::Generics,
}
impl StructData {
pub fn new(data_struct: &syn::DataStruct, ident: syn::Ident, generics: syn::Generics) -> Self {
let span = ident.span();
StructData {
name: ident,
field_idents: get_fields(data_struct.fields.iter(), span),
generics,
}
}
pub fn add_bound(&mut self, bound: &str) {
let bound = syn::TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: syn::Ident::new(bound, Span::call_site()).into(),
};
self.generics.type_params_mut().for_each(|param| {
param.bounds.push(bound.clone().into());
});
}
}
fn get_fields<'a>(fields: impl IntoIterator<Item = &'a syn::Field>, span: Span) -> Vec<Field> {
fields
.into_iter()
.enumerate()
.map(|(i, field)| Field::from_syn(i, field, span))
.collect()
}