btf_derive/
lib.rs

1use proc_macro::TokenStream;
2use proc_macro2::TokenStream as TokenStream2;
3use quote::quote;
4use regex::Regex;
5use syn::{parse_macro_input, DeriveInput, Type};
6
7/// This function converts syn's string representation of typenames to
8/// the format used by std::any::type_name.
9fn canonicalized_type_name(ty: &Type) -> String {
10    let type_name = quote! {#ty}.to_string();
11    let re = Regex::new(r"\s*;\s*").expect("Bad regex");
12    re.replace_all(&type_name, r"; ").to_string()
13}
14
15/// Recursively adds inner types to the auto_types list.
16fn add_type(ty: &Type, auto_types: &mut Vec<TokenStream2>) {
17    match ty {
18        Type::Array(a) => add_type(&a.elem, auto_types),
19        Type::Tuple(t) => {
20            for elem in &t.elems {
21                add_type(elem, auto_types);
22            }
23        }
24        _ => (),
25    }
26
27    auto_types.push(quote! {
28        <#ty>::add_to_btf(btf)?;
29    });
30}
31
32/// Implements AddToBtf for the type. If the type is a structure, it will
33/// create a new BTF type for the structure with the same name and all its
34/// inner field types.
35#[proc_macro_derive(AddToBtf, attributes(field))]
36pub fn derive_add_to_bpf(input: TokenStream) -> TokenStream {
37    let input: DeriveInput = parse_macro_input!(input);
38    let name = &input.ident;
39
40    let mut auto_types = vec![];
41    let mut fields = vec![];
42    match input.data {
43        syn::Data::Struct(s) => {
44            for field in s.fields {
45                let field_name = field.ident.expect("Field has no name").to_string();
46                let ty = field.ty;
47                add_type(&ty, &mut auto_types);
48                let type_name = canonicalized_type_name(&ty);
49                fields.push(quote! {(#field_name, #type_name)})
50            }
51        }
52        _ => panic!("Not a structure."),
53    }
54
55    let gen = quote! {
56        impl AddToBtf for #name {
57            fn add_to_btf(btf: &mut btf::BtfTypes) -> Option<&btf::types::Type> {
58                const STRUCT_FIELDS: &[(&str, &str)] = &[#(#fields),*];
59                usize::add_to_btf(btf)?;
60                #(#auto_types)*
61                btf.add_struct(stringify!(#name), STRUCT_FIELDS)
62            }
63        }
64    };
65
66    gen.into()
67}