use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{Data, DataEnum, DataStruct, DataUnion, Field, Index, Type};
pub(crate) trait DataExt {
fn fields(&self) -> Vec<(TokenStream, &Type)>;
}
impl DataExt for Data {
fn fields(&self) -> Vec<(TokenStream, &Type)> {
match self {
Data::Struct(strc) => strc.fields(),
Data::Enum(enm) => enm.fields(),
Data::Union(un) => un.fields(),
}
}
}
impl DataExt for DataStruct {
fn fields(&self) -> Vec<(TokenStream, &Type)> {
map_fields(&self.fields)
}
}
impl DataExt for DataEnum {
fn fields(&self) -> Vec<(TokenStream, &Type)> {
map_fields(self.variants.iter().flat_map(|var| &var.fields))
}
}
impl DataExt for DataUnion {
fn fields(&self) -> Vec<(TokenStream, &Type)> {
map_fields(&self.fields.named)
}
}
fn map_fields<'a>(
fields: impl 'a + IntoIterator<Item = &'a Field>,
) -> Vec<(TokenStream, &'a Type)> {
fields
.into_iter()
.enumerate()
.map(|(idx, f)| {
(
f.ident
.as_ref()
.map(ToTokens::to_token_stream)
.unwrap_or_else(|| Index::from(idx).to_token_stream()),
&f.ty,
)
})
.collect()
}
pub(crate) trait EnumExt {
fn is_fieldless(&self) -> bool;
}
impl EnumExt for DataEnum {
fn is_fieldless(&self) -> bool {
self.fields().is_empty()
}
}