mirror of https://github.com/aya-rs/aya
xtask: use aya-gen to generate the getters
parent
b66a73f6c7
commit
7ae3ddf2fa
@ -1,125 +0,0 @@
|
||||
use indexmap::IndexMap;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, TokenStreamExt};
|
||||
use syn::{
|
||||
self, Fields, FieldsNamed, Generics, Ident, Item, ItemStruct, ItemUnion, Path, Type, TypePath,
|
||||
Visibility,
|
||||
};
|
||||
|
||||
pub struct GetterList<'a> {
|
||||
slf: Ident,
|
||||
item_fields: IndexMap<Ident, (&'a Item, &'a FieldsNamed)>,
|
||||
}
|
||||
|
||||
impl<'a> GetterList<'a> {
|
||||
pub fn new(items: &'a [Item]) -> GetterList<'a> {
|
||||
let item_fields = items
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
unpack_item(item).map(|(ident, _generics, fields)| (ident.clone(), (item, fields)))
|
||||
})
|
||||
.collect();
|
||||
GetterList {
|
||||
slf: Ident::new("self", Span::call_site()),
|
||||
item_fields,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&'a Item, Vec<Getter<'_>>)> {
|
||||
self.item_fields
|
||||
.values()
|
||||
.map(move |(item, fields)| (*item, self.getters(&self.slf, fields)))
|
||||
}
|
||||
|
||||
fn getters(&self, ident: &'a Ident, fields: &'a FieldsNamed) -> Vec<Getter<'a>> {
|
||||
let mut getters = Vec::new();
|
||||
for field in &fields.named {
|
||||
if field.vis == Visibility::Inherited {
|
||||
continue;
|
||||
}
|
||||
|
||||
let field_ident = field.ident.as_ref().unwrap();
|
||||
let field_s = field_ident.to_string();
|
||||
|
||||
// FIXME: bindgen generates fields named `_bitfield_N` for bitfields. If a type T has
|
||||
// two or more unions with bitfields, the getters for the bitfields - generated in impl
|
||||
// T - will clash. To avoid that we skip getters for bitfields altogether for now.
|
||||
// See sk_reuseport_md for an example where the clash happens.
|
||||
if field_s.starts_with("_bitfield") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if field_s.starts_with("__bindgen_anon") {
|
||||
let field_ty_ident = match &field.ty {
|
||||
Type::Path(TypePath {
|
||||
path: Path { segments, .. },
|
||||
..
|
||||
}) => &segments.first().unwrap().ident,
|
||||
_ => panic!(),
|
||||
};
|
||||
let sub_fields = self
|
||||
.item_fields
|
||||
.get(field_ty_ident)
|
||||
.expect(&field_ident.to_string())
|
||||
.1;
|
||||
getters.extend(self.getters(field_ident, sub_fields).drain(..).map(
|
||||
|mut getter| {
|
||||
getter.prefix.insert(0, ident);
|
||||
getter
|
||||
},
|
||||
));
|
||||
} else {
|
||||
getters.push(Getter {
|
||||
ident: field_ident,
|
||||
prefix: vec![ident],
|
||||
ty: &field.ty,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getters
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_getters_for_items(
|
||||
items: &[Item],
|
||||
gen_getter: fn(&Getter<'_>) -> TokenStream,
|
||||
) -> TokenStream {
|
||||
let mut tokens = TokenStream::new();
|
||||
tokens.append_all(GetterList::new(&items).iter().map(|(item, getters)| {
|
||||
let getters = getters.iter().map(gen_getter);
|
||||
let (ident, generics, _) = unpack_item(item).unwrap();
|
||||
quote! {
|
||||
impl#generics #ident#generics {
|
||||
#(#getters)*
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
tokens
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Getter<'a> {
|
||||
pub ident: &'a Ident,
|
||||
pub prefix: Vec<&'a Ident>,
|
||||
pub ty: &'a Type,
|
||||
}
|
||||
|
||||
fn unpack_item(item: &Item) -> Option<(&Ident, &Generics, &FieldsNamed)> {
|
||||
match item {
|
||||
Item::Struct(ItemStruct {
|
||||
ident,
|
||||
generics,
|
||||
fields: Fields::Named(fields),
|
||||
..
|
||||
})
|
||||
| Item::Union(ItemUnion {
|
||||
ident,
|
||||
generics,
|
||||
fields,
|
||||
..
|
||||
}) => Some((ident, generics, fields)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue