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
#![feature(box_patterns)]
#![feature(box_syntax)]
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::Span;
use proc_macro_error::proc_macro_error;
use quote::quote;
use syn::{parse_macro_input, parse_quote, ItemEnum, LitInt, Type};

use crate::bit_access::BitAccess;

mod bit_access;
mod bit_field;
mod common;
mod extra_enum_access;
mod field_level_macro_arguments;
mod top_level_macro_arguments;

#[proc_macro_attribute]
#[proc_macro_error]
pub fn bitaccess(args: TokenStream, input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as ItemEnum);

    let tokens = BitAccess::new(args.into(), input)
        .expect("BitAccess::new")
        .into_token_stream();

    tokens.into()
}

#[proc_macro_derive(FieldAccess, attributes(field_access))]
#[proc_macro_error]
pub fn field_access(item: TokenStream) -> TokenStream {
    let item = parse_macro_input!(item as ItemEnum);
    let name = item.ident;
    let btattr = item
        .attrs
        .iter()
        .find(|attr| attr.path.is_ident("field_access"))
        .expect("missing field_access attribute on derivec(FieldAccess)");
    let base_type: Type = btattr
        .parse_args_with(<Type as syn::parse::Parse>::parse)
        .expect("expected base_type value in field_access attribute");

    let mut matchers = Vec::new();
    let mut val_matchers = Vec::new();
    let mut acc = 0;
    for item in item.variants {
        let item_name = item.ident;
        if let Some((_, val)) = item.discriminant {
            let lit: LitInt = parse_quote! { #val };
            acc = lit.base10_parse().expect("parse literal");
        }
        let acc_lit: LitInt = LitInt::new(&acc.to_string(), Span::call_site());

        matchers.push(quote! {
            #name::#item_name => #acc_lit,
        });
        val_matchers.push(quote! {
            #acc_lit => #name::#item_name,
        });
        acc += 1;
    }

    let ts = quote! {
        impl FieldAccess<#base_type> for #name {
            fn to_raw(&self) -> #base_type {
                match self {
                    #(#matchers)*
                }
            }
        }

        impl From<#name> for bitaccess::Field<#base_type, #name> {
            fn from(e: #name) -> Self {
                bitaccess::Field::new(e.to_raw())
            }
        }

        impl From<#base_type> for #name {
            fn from(v: #base_type) -> Self {
                match v {
                    #(#val_matchers)*
                    _ => panic!("unknown value for {}", stringify!(#name)),
                }
            }
        }
    };

    ts.into()
}