1#[macro_export]
2#[doc(hidden)]
3macro_rules! check_field_mask {
4 (bool, $mask:expr, $name:ident) => {
5 assert!(
6 $mask != 0,
7 concat!("Mask for field ", stringify!($name), " is zero.")
8 );
9 assert!(
10 ($mask as usize).is_power_of_two(),
11 concat!(
12 "Field ",
13 stringify!($name),
14 " is of type boolean, but it's mask isn't a power of two."
15 )
16 );
17 };
18 ($field_type:ty, $mask:expr, $name:ident) => {
19 assert!(
20 $mask != 0,
21 concat!("Mask for field ", stringify!($name), " is zero.")
22 );
23 assert!(
24 (($mask >> 1 ^ $mask) as usize).count_ones() <= 2,
25 concat!("Mask for field ", stringify!($name), " is discontinous.")
26 );
27 };
28}
29#[macro_export]
30#[doc(hidden)]
31macro_rules! read_field {
32 (bool, $representation:ty, $shifted_value:expr) => {
33 $shifted_value != 0
34 };
35 (u8, $representation:ty, $shifted_value:expr) => {
36 $shifted_value as u8
37 };
38 (i8, $representation:ty, $shifted_value:expr) => {
39 $shifted_value as i8
40 };
41 (u16, $representation:ty, $shifted_value:expr) => {
42 $shifted_value as u16
43 };
44 (i16, $representation:ty, $shifted_value:expr) => {
45 $shifted_value as i16
46 };
47 (u32, $representation:ty, $shifted_value:expr) => {
48 $shifted_value as u32
49 };
50 (i32, $representation:ty, $shifted_value:expr) => {
51 $shifted_value as i32
52 };
53 (u64, $representation:ty, $shifted_value:expr) => {
54 $shifted_value as u64
55 };
56 (i64, $representation:ty, $shifted_value:expr) => {
57 $shifted_value as i64
58 };
59 (u128, $representation:ty, $shifted_value:expr) => {
60 $shifted_value as u128
61 };
62 (i128, $representation:ty, $shifted_value:expr) => {
63 $shifted_value as i128
64 };
65 ($field_type:ty, $representation:ty, $shifted_value:expr) => {
66 <$field_type as From<$representation>>::from($shifted_value)
67 };
68}
69#[macro_export]
70#[doc(hidden)]
71macro_rules! write_field {
72 (bool, $representation:ty, $shifted_value:expr) => {
73 $shifted_value as $representation
74 };
75 (u8, $representation:ty, $shifted_value:expr) => {
76 $shifted_value as $representation
77 };
78 (i8, $representation:ty, $shifted_value:expr) => {
79 $shifted_value as $representation
80 };
81 (u16, $representation:ty, $shifted_value:expr) => {
82 $shifted_value as $representation
83 };
84 (i16, $representation:ty, $shifted_value:expr) => {
85 $shifted_value as $representation
86 };
87 (u32, $representation:ty, $shifted_value:expr) => {
88 $shifted_value as $representation
89 };
90 (i32, $representation:ty, $shifted_value:expr) => {
91 $shifted_value as $representation
92 };
93 (u64, $representation:ty, $shifted_value:expr) => {
94 $shifted_value as $representation
95 };
96 (i64, $representation:ty, $shifted_value:expr) => {
97 $shifted_value as $representation
98 };
99 (u128, $representation:ty, $shifted_value:expr) => {
100 $shifted_value as $representation
101 };
102 (i128, $representation:ty, $shifted_value:expr) => {
103 $shifted_value as $representation
104 };
105 ($field_type:ty, $representation:ty, $shifted_value:expr) => {
106 <$representation as From<$field_type>>::from($shifted_value)
107 };
108}
109#[macro_export]
110macro_rules! bitfield {
135 (
136 $(#[$attr:meta])*
137 $struct_vis:vis struct $struct_name:ident : $struct_representation:ty {
138 $(
139 $(#[$field_attr:meta])*
140 $field_vis:vis $field_name:ident : $field_type:ty => $field_mask:expr
141 ),*
142 }
143 ) => {
144 ::macro_bits::defile::defile! {
145
146 $(#[$attr])*
147 $struct_vis struct $struct_name {
149 $(
150 $(#[$field_attr])*
151 $field_vis $field_name: $field_type
152 ),*
153 }
154 #[allow(ineffective_bit_mask)]
155 impl $struct_name {
157 const _BITFIELD_PROOF: () = {
159 assert!(
161 ($($field_mask)^+) == $($field_mask)|+,
162 "Masks are overlapping."
163 );
164 $(
166 assert!(
167 $field_mask <= <$struct_representation>::MAX,
168 concat!("Mask for field ",
169 stringify!($field_name),
170 " is larger than the representation type."
171 )
172 );
173 )*
174 $(
176 ::macro_bits::check_field_mask!($field_type, $field_mask, $field_name);
177 )*
178 };
179 pub fn from_bits(value: $struct_representation) -> Self {
180 $(
181 let $field_name =
182 ::macro_bits::read_field!(
183 $field_type,
184 $struct_representation,
185 (value & $field_mask) >> ($field_mask as usize).trailing_zeros()
186 );
187 )+
188 Self {
189 $(
190 $field_name,
191 )+
192 }
193 }
194 pub fn into_bits(self) -> $struct_representation {
195 let mut data: $struct_representation = 0;
196 $(
197 data |= (
198 (
199 ::macro_bits::write_field!(
200 $field_type,
201 $struct_representation,
202 self.$field_name
203 )
204 ) << ($field_mask as usize).trailing_zeros()
205 ) & $field_mask;
206 )*
207 data
208 }
209 }
210 ::macro_bits::generate_conversions!($struct_representation, $struct_representation, $struct_name);
211 }
212 };
213}