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()
}