1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
use syn::{Data, DeriveInput, parse_macro_input};

#[proc_macro_derive(BpfApp, attributes(license, ringbuf, prog))]
pub fn derive_bpf_app(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let DeriveInput { ident, data, .. } = parse_macro_input!(input as DeriveInput);

    struct UserTokens<T> {
        map_cnt: T,
        prog_cnt: T,
        new_field: T,
        map_step: T,
        prog_step: T,
    }

    let ut = UserTokens {
        map_cnt: quote::quote! {},
        prog_cnt: quote::quote! {},
        new_field: quote::quote! {},
        map_step: quote::quote! {},
        prog_step: quote::quote! {},
    };

    let ut = match data {
        Data::Struct(data) => data.fields.into_iter().fold(ut, |ut, field| {
            let UserTokens {
                map_cnt,
                prog_cnt,
                new_field,
                map_step,
                prog_step,
            } = ut;
            let val = field.ident.unwrap();
            let val_str = format!("{}\0", val);
            let ty = field.ty;
            UserTokens {
                map_cnt: quote::quote! { #map_cnt + <#ty as ebpf_user::kind::AppItem>::MAP },
                prog_cnt: quote::quote! { #prog_cnt + <#ty as ebpf_user::kind::AppItem>::PROG },
                new_field: quote::quote! { #new_field #val: #ty::named(#val_str), },
                map_step: quote::quote! {
                    #map_step
                    if let ebpf_user::kind::AppItemKindMut::Map(v) = self.#val.kind_mut() {
                        if counter == index {
                            return Some(v);
                        } else {
                            counter += 1;
                        }
                    }
                },
                prog_step: quote::quote! {
                    #prog_step
                    if let ebpf_user::kind::AppItemKindMut::Prog(v) = self.#val.kind_mut() {
                        if counter == index {
                            return Some(v);
                        } else {
                            counter += 1;
                        }
                    }
                },
            }
        }),
        _ => unimplemented!(),
    };

    let UserTokens {
        map_cnt,
        prog_cnt,
        new_field,
        map_step,
        prog_step,
    } = ut;

    proc_macro::TokenStream::from(quote::quote! {
        impl ebpf_user::BpfApp for #ident {
            const MAP_CNT: usize = 0 #map_cnt;
            const PROG_CNT: usize = 0 #prog_cnt;

            fn instance() -> Self {
                use ebpf_user::kind::AppItem;

                #ident {
                    #new_field
                }
            }

            fn as_mut_map(&mut self, index: usize) -> Option<&mut ebpf_user::MapRef> {
                use ebpf_user::kind::AppItem;

                let mut counter = 0;
                #map_step
                let _ = counter;
                None
            }

            fn as_mut_prog(&mut self, index: usize) -> Option<&mut ebpf_user::ProgRef> {
                use ebpf_user::kind::AppItem;

                let mut counter = 0;
                #prog_step
                let _ = counter;
                None
            }
        }
    })
}