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