bitpatterns/
macros.rs

1//! Macros for the BitPattern crate
2
3pub use bitpatterns_proc_macro::__bitpattern_inner;
4
5/// Create a `const` [`BitPattern`][crate::BitPattern] from a "literal" with wildcards.
6/// See the documentation for that type for more details.
7///
8/// Specify the pattern as a binary number inside of a string, with optional
9/// `0b` prefix and underscore separators. Dots (`.`) will be treated as ignored/
10/// wildcard bits which can take any value. Unspecified bits (those in places
11/// beyond those in the string pattern) are always ignored.
12///
13/// The pattern will be given the smallest unsigned integer type capable of
14/// storing it. To override this behavior, specify a type manually as a second
15/// parameter. Explicitly specifying a type which is too small will cause
16/// a compilation failure.
17///
18/// If not storing to a variable, prefer the [`is_bit_match!`] macro over
19/// `bitpattern!(...).is_match(...)`.
20///
21/// # Examples
22/// ```rust
23/// use bitpatterns::*;
24///
25/// // Use the macro to define a BitPattern clearly
26/// let pattern_1 = bitpattern!("10..01");
27/// // The pattern can be stored as a constant too
28/// // Note the supported 0b prefix and _ separator
29/// let PATTERN_2: BitPattern<u8> = bitpattern!("0b00_01..");
30/// // We can also store the pattern as another type with explicit specification
31/// // This will have type BitPattern<i32>
32/// let pattern_3 = bitpattern!("0b00_01..", i32);
33/// // But specifying a type that is too small will fail
34/// // let pattern_4 = bitpattern!("0b000010001000", u8); // Doesn't compile
35///
36/// // Now we can use the patterns to match numbers
37/// assert!(pattern_1.is_match(45)); // 45 == 0b101101
38/// assert!(!PATTERN_2.is_match(45));
39///
40/// assert!(!pattern_1.is_match(6)); // 6 = 0b000110
41/// assert!(PATTERN_2.is_match(6));
42/// ```
43#[macro_export]
44macro_rules! bitpattern {
45    // We need to use a proc_macro for parsing to get strings parsed at compile time
46    // But declarative macros are more expressive for handling these different cases,
47    // so we split the macro code between a proc_macro for parsing and declarative
48    // macros for plain syntax.
49    // We also pass $crate to the proc_macro as a hack because procedural macros can't
50    // construct this identifier themselves but can receive it from a declarative macro.
51    // This allows us to get the behavior of $crate from the procedural macro
52
53    ($pattern:literal $(, $type_name:ident)?) => {{
54        $crate::__bitpattern_inner!($crate $pattern $($type_name)?)
55    }};
56}
57
58/// Match a number against a pattern of bits.
59///
60/// Patterns are "literals" of bits with an optional `0b` prefix and underscore `_`
61/// separators. Dots `.` are used to denote ignored bits/wildcards. Bits more significant
62/// than those specified in the pattern are also ignored. The type of the `other` being
63/// compared will determine the type of the pattern that is created.
64///
65/// This uses a temporary [`BitPattern`][crate::BitPattern] to check a number against,
66/// see the documentation on that type for more details about it. This macro will handle
67/// type issues for you; the argument will be extended/shrunk to the minimal size
68/// needed for the pattern.
69///
70/// # Examples
71/// ```rust
72/// use bitpatterns::*;
73///
74/// // Patterns use . to denote ignored bits
75/// assert!(is_bit_match!("0b10..", 8));   // 8  == 0b1000
76/// assert!(is_bit_match!("0b10..", 11));  // 11 == 0b1011
77/// // The 0b prefix is optional, it will still be a binary pattern
78/// assert!(!is_bit_match!("10..", 7));  // 7  == 0b0111
79/// // Underscore separators can be used anywhere in the pattern
80/// assert!(!is_bit_match!("10_..", 16)); // 16 == 0b10000
81/// // Digits which are more significant than those in the pattern are always ignored
82/// assert!(is_bit_match!("0b1", 3));  // 3 == 0b11
83/// assert!(!is_bit_match!("0b1", 2)); // 2 == 0b10
84/// ```
85#[macro_export]
86macro_rules! is_bit_match {
87    ($pattern:literal, $other:expr) => {
88        bitpattern!($pattern).is_match(($other) as _)
89    };
90}