master
rs 466 lines 13.8 KB
Raw
1 // SPDX-License-Identifier: MIT or Apache-2.0 or GPL-2.0-or-later
2
3 /// # Definition entry point
4 ///
5 /// Define a struct with a single field of type $type. Include public constants
6 /// for each element listed in braces.
7 ///
8 /// The unnamed element at the end, if present, can be used to enlarge the set
9 /// of valid bits. Bits that are valid but not listed are treated normally for
10 /// the purpose of arithmetic operations, and are printed with their hexadecimal
11 /// value.
12 ///
13 /// The struct implements the following traits: [`BitAnd`](std::ops::BitAnd),
14 /// [`BitOr`](std::ops::BitOr), [`BitXor`](std::ops::BitXor),
15 /// [`Not`](std::ops::Not), [`Sub`](std::ops::Sub); [`Debug`](std::fmt::Debug),
16 /// [`Display`](std::fmt::Display), [`Binary`](std::fmt::Binary),
17 /// [`Octal`](std::fmt::Octal), [`LowerHex`](std::fmt::LowerHex),
18 /// [`UpperHex`](std::fmt::UpperHex); [`From`]`<type>`/[`Into`]`<type>` where
19 /// type is the type specified in the definition.
20 ///
21 /// ## Example
22 ///
23 /// ```
24 /// # use bits::bits;
25 /// bits! {
26 /// pub struct Colors(u8) {
27 /// BLACK = 0,
28 /// RED = 1,
29 /// GREEN = 1 << 1,
30 /// BLUE = 1 << 2,
31 /// WHITE = (1 << 0) | (1 << 1) | (1 << 2),
32 /// }
33 /// }
34 /// ```
35 ///
36 /// ```
37 /// # use bits::bits;
38 /// # bits! { pub struct Colors(u8) { BLACK = 0, RED = 1, GREEN = 1 << 1, BLUE = 1 << 2, } }
39 ///
40 /// bits! {
41 /// pub struct Colors8(u8) {
42 /// BLACK = 0,
43 /// RED = 1,
44 /// GREEN = 1 << 1,
45 /// BLUE = 1 << 2,
46 /// WHITE = (1 << 0) | (1 << 1) | (1 << 2),
47 ///
48 /// _ = 255,
49 /// }
50 /// }
51 ///
52 /// // The previously defined struct ignores bits not explicitly defined.
53 /// assert_eq!(
54 /// Colors::from(255).into_bits(),
55 /// (Colors::RED | Colors::GREEN | Colors::BLUE).into_bits()
56 /// );
57 ///
58 /// // Adding "_ = 255" makes it retain other bits as well.
59 /// assert_eq!(Colors8::from(255).into_bits(), 255);
60 ///
61 /// // all() does not include the additional bits, valid_bits() does
62 /// assert_eq!(Colors8::all().into_bits(), Colors::all().into_bits());
63 /// assert_eq!(Colors8::valid_bits().into_bits(), 255);
64 /// ```
65 ///
66 /// # Evaluation entry point
67 ///
68 /// Return a constant corresponding to the boolean expression `$expr`.
69 /// Identifiers in the expression correspond to values defined for the
70 /// type `$type`. Supported operators are `!` (unary), `-`, `&`, `^`, `|`.
71 ///
72 /// ## Examples
73 ///
74 /// ```
75 /// # use bits::bits;
76 /// bits! {
77 /// pub struct Colors(u8) {
78 /// BLACK = 0,
79 /// RED = 1,
80 /// GREEN = 1 << 1,
81 /// BLUE = 1 << 2,
82 /// // same as "WHITE = 7",
83 /// WHITE = bits!(Self as u8: RED | GREEN | BLUE),
84 /// }
85 /// }
86 ///
87 /// let rgb = bits! { Colors: RED | GREEN | BLUE };
88 /// assert_eq!(rgb, Colors::WHITE);
89 /// ```
90 #[macro_export]
91 macro_rules! bits {
92 {
93 $(#[$struct_meta:meta])*
94 $struct_vis:vis struct $struct_name:ident($field_vis:vis $type:ty) {
95 $($(#[$const_meta:meta])* $const:ident = $val:expr),+
96 $(,_ = $mask:expr)?
97 $(,)?
98 }
99 } => {
100 $(#[$struct_meta])*
101 #[derive(Clone, Copy, PartialEq, Eq)]
102 #[repr(transparent)]
103 $struct_vis struct $struct_name($field_vis $type);
104
105 impl $struct_name {
106 $( #[allow(dead_code)] $(#[$const_meta])*
107 pub const $const: $struct_name = $struct_name($val); )+
108
109 #[doc(hidden)]
110 const VALID__: $type = $( Self::$const.0 )|+ $(|$mask)?;
111
112 #[allow(dead_code)]
113 #[inline(always)]
114 pub const fn empty() -> Self {
115 Self(0)
116 }
117
118 #[allow(dead_code)]
119 #[inline(always)]
120 pub const fn all() -> Self {
121 Self($( Self::$const.0 )|+)
122 }
123
124 #[allow(dead_code)]
125 #[inline(always)]
126 pub const fn valid_bits() -> Self {
127 Self(Self::VALID__)
128 }
129
130 #[allow(dead_code)]
131 #[inline(always)]
132 pub const fn valid(val: $type) -> bool {
133 (val & !Self::VALID__) == 0
134 }
135
136 #[allow(dead_code)]
137 #[inline(always)]
138 pub const fn any_set(self, mask: Self) -> bool {
139 (self.0 & mask.0) != 0
140 }
141
142 #[allow(dead_code)]
143 #[inline(always)]
144 pub const fn all_set(self, mask: Self) -> bool {
145 (self.0 & mask.0) == mask.0
146 }
147
148 #[allow(dead_code)]
149 #[inline(always)]
150 pub const fn none_set(self, mask: Self) -> bool {
151 (self.0 & mask.0) == 0
152 }
153
154 #[allow(dead_code)]
155 #[inline(always)]
156 pub const fn from_bits(value: $type) -> Self {
157 $struct_name(value)
158 }
159
160 #[allow(dead_code)]
161 #[inline(always)]
162 pub const fn into_bits(self) -> $type {
163 self.0
164 }
165
166 #[allow(dead_code)]
167 #[inline(always)]
168 pub const fn set(&mut self, rhs: Self) {
169 self.0 |= rhs.0;
170 }
171
172 #[allow(dead_code)]
173 #[inline(always)]
174 pub const fn clear(&mut self, rhs: Self) {
175 self.0 &= !rhs.0;
176 }
177
178 #[allow(dead_code)]
179 #[inline(always)]
180 pub const fn toggle(&mut self, rhs: Self) {
181 self.0 ^= rhs.0;
182 }
183
184 #[allow(dead_code)]
185 #[inline(always)]
186 pub const fn intersection(self, rhs: Self) -> Self {
187 $struct_name(self.0 & rhs.0)
188 }
189
190 #[allow(dead_code)]
191 #[inline(always)]
192 pub const fn difference(self, rhs: Self) -> Self {
193 $struct_name(self.0 & !rhs.0)
194 }
195
196 #[allow(dead_code)]
197 #[inline(always)]
198 pub const fn symmetric_difference(self, rhs: Self) -> Self {
199 $struct_name(self.0 ^ rhs.0)
200 }
201
202 #[allow(dead_code)]
203 #[inline(always)]
204 pub const fn union(self, rhs: Self) -> Self {
205 $struct_name(self.0 | rhs.0)
206 }
207
208 #[allow(dead_code)]
209 #[inline(always)]
210 pub const fn invert(self) -> Self {
211 $struct_name(self.0 ^ Self::VALID__)
212 }
213 }
214
215 impl ::std::fmt::Binary for $struct_name {
216 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
217 // If no width, use the highest valid bit
218 let width = f
219 .width()
220 .unwrap_or(Self::VALID__.checked_ilog2().map_or(1, |bit| (bit + 1) as usize));
221 write!(f, "{:0>width$.precision$b}", self.0,
222 width = width,
223 precision = f.precision().unwrap_or(width))
224 }
225 }
226
227 impl ::std::fmt::LowerHex for $struct_name {
228 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
229 <$type as ::std::fmt::LowerHex>::fmt(&self.0, f)
230 }
231 }
232
233 impl ::std::fmt::Octal for $struct_name {
234 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
235 <$type as ::std::fmt::Octal>::fmt(&self.0, f)
236 }
237 }
238
239 impl ::std::fmt::UpperHex for $struct_name {
240 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
241 <$type as ::std::fmt::UpperHex>::fmt(&self.0, f)
242 }
243 }
244
245 impl ::std::fmt::Debug for $struct_name {
246 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
247 write!(f, "{}({})", stringify!($struct_name), self)
248 }
249 }
250
251 impl ::std::fmt::Display for $struct_name {
252 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
253 use ::std::fmt::Display;
254 let mut first = true;
255 let mut left = self.0;
256 $(if Self::$const.0.is_power_of_two() && (self & Self::$const).0 != 0 {
257 if first { first = false } else { Display::fmt(&'|', f)?; }
258 Display::fmt(stringify!($const), f)?;
259 left -= Self::$const.0;
260 })+
261 if first {
262 Display::fmt(&'0', f)
263 } else if left != 0 {
264 write!(f, "|{left:#x}")
265 } else {
266 Ok(())
267 }
268 }
269 }
270
271 impl ::std::cmp::PartialEq<$type> for $struct_name {
272 fn eq(&self, rhs: &$type) -> bool {
273 self.0 == *rhs
274 }
275 }
276
277 impl ::std::ops::BitAnd<$struct_name> for &$struct_name {
278 type Output = $struct_name;
279 fn bitand(self, rhs: $struct_name) -> Self::Output {
280 $struct_name(self.0 & rhs.0)
281 }
282 }
283
284 impl ::std::ops::BitAndAssign<$struct_name> for $struct_name {
285 fn bitand_assign(&mut self, rhs: $struct_name) {
286 self.0 = self.0 & rhs.0
287 }
288 }
289
290 impl ::std::ops::BitXor<$struct_name> for &$struct_name {
291 type Output = $struct_name;
292 fn bitxor(self, rhs: $struct_name) -> Self::Output {
293 $struct_name(self.0 ^ rhs.0)
294 }
295 }
296
297 impl ::std::ops::BitXorAssign<$struct_name> for $struct_name {
298 fn bitxor_assign(&mut self, rhs: $struct_name) {
299 self.0 = self.0 ^ rhs.0
300 }
301 }
302
303 impl ::std::ops::BitOr<$struct_name> for &$struct_name {
304 type Output = $struct_name;
305 fn bitor(self, rhs: $struct_name) -> Self::Output {
306 $struct_name(self.0 | rhs.0)
307 }
308 }
309
310 impl ::std::ops::BitOrAssign<$struct_name> for $struct_name {
311 fn bitor_assign(&mut self, rhs: $struct_name) {
312 self.0 = self.0 | rhs.0
313 }
314 }
315
316 impl ::std::ops::Sub<$struct_name> for &$struct_name {
317 type Output = $struct_name;
318 fn sub(self, rhs: $struct_name) -> Self::Output {
319 $struct_name(self.0 & !rhs.0)
320 }
321 }
322
323 impl ::std::ops::SubAssign<$struct_name> for $struct_name {
324 fn sub_assign(&mut self, rhs: $struct_name) {
325 self.0 &= !rhs.0
326 }
327 }
328
329 impl ::std::ops::Not for &$struct_name {
330 type Output = $struct_name;
331 fn not(self) -> Self::Output {
332 $struct_name(self.0 ^ $struct_name::VALID__)
333 }
334 }
335
336 impl ::std::ops::BitAnd<$struct_name> for $struct_name {
337 type Output = Self;
338 fn bitand(self, rhs: Self) -> Self::Output {
339 $struct_name(self.0 & rhs.0)
340 }
341 }
342
343 impl ::std::ops::BitXor<$struct_name> for $struct_name {
344 type Output = Self;
345 fn bitxor(self, rhs: Self) -> Self::Output {
346 $struct_name(self.0 ^ rhs.0)
347 }
348 }
349
350 impl ::std::ops::BitOr<$struct_name> for $struct_name {
351 type Output = Self;
352 fn bitor(self, rhs: Self) -> Self::Output {
353 $struct_name(self.0 | rhs.0)
354 }
355 }
356
357 impl ::std::ops::Sub<$struct_name> for $struct_name {
358 type Output = Self;
359 fn sub(self, rhs: Self) -> Self::Output {
360 $struct_name(self.0 & !rhs.0)
361 }
362 }
363
364 impl ::std::ops::Not for $struct_name {
365 type Output = Self;
366 fn not(self) -> Self::Output {
367 $struct_name(self.0 ^ Self::VALID__)
368 }
369 }
370
371 impl From<$struct_name> for $type {
372 fn from(x: $struct_name) -> $type {
373 x.0
374 }
375 }
376
377 impl From<$type> for $struct_name {
378 fn from(x: $type) -> Self {
379 $struct_name(x & Self::VALID__)
380 }
381 }
382 };
383
384 { $type:ty: $expr:expr } => {
385 $crate::bits_const_internal! { $type @ ($expr) }
386 };
387
388 { $type:ty as $int_type:ty: $expr:expr } => {
389 ($crate::bits_const_internal! { $type @ ($expr) }.into_bits()) as $int_type
390 };
391 }
392
393 #[doc(hidden)]
394 pub use qemu_macros::bits_const_internal;
395
396 #[cfg(test)]
397 mod test {
398 bits! {
399 pub struct InterruptMask(u32) {
400 OE = 1 << 10,
401 BE = 1 << 9,
402 PE = 1 << 8,
403 FE = 1 << 7,
404 RT = 1 << 6,
405 TX = 1 << 5,
406 RX = 1 << 4,
407 DSR = 1 << 3,
408 DCD = 1 << 2,
409 CTS = 1 << 1,
410 RI = 1 << 0,
411
412 E = bits!(Self as u32: OE | BE | PE | FE),
413 MS = bits!(Self as u32: RI | DSR | DCD | CTS),
414 }
415 }
416
417 bits! {
418 pub struct EmptyMask(u32) {
419 NONE = 0,
420 }
421 }
422
423 #[test]
424 pub fn test_not() {
425 assert_eq!(
426 !InterruptMask::from(InterruptMask::RT.0),
427 InterruptMask::E | InterruptMask::MS | InterruptMask::TX | InterruptMask::RX
428 );
429 }
430
431 #[test]
432 pub fn test_and() {
433 assert_eq!(
434 InterruptMask::from(0),
435 InterruptMask::MS & InterruptMask::OE
436 )
437 }
438
439 #[test]
440 pub fn test_or() {
441 assert_eq!(
442 InterruptMask::E,
443 InterruptMask::OE | InterruptMask::BE | InterruptMask::PE | InterruptMask::FE
444 );
445 }
446
447 #[test]
448 pub fn test_xor() {
449 assert_eq!(
450 InterruptMask::E ^ InterruptMask::BE,
451 InterruptMask::OE | InterruptMask::PE | InterruptMask::FE
452 );
453 }
454
455 #[test]
456 pub fn test_sub_assign() {
457 let mut op1 = InterruptMask::E;
458 op1 -= InterruptMask::RI;
459 assert_eq!(op1, InterruptMask::E - InterruptMask::RI);
460 }
461
462 #[test]
463 pub fn test_bit_display_empty() {
464 assert_eq!(format!("{:b}", EmptyMask::NONE), "0");
465 }
466 }