kernel/bits.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Bit manipulation macros.
4//!
5//! C header: [`include/linux/bits.h`](srctree/include/linux/bits.h)
6
7use crate::prelude::*;
8use core::ops::RangeInclusive;
9use macros::paste;
10
11macro_rules! impl_bit_fn {
12 (
13 $ty:ty
14 ) => {
15 paste! {
16 /// Computes `1 << n` if `n` is in bounds, i.e.: if `n` is smaller than
17 /// the maximum number of bits supported by the type.
18 ///
19 /// Returns [`None`] otherwise.
20 #[inline]
21 pub fn [<checked_bit_ $ty>](n: u32) -> Option<$ty> {
22 (1 as $ty).checked_shl(n)
23 }
24
25 /// Computes `1 << n` by performing a compile-time assertion that `n` is
26 /// in bounds.
27 ///
28 /// This version is the default and should be used if `n` is known at
29 /// compile time.
30 #[inline]
31 pub const fn [<bit_ $ty>](n: u32) -> $ty {
32 build_assert!(n < <$ty>::BITS);
33 (1 as $ty) << n
34 }
35 }
36 };
37}
38
39impl_bit_fn!(u64);
40impl_bit_fn!(u32);
41impl_bit_fn!(u16);
42impl_bit_fn!(u8);
43
44macro_rules! impl_genmask_fn {
45 (
46 $ty:ty,
47 $(#[$genmask_checked_ex:meta])*,
48 $(#[$genmask_ex:meta])*
49 ) => {
50 paste! {
51 /// Creates a contiguous bitmask for the given range by validating
52 /// the range at runtime.
53 ///
54 /// Returns [`None`] if the range is invalid, i.e.: if the start is
55 /// greater than the end or if the range is outside of the
56 /// representable range for the type.
57 $(#[$genmask_checked_ex])*
58 #[inline]
59 pub fn [<genmask_checked_ $ty>](range: RangeInclusive<u32>) -> Option<$ty> {
60 let start = *range.start();
61 let end = *range.end();
62
63 if start > end {
64 return None;
65 }
66
67 let high = [<checked_bit_ $ty>](end)?;
68 let low = [<checked_bit_ $ty>](start)?;
69 Some((high | (high - 1)) & !(low - 1))
70 }
71
72 /// Creates a compile-time contiguous bitmask for the given range by
73 /// performing a compile-time assertion that the range is valid.
74 ///
75 /// This version is the default and should be used if the range is known
76 /// at compile time.
77 $(#[$genmask_ex])*
78 #[inline]
79 pub const fn [<genmask_ $ty>](range: RangeInclusive<u32>) -> $ty {
80 let start = *range.start();
81 let end = *range.end();
82
83 build_assert!(start <= end);
84
85 let high = [<bit_ $ty>](end);
86 let low = [<bit_ $ty>](start);
87 (high | (high - 1)) & !(low - 1)
88 }
89 }
90 };
91}
92
93impl_genmask_fn!(
94 u64,
95 /// # Examples
96 ///
97 /// ```
98 /// # #![expect(clippy::reversed_empty_ranges)]
99 /// # use kernel::bits::genmask_checked_u64;
100 /// assert_eq!(genmask_checked_u64(0..=0), Some(0b1));
101 /// assert_eq!(genmask_checked_u64(0..=63), Some(u64::MAX));
102 /// assert_eq!(genmask_checked_u64(21..=39), Some(0x0000_00ff_ffe0_0000));
103 ///
104 /// // `80` is out of the supported bit range.
105 /// assert_eq!(genmask_checked_u64(21..=80), None);
106 ///
107 /// // Invalid range where the start is bigger than the end.
108 /// assert_eq!(genmask_checked_u64(15..=8), None);
109 /// ```
110 ,
111 /// # Examples
112 ///
113 /// ```
114 /// # use kernel::bits::genmask_u64;
115 /// assert_eq!(genmask_u64(21..=39), 0x0000_00ff_ffe0_0000);
116 /// assert_eq!(genmask_u64(0..=0), 0b1);
117 /// assert_eq!(genmask_u64(0..=63), u64::MAX);
118 /// ```
119);
120
121impl_genmask_fn!(
122 u32,
123 /// # Examples
124 ///
125 /// ```
126 /// # #![expect(clippy::reversed_empty_ranges)]
127 /// # use kernel::bits::genmask_checked_u32;
128 /// assert_eq!(genmask_checked_u32(0..=0), Some(0b1));
129 /// assert_eq!(genmask_checked_u32(0..=31), Some(u32::MAX));
130 /// assert_eq!(genmask_checked_u32(21..=31), Some(0xffe0_0000));
131 ///
132 /// // `40` is out of the supported bit range.
133 /// assert_eq!(genmask_checked_u32(21..=40), None);
134 ///
135 /// // Invalid range where the start is bigger than the end.
136 /// assert_eq!(genmask_checked_u32(15..=8), None);
137 /// ```
138 ,
139 /// # Examples
140 ///
141 /// ```
142 /// # use kernel::bits::genmask_u32;
143 /// assert_eq!(genmask_u32(21..=31), 0xffe0_0000);
144 /// assert_eq!(genmask_u32(0..=0), 0b1);
145 /// assert_eq!(genmask_u32(0..=31), u32::MAX);
146 /// ```
147);
148
149impl_genmask_fn!(
150 u16,
151 /// # Examples
152 ///
153 /// ```
154 /// # #![expect(clippy::reversed_empty_ranges)]
155 /// # use kernel::bits::genmask_checked_u16;
156 /// assert_eq!(genmask_checked_u16(0..=0), Some(0b1));
157 /// assert_eq!(genmask_checked_u16(0..=15), Some(u16::MAX));
158 /// assert_eq!(genmask_checked_u16(6..=15), Some(0xffc0));
159 ///
160 /// // `20` is out of the supported bit range.
161 /// assert_eq!(genmask_checked_u16(6..=20), None);
162 ///
163 /// // Invalid range where the start is bigger than the end.
164 /// assert_eq!(genmask_checked_u16(10..=5), None);
165 /// ```
166 ,
167 /// # Examples
168 ///
169 /// ```
170 /// # use kernel::bits::genmask_u16;
171 /// assert_eq!(genmask_u16(6..=15), 0xffc0);
172 /// assert_eq!(genmask_u16(0..=0), 0b1);
173 /// assert_eq!(genmask_u16(0..=15), u16::MAX);
174 /// ```
175);
176
177impl_genmask_fn!(
178 u8,
179 /// # Examples
180 ///
181 /// ```
182 /// # #![expect(clippy::reversed_empty_ranges)]
183 /// # use kernel::bits::genmask_checked_u8;
184 /// assert_eq!(genmask_checked_u8(0..=0), Some(0b1));
185 /// assert_eq!(genmask_checked_u8(0..=7), Some(u8::MAX));
186 /// assert_eq!(genmask_checked_u8(6..=7), Some(0xc0));
187 ///
188 /// // `10` is out of the supported bit range.
189 /// assert_eq!(genmask_checked_u8(6..=10), None);
190 ///
191 /// // Invalid range where the start is bigger than the end.
192 /// assert_eq!(genmask_checked_u8(5..=2), None);
193 /// ```
194 ,
195 /// # Examples
196 ///
197 /// ```
198 /// # use kernel::bits::genmask_u8;
199 /// assert_eq!(genmask_u8(6..=7), 0xc0);
200 /// assert_eq!(genmask_u8(0..=0), 0b1);
201 /// assert_eq!(genmask_u8(0..=7), u8::MAX);
202 /// ```
203);