xref: /linux/rust/kernel/bits.rs (revision 989fe6771266bdb82a815d78802c5aa7c918fdfd)
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             #[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 
39 impl_bit_fn!(u64);
40 impl_bit_fn!(u32);
41 impl_bit_fn!(u16);
42 impl_bit_fn!(u8);
43 
44 macro_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 
93 impl_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 
121 impl_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 
149 impl_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 
177 impl_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 );
204