1#![recursion_limit="128"]
2extern crate proc_macro;
3extern crate proc_macro2;
4extern crate quote;
5extern crate syn;
6
7use proc_macro::TokenStream;
8use proc_macro2::Span;
9use quote::{quote, ToTokens};
10use syn::{
11 parse, parse::{Parse, ParseStream},
12 punctuated::Punctuated,
13 Ident, Visibility, Type, LitInt, token,
14 Token, bracketed, braced
15};
16
17#[derive(Clone)]
18struct BfField {
19 vis: Visibility,
20 name: Ident,
21 start_pos: LitInt,
22 end_pos: LitInt,
23}
24
25impl Parse for BfField {
26 fn parse(stream: ParseStream) -> Result<Self, parse::Error> {
27 let (vis, name) = if stream.fork().parse::<Visibility>().is_ok() {
28 (stream.parse()?, stream.parse()?)
29 } else {
30 (Visibility::Inherited, stream.parse()?)
31 };
32 token::Colon::parse(stream)?;
33
34 let start_pos = stream.parse()?;
35 token::Colon::parse(stream)?;
36 let end_pos = stream.parse()?;
37
38 Ok(Self {
39 vis: vis,
40 name: name,
41 start_pos: start_pos,
42 end_pos: end_pos
43 })
44 }
45}
46
47#[derive(Clone)]
48struct BfInfo {
49 vis: Visibility,
50 name: Ident,
51 ty: Type,
52 fields: Vec<BfField>
53}
54
55impl Parse for BfInfo {
56 fn parse(stream: ParseStream) -> Result<Self, parse::Error> {
57 let (vis, name) = if stream.fork().parse::<Visibility>().is_ok() {
58 (stream.parse()?, stream.parse()?)
59 } else {
60 (Visibility::Inherited, stream.parse()?)
61 };
62
63 let ty_inner;
64 bracketed!(ty_inner in stream);
65 let ty = ty_inner.parse()?;
66
67 let fields_inner;
68 braced!(fields_inner in stream);
69
70 let field_parser = Punctuated::<BfField, Token![,]>::parse_terminated;
71 let fields = field_parser(&fields_inner)?;
72 let fields = fields.iter().cloned().collect();
73
74 Ok(Self {
75 vis: vis,
76 name: name,
77 ty: ty,
78 fields: fields
79 })
80 }
81}
82
83fn make_accessor(ty: &Type, field: &BfField) -> impl ToTokens {
84 let BfField { vis, name, start_pos, end_pos } = field;
85 let set_name = Ident::new(&format!("set_{}", name), Span::call_site());
86 let upd_name = Ident::new(&format!("upd_{}", name), Span::call_site());
87
88 let base_mask_const = quote!(
89 const BASE_MASK: #ty = (1 << (#end_pos - #start_pos + 1)) - 1;
90 );
91
92 quote!(
93 #[inline(always)]
94 #[allow(dead_code)]
95 #vis fn #name(&self) -> #ty {
96 #base_mask_const
97 (self.val >> #start_pos) & BASE_MASK
98 }
99
100 #[inline(always)]
101 #[allow(dead_code)]
102 #vis fn #set_name(&mut self, val: #ty) -> &mut Self {
103 #base_mask_const
104 self.val &= !(BASE_MASK << #start_pos);
105 self.val |= (val & BASE_MASK) << #start_pos;
106 self
107 }
108
109 #[inline(always)]
110 #[allow(dead_code)]
111 #vis fn #upd_name<F>(&mut self, func: F) -> &mut Self
112 where F: FnOnce(#ty) -> #ty {
113 let old = self.#name();
114 self.#set_name(func(old))
115 }
116 )
117}
118
119#[cfg(feature="use_std")]
120fn make_debug<'a>(name: &Ident, fields: impl Iterator<Item=&'a Ident>) -> impl ToTokens {
121 let (field_names, fields): (Vec<_>, Vec<_>) = fields.map(|f| (f.to_string(), f)).unzip();
122 quote!(
123 impl ::std::fmt::Debug for #name {
124 fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
125 f.debug_struct(stringify!(#name))
126 #(.field(#field_names, &self.#fields()))*
127 .finish()
128 }
129 }
130 )
131}
132
133
134#[cfg(not(feature="use_std"))]
135fn make_debug<'a>(_: &Ident, _: impl Iterator<Item=&'a Ident>) -> impl ToTokens {
136 quote!()
137}
138
139#[proc_macro]
140pub fn bf(tok: TokenStream) -> TokenStream {
141 let bfinfo: BfInfo = parse(tok).unwrap();
142 let BfInfo{vis, name, ty, fields} = bfinfo;
143 let accessors = fields.iter()
144 .map(|f| make_accessor(&ty, f));
145
146 let fmt = make_debug(&name, fields.iter().map(|f| &f.name));
147
148 quote!(
149 #[derive(Copy, Clone)]
150 #[repr(transparent)]
151 #vis struct #name {
152 pub val: #ty
153 }
154
155 impl #name {
156 #[inline(always)]
157 pub fn new(val: #ty) -> Self {
158 Self { val: val }
159 }
160
161 #[allow(dead_code)]
162 #[inline(always)]
163 pub fn alias<'a>(val: &'a #ty) -> &'a Self {
164 unsafe { &*(val as *const #ty as *const Self) }
165 }
166
167 #[allow(dead_code)]
168 #[inline(always)]
169 pub fn alias_mut<'a>(val: &'a mut #ty) -> &'a mut Self {
170 unsafe { &mut *(val as *mut #ty as *mut Self) }
171 }
172
173 #(#accessors)*
174 }
175
176 #fmt
177 ).into()
178}