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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
extern crate proc_macro;
use self::proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;
use syn::parse::{Parse, ParseStream, Result};
use syn::{parse_macro_input, Expr, Ident, LitStr, Token, Type};
struct RegisterBit {
const_name: Ident,
const_value: Expr,
const_type: Type,
get_set_name: Ident,
}
impl Parse for RegisterBit {
fn parse(input: ParseStream) -> Result<Self> {
let const_name: Ident = input.parse()?;
input.parse::<Token![,]>()?;
let const_type: Type = input.parse()?;
input.parse::<Token![,]>()?;
let const_value: Expr = input.parse()?;
input.parse::<Token![,]>()?;
let get_set_name: Ident = input.parse()?;
Ok(RegisterBit {
const_name,
const_value,
const_type,
get_set_name,
})
}
}
#[proc_macro]
pub fn register_bit(input: TokenStream) -> TokenStream {
let RegisterBit {
const_name,
const_value,
const_type,
get_set_name,
} = parse_macro_input!(input as RegisterBit);
let read_fn = {
let read_name = get_set_name.clone();
quote! {
pub fn #read_name(&self) -> bool {
(self.0 & Self::#const_name) != 0
}
}
};
let write_fn = {
let write_name = Ident::new(&format!("set_{}", get_set_name), Span::call_site());
quote! {
pub fn #write_name(&mut self, bit: bool) {
if bit {
self.0 |= Self::#const_name;
} else {
self.0 &= !Self::#const_name;
}
}
}
};
TokenStream::from(quote! {
pub const #const_name: #const_type = #const_value;
#read_fn
#write_fn
})
}
struct NewtypeDeclaration {
newtype_name: Type,
base_type: Type,
doc_comments: LitStr,
}
impl Parse for NewtypeDeclaration {
fn parse(input: ParseStream) -> Result<Self> {
let newtype_name: Type = input.parse()?;
input.parse::<Token![,]>()?;
let base_type: Type = input.parse()?;
let doc_comments: LitStr = if input.is_empty() {
LitStr::new("", Span::call_site())
} else {
input.parse::<Token![,]>()?;
input.parse()?
};
Ok(NewtypeDeclaration {
newtype_name,
base_type,
doc_comments,
})
}
}
#[proc_macro]
pub fn newtype(input: TokenStream) -> TokenStream {
let NewtypeDeclaration {
newtype_name,
base_type,
doc_comments,
} = parse_macro_input!(input as NewtypeDeclaration);
TokenStream::from(quote! {
#[doc = #doc_comments]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct #newtype_name(#base_type);
impl From<#newtype_name> for #base_type {
fn from(x: #newtype_name) -> #base_type {
x.0
}
}
})
}