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);