|
4 | 4 |
|
5 | 5 | /// Static assert (i.e. compile-time assert).
|
6 | 6 | ///
|
7 |
| -/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`]. |
| 7 | +/// There are several forms of this macro: |
| 8 | +/// |
| 9 | +/// - Boolean assertion: `expr`. |
| 10 | +/// - Set membership assertion: `(expr) is in {a0, ..., aN}`. |
| 11 | +/// - Interval membership assertion: `(expr) is in [min, max]`. |
| 12 | +/// - Fits-in-type assertion: `(expr) fits in type`. |
| 13 | +/// |
| 14 | +/// The expressions in all the forms are evaluated in [const context]. |
| 15 | +/// |
| 16 | +/// [const context]: https://doc.rust-lang.org/reference/const_eval.html |
8 | 17 | ///
|
| 18 | +/// # Boolean assertion: `expr` |
| 19 | +/// |
| 20 | +/// Statically asserts the given expression. |
| 21 | +/// |
| 22 | +/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`]. |
9 | 23 | /// The feature may be added to Rust in the future: see [RFC 2790].
|
10 | 24 | ///
|
11 | 25 | /// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
|
12 | 26 | /// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
|
13 | 27 | /// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
|
14 | 28 | ///
|
15 |
| -/// # Examples |
| 29 | +/// ## Examples |
16 | 30 | ///
|
17 | 31 | /// ```
|
| 32 | +/// // Trivial assert. |
18 | 33 | /// static_assert!(42 > 24);
|
| 34 | +/// |
| 35 | +/// // Assert on sizes, similar to C's `sizeof(T)`. |
19 | 36 | /// static_assert!(core::mem::size_of::<u8>() == 1);
|
20 | 37 | ///
|
| 38 | +/// // Assert on binary string. |
21 | 39 | /// const X: &[u8] = b"bar";
|
22 |
| -/// static_assert!(X[1] == 'a' as u8); |
| 40 | +/// static_assert!(X[1] == b'a'); |
| 41 | +/// |
| 42 | +/// // Check we uphold some constraint from the C side by testing the bindings. |
| 43 | +/// static_assert!(RUST_BUFFER_SIZE >= bindings::LOG_LINE_MAX); |
23 | 44 | ///
|
| 45 | +/// // Calling `const fn`s is possible. |
24 | 46 | /// const fn f(x: i32) -> i32 {
|
25 | 47 | /// x + 2
|
26 | 48 | /// }
|
27 | 49 | /// static_assert!(f(40) == 42);
|
28 | 50 | /// ```
|
| 51 | +/// |
| 52 | +/// # Set membership assertion: `(expr) is in {a0, ..., aN}` |
| 53 | +/// |
| 54 | +/// Statically asserts that the given expression (typically a `const` integer) is in a set. |
| 55 | +/// The negated form (`is not in`) is also available. |
| 56 | +/// |
| 57 | +/// ## Examples |
| 58 | +/// |
| 59 | +/// ``` |
| 60 | +/// // Trivial usage. |
| 61 | +/// static_assert!((-2) is not in {-1, 0, 2}); |
| 62 | +/// static_assert!((-1) is in {-1, 0, 2}); |
| 63 | +/// static_assert!(( 0) is in {-1, 0, 2}); |
| 64 | +/// static_assert!(( 1) is not in {-1, 0, 2}); |
| 65 | +/// static_assert!(( 2) is in {-1, 0, 2}); |
| 66 | +/// static_assert!(( 3) is not in {-1, 0, 2}); |
| 67 | +/// |
| 68 | +/// // Typical usage. |
| 69 | +/// static_assert!((SOME_CONSTANT_DEPENDING_ON_ARCH) is in {FOO, BAR, BAZ}); |
| 70 | +/// static_assert!((core::mem::size_of::<usize>()) is in {4, 8}); |
| 71 | +/// ``` |
| 72 | +/// |
| 73 | +/// # Interval membership assertion: `(expr) is in [min, max]` |
| 74 | +/// |
| 75 | +/// Statically asserts that the given expression (typically a `const` integer) is in a closed |
| 76 | +/// interval (i.e. inclusive range). The negated form (`is not in`) is also available. |
| 77 | +/// |
| 78 | +/// ## Examples |
| 79 | +/// |
| 80 | +/// ``` |
| 81 | +/// // Trivial usage. |
| 82 | +/// static_assert!((-2) is not in [-1, 2]); |
| 83 | +/// static_assert!((-1) is in [-1, 2]); |
| 84 | +/// static_assert!(( 0) is in [-1, 2]); |
| 85 | +/// static_assert!(( 1) is in [-1, 2]); |
| 86 | +/// static_assert!(( 2) is in [-1, 2]); |
| 87 | +/// static_assert!(( 3) is not in [-1, 2]); |
| 88 | +/// |
| 89 | +/// // Typical usage. |
| 90 | +/// static_assert!((FOO) is in [MIN_FOO, MAX_FOO]); |
| 91 | +/// ``` |
| 92 | +/// |
| 93 | +/// # Fits-in-type assertion: `(expr) fits in type` |
| 94 | +/// |
| 95 | +/// Statically asserts that the given expression (typically a `const` integer) fits in the given |
| 96 | +/// type (which must provide `T::MIN` and `T::MAX`). The negated form (`does not fit in`) is also |
| 97 | +/// available. |
| 98 | +/// |
| 99 | +/// Casting a "kernel integer" (i.e. up to [`i64`]/[`u64`]) to [`i128`] within the expression is |
| 100 | +/// allowed to easily manipulate integers: no 128-bit code will be generated since it will be |
| 101 | +/// evaluated in a const context. |
| 102 | +/// |
| 103 | +/// ## Examples |
| 104 | +/// |
| 105 | +/// ``` |
| 106 | +/// // Trivial usage. |
| 107 | +/// static_assert!(( -1) does not fit in u8); |
| 108 | +/// static_assert!(( 0) fits in u8); |
| 109 | +/// static_assert!((255) fits in u8); |
| 110 | +/// static_assert!((256) does not fit in u8); |
| 111 | +/// |
| 112 | +/// // Two's complement. |
| 113 | +/// static_assert!((-128) fits in i8); |
| 114 | +/// static_assert!(( 127) fits in i8); |
| 115 | +/// static_assert!(( 128) does not fit in i8); |
| 116 | +/// |
| 117 | +/// // Using `i128` for easy manipulation of integers. |
| 118 | +/// const MAX_ERRNO: u32 = 4095; |
| 119 | +/// static_assert!((-(MAX_ERRNO as i128)) fits in i16); |
| 120 | +/// ``` |
29 | 121 | #[macro_export]
|
30 | 122 | macro_rules! static_assert {
|
| 123 | + // Boolean assertion: `expr`. |
31 | 124 | ($condition:expr) => {
|
32 | 125 | // Based on the latest one in `rustc`'s one before it was [removed].
|
33 | 126 | //
|
34 | 127 | // [removed]: https://github.com/rust-lang/rust/commit/c2dad1c6b9f9636198d7c561b47a2974f5103f6d
|
35 | 128 | #[allow(dead_code)]
|
36 | 129 | const _: () = [()][!($condition) as usize];
|
37 | 130 | };
|
| 131 | + |
| 132 | + // Set membership assertion: `(expr) is in {a0, ..., aN}`. |
| 133 | + (($expression:expr) is in {$($a:expr),+}) => { |
| 134 | + static_assert!( $(($expression) == ($a))||* ); |
| 135 | + }; |
| 136 | + (($expression:expr) is not in {$($a:expr),+}) => { |
| 137 | + static_assert!(!($(($expression) == ($a))||*)); |
| 138 | + }; |
| 139 | + |
| 140 | + // Interval membership assertion: `(expr) is in [min, max]`. |
| 141 | + (($expression:expr) is in [$min:expr, $max:expr]) => { |
| 142 | + static_assert!( ($expression) >= ($min) && ($expression) <= ($max) ); |
| 143 | + }; |
| 144 | + (($expression:expr) is not in [$min:expr, $max:expr]) => { |
| 145 | + static_assert!(!(($expression) >= ($min) && ($expression) <= ($max))); |
| 146 | + }; |
| 147 | + |
| 148 | + // Fits-in-type assertion: `(expr) fits in type`. |
| 149 | + (($expression:expr) fits in $t:ty) => { |
| 150 | + static_assert!(($expression) is in [<$t>::MIN as i128, <$t>::MAX as i128]); |
| 151 | + }; |
| 152 | + (($expression:expr) does not fit in $t:ty) => { |
| 153 | + static_assert!(($expression) is not in [<$t>::MIN as i128, <$t>::MAX as i128]); |
| 154 | + }; |
| 155 | +} |
| 156 | + |
| 157 | +// Tests. |
| 158 | +// |
| 159 | +// These should later on go into a proper test. |
| 160 | + |
| 161 | +static_assert!(42 > 24); |
| 162 | +static_assert!(core::mem::size_of::<u8>() == 1); |
| 163 | + |
| 164 | +const X: &[u8] = b"bar"; |
| 165 | +static_assert!(X[1] == b'a'); |
| 166 | + |
| 167 | +const fn f(x: i32) -> i32 { |
| 168 | + x + 2 |
38 | 169 | }
|
| 170 | +static_assert!(f(40) == 42); |
| 171 | + |
| 172 | +static_assert!((-2) is not in {-1, 0, 2}); |
| 173 | +static_assert!((-1) is in {-1, 0, 2}); |
| 174 | +static_assert!(( 0) is in {-1, 0, 2}); |
| 175 | +static_assert!(( 1) is not in {-1, 0, 2}); |
| 176 | +static_assert!(( 2) is in {-1, 0, 2}); |
| 177 | +static_assert!(( 3) is not in {-1, 0, 2}); |
| 178 | + |
| 179 | +static_assert!((core::mem::size_of::<usize>()) is in {4, 8}); |
| 180 | + |
| 181 | +static_assert!((-2) is not in [-1, 2]); |
| 182 | +static_assert!((-1) is in [-1, 2]); |
| 183 | +static_assert!(( 0) is in [-1, 2]); |
| 184 | +static_assert!(( 1) is in [-1, 2]); |
| 185 | +static_assert!(( 2) is in [-1, 2]); |
| 186 | +static_assert!(( 3) is not in [-1, 2]); |
| 187 | + |
| 188 | +static_assert!((-129) does not fit in i8); |
| 189 | +static_assert!((-128) fits in i8); |
| 190 | +static_assert!(( 127) fits in i8); |
| 191 | +static_assert!(( 128) does not fit in i8); |
| 192 | + |
| 193 | +static_assert!(( -1) does not fit in u8); |
| 194 | +static_assert!(( 0) fits in u8); |
| 195 | +static_assert!((255) fits in u8); |
| 196 | +static_assert!((256) does not fit in u8); |
| 197 | + |
| 198 | +const MAX_ERRNO: u32 = 4095; |
| 199 | +static_assert!((-(MAX_ERRNO as i128)) fits in i16); |
| 200 | +static_assert!((-(MAX_ERRNO as i128)) does not fit in i8); |
| 201 | +static_assert!((-(MAX_ERRNO as i128)) does not fit in u16); |
0 commit comments