Skip to main content

kernel/num/
bounded.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Implementation of [`Bounded`], a wrapper around integer types limiting the number of bits
4//! usable for value representation.
5
6use core::{
7    cmp,
8    fmt,
9    ops::{
10        self,
11        Deref, //
12    }, //,
13};
14
15use kernel::{
16    num::{
17        FromConst,
18        Integer,
19        Unsigned, //
20    },
21    prelude::*, //
22};
23
24/// Evaluates to `true` if `$value` can be represented using at most `$n` bits in a `$type`.
25///
26/// `expr` must be of type `type`, or the result will be incorrect.
27///
28/// Can be used in const context.
29macro_rules! fits_within {
30    ($value:expr, $type:ty, $n:expr) => {{
31        let shift: u32 = <$type>::BITS - $n;
32
33        // `value` fits within `$n` bits if shifting it left by the number of unused bits, then
34        // right by the same number, doesn't change it.
35        //
36        // This method has the benefit of working for both unsigned and signed values.
37        ($value << shift) >> shift == $value
38    }};
39}
40
41/// Returns `true` if `value` can be represented with at most `N` bits in a `T`.
42#[inline(always)]
43fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool {
44    fits_within!(value, T, num_bits)
45}
46
47/// An integer value that requires only the `N` least significant bits of the wrapped type to be
48/// encoded.
49///
50/// This limits the number of usable bits in the wrapped integer type, and thus the stored value to
51/// a narrower range, which provides guarantees that can be useful when working within e.g.
52/// bitfields.
53///
54/// # Invariants
55///
56/// - `N` is greater than `0`.
57/// - `N` is less than or equal to `T::BITS`.
58/// - Stored values can be represented with at most `N` bits.
59///
60/// # Examples
61///
62/// The preferred way to create values is through constants and the [`Bounded::new`] family of
63/// constructors, as they trigger a build error if the type invariants cannot be upheld.
64///
65/// ```
66/// use kernel::num::Bounded;
67///
68/// // An unsigned 8-bit integer, of which only the 4 LSBs are used.
69/// // The value `15` is statically validated to fit that constraint at build time.
70/// let v = Bounded::<u8, 4>::new::<15>();
71/// assert_eq!(v.get(), 15);
72///
73/// // Same using signed values.
74/// let v = Bounded::<i8, 4>::new::<-8>();
75/// assert_eq!(v.get(), -8);
76///
77/// // This doesn't build: a `u8` is smaller than the requested 9 bits.
78/// // let _ = Bounded::<u8, 9>::new::<10>();
79///
80/// // This also doesn't build: the requested value doesn't fit within 4 signed bits.
81/// // let _ = Bounded::<i8, 4>::new::<8>();
82/// ```
83///
84/// Values can also be validated at runtime with [`Bounded::try_new`].
85///
86/// ```
87/// use kernel::num::Bounded;
88///
89/// // This succeeds because `15` can be represented with 4 unsigned bits.
90/// assert!(Bounded::<u8, 4>::try_new(15).is_some());
91///
92/// // This fails because `16` cannot be represented with 4 unsigned bits.
93/// assert!(Bounded::<u8, 4>::try_new(16).is_none());
94/// ```
95///
96/// Non-constant expressions can be validated at build-time thanks to compiler optimizations. This
97/// should be used with caution, on simple expressions only.
98///
99/// ```
100/// use kernel::num::Bounded;
101/// # fn some_number() -> u32 { 0xffffffff }
102///
103/// // Here the compiler can infer from the mask that the type invariants are not violated, even
104/// // though the value returned by `some_number` is not statically known.
105/// let v = Bounded::<u32, 4>::from_expr(some_number() & 0xf);
106/// ```
107///
108/// Comparison and arithmetic operations are supported on [`Bounded`]s with a compatible backing
109/// type, regardless of their number of valid bits.
110///
111/// ```
112/// use kernel::num::Bounded;
113///
114/// let v1 = Bounded::<u32, 8>::new::<4>();
115/// let v2 = Bounded::<u32, 4>::new::<15>();
116///
117/// assert!(v1 != v2);
118/// assert!(v1 < v2);
119/// assert_eq!(v1 + v2, 19);
120/// assert_eq!(v2 % v1, 3);
121/// ```
122///
123/// These operations are also supported between a [`Bounded`] and its backing type.
124///
125/// ```
126/// use kernel::num::Bounded;
127///
128/// let v = Bounded::<u8, 4>::new::<15>();
129///
130/// assert!(v == 15);
131/// assert!(v > 12);
132/// assert_eq!(v + 5, 20);
133/// assert_eq!(v / 3, 5);
134/// ```
135///
136/// A change of backing types is possible using [`Bounded::cast`], and the number of valid bits can
137/// be extended or reduced with [`Bounded::extend`] and [`Bounded::try_shrink`].
138///
139/// ```
140/// use kernel::num::Bounded;
141///
142/// let v = Bounded::<u32, 12>::new::<127>();
143///
144/// // Changes backing type from `u32` to `u16`.
145/// let _: Bounded<u16, 12> = v.cast();
146///
147/// // This does not build, as `u8` is smaller than 12 bits.
148/// // let _: Bounded<u8, 12> = v.cast();
149///
150/// // We can safely extend the number of bits...
151/// let _ = v.extend::<15>();
152///
153/// // ... to the limits of the backing type. This doesn't build as a `u32` cannot contain 33 bits.
154/// // let _ = v.extend::<33>();
155///
156/// // Reducing the number of bits is validated at runtime. This works because `127` can be
157/// // represented with 8 bits.
158/// assert!(v.try_shrink::<8>().is_some());
159///
160/// // ... but not with 6, so this fails.
161/// assert!(v.try_shrink::<6>().is_none());
162/// ```
163///
164/// Infallible conversions from a primitive integer to a large-enough [`Bounded`] are supported.
165///
166/// ```
167/// use kernel::num::Bounded;
168///
169/// // This unsigned `Bounded` has 8 bits, so it can represent any `u8`.
170/// let v = Bounded::<u32, 8>::from(128u8);
171/// assert_eq!(v.get(), 128);
172///
173/// // This signed `Bounded` has 8 bits, so it can represent any `i8`.
174/// let v = Bounded::<i32, 8>::from(-128i8);
175/// assert_eq!(v.get(), -128);
176///
177/// // This doesn't build, as this 6-bit `Bounded` does not have enough capacity to represent a
178/// // `u8` (regardless of the passed value).
179/// // let _ = Bounded::<u32, 6>::from(10u8);
180///
181/// // Booleans can be converted into unsigned `Bounded`s.
182///
183/// let v = Bounded::<u64, 1>::from(false);
184/// assert_eq!(v.get(), 0);
185///
186/// let v = Bounded::<u64, 1>::from(true);
187/// assert_eq!(v.get(), 1);
188///
189/// // This does not build because `i8` is signed.
190/// // let _ = Bounded::<i8, 2>::from(true);
191/// ```
192///
193/// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and
194/// dependent on the number of bits used for value representation, not on the backing type.
195///
196/// ```
197/// use kernel::num::Bounded;
198///
199/// // Even though its backing type is `u32`, this `Bounded` only uses 6 bits and thus can safely
200/// // be converted to a `u8`.
201/// let v = Bounded::<u32, 6>::new::<63>();
202/// assert_eq!(u8::from(v), 63);
203///
204/// // Same using signed values.
205/// let v = Bounded::<i32, 8>::new::<-128>();
206/// assert_eq!(i8::from(v), -128);
207///
208/// // This however does not build, as 10 bits won't fit into a `u8` (regardless of the actually
209/// // contained value).
210/// let _v = Bounded::<u32, 10>::new::<10>();
211/// // assert_eq!(u8::from(_v), 10);
212///
213/// // Unsigned single-bit `Bounded`s can be converted into a boolean.
214/// let v = Bounded::<u8, 1>::new::<1>();
215/// assert_eq!(bool::from(v), true);
216///
217/// let v = Bounded::<u8, 1>::new::<0>();
218/// assert_eq!(bool::from(v), false);
219///
220/// // This does not build because `i8` is signed.
221/// // let v = Bounded::<i8, 1>::new::<-1>();
222/// // let _ = bool::from(v);
223/// ```
224///
225/// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the
226/// [`TryIntoBounded`] trait.
227///
228/// ```
229/// use kernel::num::{Bounded, TryIntoBounded};
230///
231/// // Succeeds because `128` fits into 8 bits.
232/// let v: Option<Bounded<u16, 8>> = 128u32.try_into_bounded();
233/// assert_eq!(v.as_deref().copied(), Some(128));
234///
235/// // Fails because `128` doesn't fit into 6 bits.
236/// let v: Option<Bounded<u16, 6>> = 128u32.try_into_bounded();
237/// assert_eq!(v, None);
238/// ```
239#[repr(transparent)]
240#[derive(Clone, Copy, Debug, Default, Hash)]
241pub struct Bounded<T: Integer, const N: u32>(T);
242
243/// Validating the value as a const expression cannot be done as a regular method, as the
244/// arithmetic operations we rely on to check the bounds are not const. Thus, implement
245/// [`Bounded::new`] using a macro.
246macro_rules! impl_const_new {
247    ($($type:ty)*) => {
248        $(
249        impl<const N: u32> Bounded<$type, N> {
250            /// Creates a [`Bounded`] for the constant `VALUE`.
251            ///
252            /// Fails at build time if `VALUE` cannot be represented with `N` bits.
253            ///
254            /// This method should be preferred to [`Self::from_expr`] whenever possible.
255            ///
256            /// # Examples
257            ///
258            /// ```
259            /// use kernel::num::Bounded;
260            ///
261            #[doc = ::core::concat!(
262                "let v = Bounded::<",
263                ::core::stringify!($type),
264                ", 4>::new::<7>();")]
265            /// assert_eq!(v.get(), 7);
266            /// ```
267            pub const fn new<const VALUE: $type>() -> Self {
268                // Statically assert that `VALUE` fits within the set number of bits.
269                const_assert!(fits_within!(VALUE, $type, N));
270
271                // SAFETY: `fits_within` confirmed that `VALUE` can be represented within
272                // `N` bits.
273                unsafe { Self::__new(VALUE) }
274            }
275        }
276
277        impl<const N: u32, const V: i128> FromConst<V> for Bounded<$type, N> {
278            const VALUE: Self = {
279                let value = <$type as FromConst<V>>::VALUE;
280                // Statically assert that `value` fits within the set number of bits.
281                assert!(
282                    fits_within!(value, $type, N),
283                    "constant cannot be represented within the given number of bits"
284                );
285
286                // SAFETY: The assert above confirmed that `value` can be represented within `N`
287                // bits.
288                unsafe { Self::__new(value) }
289            };
290        }
291        )*
292    };
293}
294
295impl_const_new!(
296    u8 u16 u32 u64 usize
297    i8 i16 i32 i64 isize
298);
299
300impl<T, const N: u32> Bounded<T, N>
301where
302    T: Integer,
303{
304    /// Private constructor enforcing the type invariants.
305    ///
306    /// All instances of [`Bounded`] must be created through this method as it enforces most of the
307    /// type invariants.
308    ///
309    /// # Safety
310    ///
311    /// The caller must ensure that `value` can be represented within `N` bits.
312    const unsafe fn __new(value: T) -> Self {
313        // Enforce the type invariants.
314        // `N` cannot be zero.
315        const_assert!(N != 0);
316        // The backing type is at least as large as `N` bits.
317        const_assert!(N <= T::BITS);
318
319        // INVARIANT: The caller ensures `value` fits within `N` bits.
320        Self(value)
321    }
322
323    /// Attempts to turn `value` into a `Bounded` using `N` bits.
324    ///
325    /// Returns [`None`] if `value` doesn't fit within `N` bits.
326    ///
327    /// # Examples
328    ///
329    /// ```
330    /// use kernel::num::Bounded;
331    ///
332    /// let v = Bounded::<u8, 1>::try_new(1);
333    /// assert_eq!(v.as_deref().copied(), Some(1));
334    ///
335    /// let v = Bounded::<i8, 4>::try_new(-2);
336    /// assert_eq!(v.as_deref().copied(), Some(-2));
337    ///
338    /// // `0x1ff` doesn't fit into 8 unsigned bits.
339    /// let v = Bounded::<u32, 8>::try_new(0x1ff);
340    /// assert_eq!(v, None);
341    ///
342    /// // The range of values representable with 4 bits is `[-8..=7]`. The following tests these
343    /// // limits.
344    /// let v = Bounded::<i8, 4>::try_new(-8);
345    /// assert_eq!(v.map(Bounded::get), Some(-8));
346    /// let v = Bounded::<i8, 4>::try_new(-9);
347    /// assert_eq!(v, None);
348    /// let v = Bounded::<i8, 4>::try_new(7);
349    /// assert_eq!(v.map(Bounded::get), Some(7));
350    /// let v = Bounded::<i8, 4>::try_new(8);
351    /// assert_eq!(v, None);
352    /// ```
353    pub fn try_new(value: T) -> Option<Self> {
354        fits_within(value, N).then(|| {
355            // SAFETY: `fits_within` confirmed that `value` can be represented within `N` bits.
356            unsafe { Self::__new(value) }
357        })
358    }
359
360    /// Checks that `expr` is valid for this type at compile-time and build a new value.
361    ///
362    /// This relies on [`build_assert!`] and guaranteed optimization to perform validation at
363    /// compile-time. If `expr` cannot be proved to be within the requested bounds at compile-time,
364    /// use the fallible [`Self::try_new`] instead.
365    ///
366    /// Limit this to simple, easily provable expressions, and prefer one of the [`Self::new`]
367    /// constructors whenever possible as they statically validate the value instead of relying on
368    /// compiler optimizations.
369    ///
370    /// # Examples
371    ///
372    /// ```
373    /// use kernel::num::Bounded;
374    /// # fn some_number() -> u32 { 0xffffffff }
375    ///
376    /// // Some undefined number.
377    /// let v: u32 = some_number();
378    ///
379    /// // Triggers a build error as `v` cannot be asserted to fit within 4 bits...
380    /// // let _ = Bounded::<u32, 4>::from_expr(v);
381    ///
382    /// // ... but this works as the compiler can assert the range from the mask.
383    /// let _ = Bounded::<u32, 4>::from_expr(v & 0xf);
384    ///
385    /// // These expressions are simple enough to be proven correct, but since they are static the
386    /// // `new` constructor should be preferred.
387    /// assert_eq!(Bounded::<u8, 1>::from_expr(1).get(), 1);
388    /// assert_eq!(Bounded::<u16, 8>::from_expr(0xff).get(), 0xff);
389    /// ```
390    // Always inline to optimize out error path of `build_assert`.
391    #[inline(always)]
392    pub fn from_expr(expr: T) -> Self {
393        crate::build_assert::build_assert!(
394            fits_within(expr, N),
395            "Requested value larger than maximal representable value."
396        );
397
398        // SAFETY: `fits_within` confirmed that `expr` can be represented within `N` bits.
399        unsafe { Self::__new(expr) }
400    }
401
402    /// Returns the wrapped value as the backing type.
403    ///
404    /// This is similar to the [`Deref`] implementation, but doesn't enforce the size invariant of
405    /// the [`Bounded`], which might produce slightly less optimal code.
406    ///
407    /// # Examples
408    ///
409    /// ```
410    /// use kernel::num::Bounded;
411    ///
412    /// let v = Bounded::<u32, 4>::new::<7>();
413    /// assert_eq!(v.get(), 7u32);
414    /// ```
415    pub const fn get(self) -> T {
416        self.0
417    }
418
419    /// Increases the number of bits usable for `self`.
420    ///
421    /// This operation cannot fail.
422    ///
423    /// # Examples
424    ///
425    /// ```
426    /// use kernel::num::Bounded;
427    ///
428    /// let v = Bounded::<u32, 4>::new::<7>();
429    /// let larger_v = v.extend::<12>();
430    /// // The contained values are equal even though `larger_v` has a bigger capacity.
431    /// assert_eq!(larger_v, v);
432    /// ```
433    pub const fn extend<const M: u32>(self) -> Bounded<T, M> {
434        const_assert!(
435            M >= N,
436            "Requested number of bits is less than the current representation."
437        );
438
439        // SAFETY: The value did fit within `N` bits, so it will all the more fit within
440        // the larger `M` bits.
441        unsafe { Bounded::__new(self.0) }
442    }
443
444    /// Attempts to shrink the number of bits usable for `self`.
445    ///
446    /// Returns [`None`] if the value of `self` cannot be represented within `M` bits.
447    ///
448    /// # Examples
449    ///
450    /// ```
451    /// use kernel::num::Bounded;
452    ///
453    /// let v = Bounded::<u32, 12>::new::<7>();
454    ///
455    /// // `7` can be represented using 3 unsigned bits...
456    /// let smaller_v = v.try_shrink::<3>();
457    /// assert_eq!(smaller_v.as_deref().copied(), Some(7));
458    ///
459    /// // ... but doesn't fit within `2` bits.
460    /// assert_eq!(v.try_shrink::<2>(), None);
461    /// ```
462    pub fn try_shrink<const M: u32>(self) -> Option<Bounded<T, M>> {
463        Bounded::<T, M>::try_new(self.get())
464    }
465
466    /// Casts `self` into a [`Bounded`] backed by a different storage type, but using the same
467    /// number of valid bits.
468    ///
469    /// Both `T` and `U` must be of same signedness, and `U` must be at least as large as
470    /// `N` bits, or a build error will occur.
471    ///
472    /// # Examples
473    ///
474    /// ```
475    /// use kernel::num::Bounded;
476    ///
477    /// let v = Bounded::<u32, 12>::new::<127>();
478    ///
479    /// let u16_v: Bounded<u16, 12> = v.cast();
480    /// assert_eq!(u16_v.get(), 127);
481    ///
482    /// // This won't build: a `u8` is smaller than the required 12 bits.
483    /// // let _: Bounded<u8, 12> = v.cast();
484    /// ```
485    pub fn cast<U>(self) -> Bounded<U, N>
486    where
487        U: TryFrom<T> + Integer,
488        T: Integer,
489        U: Integer<Signedness = T::Signedness>,
490    {
491        // SAFETY: The converted value is represented using `N` bits, `U` can contain `N` bits, and
492        // `U` and `T` have the same sign, hence this conversion cannot fail.
493        let value = unsafe { U::try_from(self.get()).unwrap_unchecked() };
494
495        // SAFETY: Although the backing type has changed, the value is still represented within
496        // `N` bits, and with the same signedness.
497        unsafe { Bounded::__new(value) }
498    }
499
500    /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, RES>`, where `RES >=
501    /// N - SHIFT`.
502    ///
503    /// # Examples
504    ///
505    /// ```
506    /// use kernel::num::Bounded;
507    ///
508    /// let v = Bounded::<u32, 16>::new::<0xff00>();
509    /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>();
510    ///
511    /// assert_eq!(v_shifted.get(), 0xff);
512    /// ```
513    pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
514        const_assert!(SHIFT < T::BITS);
515        const_assert!(RES + SHIFT >= N);
516
517        // SAFETY: We shift the value right by `SHIFT`, reducing the number of bits needed to
518        // represent the shifted value by as much, and just asserted that `RES >= N - SHIFT`.
519        unsafe { Bounded::__new(self.0 >> SHIFT) }
520    }
521
522    /// Right-shifts `self` by `SHIFT` if that loses no set bits, and returns the result as a
523    /// `Bounded<_, RES>`, where `RES >= N - SHIFT`.
524    ///
525    /// Returns [`None`] if any of the `SHIFT` least significant bits of `self` is set.
526    ///
527    /// # Examples
528    ///
529    /// ```
530    /// use kernel::num::Bounded;
531    ///
532    /// let v = Bounded::<u32, 16>::new::<0xff00>();
533    /// let v_shifted: Option<Bounded<u32, 8>> = v.shr_exact::<8, _>();
534    ///
535    /// assert_eq!(v_shifted.map(|v| v.get()), Some(0xff));
536    ///
537    /// // A set bit would be shifted out.
538    /// let v = Bounded::<u32, 16>::new::<0xff01>();
539    /// let v_shifted: Option<Bounded<u32, 8>> = v.shr_exact::<8, _>();
540    ///
541    /// assert!(v_shifted.is_none());
542    /// ```
543    #[inline]
544    pub fn shr_exact<const SHIFT: u32, const RES: u32>(self) -> Option<Bounded<T, RES>> {
545        let shifted = self.shr::<SHIFT, RES>();
546        if shifted.get() << SHIFT == self.0 {
547            Some(shifted)
548        } else {
549            None
550        }
551    }
552
553    /// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, RES>`, where `RES >=
554    /// N + SHIFT`.
555    ///
556    /// # Examples
557    ///
558    /// ```
559    /// use kernel::num::Bounded;
560    ///
561    /// let v = Bounded::<u32, 8>::new::<0xff>();
562    /// let v_shifted: Bounded::<u32, 16> = v.shl::<8, _>();
563    ///
564    /// assert_eq!(v_shifted.get(), 0xff00);
565    /// ```
566    pub fn shl<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> {
567        const_assert!(RES >= N + SHIFT);
568
569        // SAFETY: We shift the value left by `SHIFT`, augmenting the number of bits needed to
570        // represent the shifted value by as much, and just asserted that `RES >= N + SHIFT`.
571        unsafe { Bounded::__new(self.0 << SHIFT) }
572    }
573}
574
575impl<T, const N: u32> Deref for Bounded<T, N>
576where
577    T: Integer,
578{
579    type Target = T;
580
581    fn deref(&self) -> &Self::Target {
582        // Enforce the invariant to inform the compiler of the bounds of the value.
583        if !fits_within(self.0, N) {
584            // SAFETY: Per the `Bounded` invariants, `fits_within` can never return `false` on the
585            // value of a valid instance.
586            unsafe { core::hint::unreachable_unchecked() }
587        }
588
589        &self.0
590    }
591}
592
593/// Trait similar to [`TryInto`] but for [`Bounded`], to avoid conflicting implementations.
594///
595/// # Examples
596///
597/// ```
598/// use kernel::num::{Bounded, TryIntoBounded};
599///
600/// // Succeeds because `128` fits into 8 bits.
601/// let v: Option<Bounded<u16, 8>> = 128u32.try_into_bounded();
602/// assert_eq!(v.as_deref().copied(), Some(128));
603///
604/// // Fails because `128` doesn't fit into 6 bits.
605/// let v: Option<Bounded<u16, 6>> = 128u32.try_into_bounded();
606/// assert_eq!(v, None);
607/// ```
608pub trait TryIntoBounded<T: Integer, const N: u32> {
609    /// Attempts to convert `self` into a [`Bounded`] using `N` bits.
610    ///
611    /// Returns [`None`] if `self` does not fit into the target type.
612    fn try_into_bounded(self) -> Option<Bounded<T, N>>;
613}
614
615/// Any integer value can be attempted to be converted into a [`Bounded`] of any size.
616impl<T, U, const N: u32> TryIntoBounded<T, N> for U
617where
618    T: Integer,
619    U: TryInto<T>,
620{
621    fn try_into_bounded(self) -> Option<Bounded<T, N>> {
622        self.try_into().ok().and_then(Bounded::try_new)
623    }
624}
625
626// Comparisons between `Bounded`s.
627
628impl<T, U, const N: u32, const M: u32> PartialEq<Bounded<U, M>> for Bounded<T, N>
629where
630    T: Integer,
631    U: Integer,
632    T: PartialEq<U>,
633{
634    fn eq(&self, other: &Bounded<U, M>) -> bool {
635        self.get() == other.get()
636    }
637}
638
639impl<T, const N: u32> Eq for Bounded<T, N> where T: Integer {}
640
641impl<T, U, const N: u32, const M: u32> PartialOrd<Bounded<U, M>> for Bounded<T, N>
642where
643    T: Integer,
644    U: Integer,
645    T: PartialOrd<U>,
646{
647    fn partial_cmp(&self, other: &Bounded<U, M>) -> Option<cmp::Ordering> {
648        self.get().partial_cmp(&other.get())
649    }
650}
651
652impl<T, const N: u32> Ord for Bounded<T, N>
653where
654    T: Integer,
655    T: Ord,
656{
657    fn cmp(&self, other: &Self) -> cmp::Ordering {
658        self.get().cmp(&other.get())
659    }
660}
661
662// Comparisons between a `Bounded` and its backing type.
663
664impl<T, const N: u32> PartialEq<T> for Bounded<T, N>
665where
666    T: Integer,
667    T: PartialEq,
668{
669    fn eq(&self, other: &T) -> bool {
670        self.get() == *other
671    }
672}
673
674impl<T, const N: u32> PartialOrd<T> for Bounded<T, N>
675where
676    T: Integer,
677    T: PartialOrd,
678{
679    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
680        self.get().partial_cmp(other)
681    }
682}
683
684// Implementations of `core::ops` for two `Bounded` with the same backing type.
685
686impl<T, const N: u32, const M: u32> ops::Add<Bounded<T, M>> for Bounded<T, N>
687where
688    T: Integer,
689    T: ops::Add<Output = T>,
690{
691    type Output = T;
692
693    fn add(self, rhs: Bounded<T, M>) -> Self::Output {
694        self.get() + rhs.get()
695    }
696}
697
698impl<T, const N: u32, const M: u32> ops::BitAnd<Bounded<T, M>> for Bounded<T, N>
699where
700    T: Integer,
701    T: ops::BitAnd<Output = T>,
702{
703    type Output = T;
704
705    fn bitand(self, rhs: Bounded<T, M>) -> Self::Output {
706        self.get() & rhs.get()
707    }
708}
709
710impl<T, const N: u32, const M: u32> ops::BitOr<Bounded<T, M>> for Bounded<T, N>
711where
712    T: Integer,
713    T: ops::BitOr<Output = T>,
714{
715    type Output = T;
716
717    fn bitor(self, rhs: Bounded<T, M>) -> Self::Output {
718        self.get() | rhs.get()
719    }
720}
721
722impl<T, const N: u32, const M: u32> ops::BitXor<Bounded<T, M>> for Bounded<T, N>
723where
724    T: Integer,
725    T: ops::BitXor<Output = T>,
726{
727    type Output = T;
728
729    fn bitxor(self, rhs: Bounded<T, M>) -> Self::Output {
730        self.get() ^ rhs.get()
731    }
732}
733
734impl<T, const N: u32, const M: u32> ops::Div<Bounded<T, M>> for Bounded<T, N>
735where
736    T: Integer,
737    T: ops::Div<Output = T>,
738{
739    type Output = T;
740
741    fn div(self, rhs: Bounded<T, M>) -> Self::Output {
742        self.get() / rhs.get()
743    }
744}
745
746impl<T, const N: u32, const M: u32> ops::Mul<Bounded<T, M>> for Bounded<T, N>
747where
748    T: Integer,
749    T: ops::Mul<Output = T>,
750{
751    type Output = T;
752
753    fn mul(self, rhs: Bounded<T, M>) -> Self::Output {
754        self.get() * rhs.get()
755    }
756}
757
758impl<T, const N: u32, const M: u32> ops::Rem<Bounded<T, M>> for Bounded<T, N>
759where
760    T: Integer,
761    T: ops::Rem<Output = T>,
762{
763    type Output = T;
764
765    fn rem(self, rhs: Bounded<T, M>) -> Self::Output {
766        self.get() % rhs.get()
767    }
768}
769
770impl<T, const N: u32, const M: u32> ops::Sub<Bounded<T, M>> for Bounded<T, N>
771where
772    T: Integer,
773    T: ops::Sub<Output = T>,
774{
775    type Output = T;
776
777    fn sub(self, rhs: Bounded<T, M>) -> Self::Output {
778        self.get() - rhs.get()
779    }
780}
781
782// Implementations of `core::ops` between a `Bounded` and its backing type.
783
784impl<T, const N: u32> ops::Add<T> for Bounded<T, N>
785where
786    T: Integer,
787    T: ops::Add<Output = T>,
788{
789    type Output = T;
790
791    fn add(self, rhs: T) -> Self::Output {
792        self.get() + rhs
793    }
794}
795
796impl<T, const N: u32> ops::BitAnd<T> for Bounded<T, N>
797where
798    T: Integer,
799    T: ops::BitAnd<Output = T>,
800{
801    type Output = T;
802
803    fn bitand(self, rhs: T) -> Self::Output {
804        self.get() & rhs
805    }
806}
807
808impl<T, const N: u32> ops::BitOr<T> for Bounded<T, N>
809where
810    T: Integer,
811    T: ops::BitOr<Output = T>,
812{
813    type Output = T;
814
815    fn bitor(self, rhs: T) -> Self::Output {
816        self.get() | rhs
817    }
818}
819
820impl<T, const N: u32> ops::BitXor<T> for Bounded<T, N>
821where
822    T: Integer,
823    T: ops::BitXor<Output = T>,
824{
825    type Output = T;
826
827    fn bitxor(self, rhs: T) -> Self::Output {
828        self.get() ^ rhs
829    }
830}
831
832impl<T, const N: u32> ops::Div<T> for Bounded<T, N>
833where
834    T: Integer,
835    T: ops::Div<Output = T>,
836{
837    type Output = T;
838
839    fn div(self, rhs: T) -> Self::Output {
840        self.get() / rhs
841    }
842}
843
844impl<T, const N: u32> ops::Mul<T> for Bounded<T, N>
845where
846    T: Integer,
847    T: ops::Mul<Output = T>,
848{
849    type Output = T;
850
851    fn mul(self, rhs: T) -> Self::Output {
852        self.get() * rhs
853    }
854}
855
856impl<T, const N: u32> ops::Neg for Bounded<T, N>
857where
858    T: Integer,
859    T: ops::Neg<Output = T>,
860{
861    type Output = T;
862
863    fn neg(self) -> Self::Output {
864        -self.get()
865    }
866}
867
868impl<T, const N: u32> ops::Not for Bounded<T, N>
869where
870    T: Integer,
871    T: ops::Not<Output = T>,
872{
873    type Output = T;
874
875    fn not(self) -> Self::Output {
876        !self.get()
877    }
878}
879
880impl<T, const N: u32> ops::Rem<T> for Bounded<T, N>
881where
882    T: Integer,
883    T: ops::Rem<Output = T>,
884{
885    type Output = T;
886
887    fn rem(self, rhs: T) -> Self::Output {
888        self.get() % rhs
889    }
890}
891
892impl<T, const N: u32> ops::Sub<T> for Bounded<T, N>
893where
894    T: Integer,
895    T: ops::Sub<Output = T>,
896{
897    type Output = T;
898
899    fn sub(self, rhs: T) -> Self::Output {
900        self.get() - rhs
901    }
902}
903
904// Proxy implementations of `core::fmt`.
905
906impl<T, const N: u32> fmt::Display for Bounded<T, N>
907where
908    T: Integer,
909    T: fmt::Display,
910{
911    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
912        self.get().fmt(f)
913    }
914}
915
916impl<T, const N: u32> fmt::Binary for Bounded<T, N>
917where
918    T: Integer,
919    T: fmt::Binary,
920{
921    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
922        self.get().fmt(f)
923    }
924}
925
926impl<T, const N: u32> fmt::LowerExp for Bounded<T, N>
927where
928    T: Integer,
929    T: fmt::LowerExp,
930{
931    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
932        self.get().fmt(f)
933    }
934}
935
936impl<T, const N: u32> fmt::LowerHex for Bounded<T, N>
937where
938    T: Integer,
939    T: fmt::LowerHex,
940{
941    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
942        self.get().fmt(f)
943    }
944}
945
946impl<T, const N: u32> fmt::Octal for Bounded<T, N>
947where
948    T: Integer,
949    T: fmt::Octal,
950{
951    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
952        self.get().fmt(f)
953    }
954}
955
956impl<T, const N: u32> fmt::UpperExp for Bounded<T, N>
957where
958    T: Integer,
959    T: fmt::UpperExp,
960{
961    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
962        self.get().fmt(f)
963    }
964}
965
966impl<T, const N: u32> fmt::UpperHex for Bounded<T, N>
967where
968    T: Integer,
969    T: fmt::UpperHex,
970{
971    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
972        self.get().fmt(f)
973    }
974}
975
976/// Implements `$trait` for all [`Bounded`] types represented using `$num_bits`.
977///
978/// This is used to declare size properties as traits that we can constrain against in impl blocks.
979macro_rules! impl_size_rule {
980    ($trait:ty, $($num_bits:literal)*) => {
981        $(
982        impl<T> $trait for Bounded<T, $num_bits> where T: Integer {}
983        )*
984    };
985}
986
987/// Local trait expressing the fact that a given [`Bounded`] has at least `N` bits used for value
988/// representation.
989trait AtLeastXBits<const N: usize> {}
990
991/// Implementations for infallibly converting a primitive type into a [`Bounded`] that can contain
992/// it.
993///
994/// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent
995/// module.
996mod atleast_impls {
997    use super::*;
998
999    // Number of bits at least as large as 64.
1000    impl_size_rule!(AtLeastXBits<64>, 64);
1001
1002    // Anything 64 bits or more is also larger than 32.
1003    impl<T> AtLeastXBits<32> for T where T: AtLeastXBits<64> {}
1004    // Other numbers of bits at least as large as 32.
1005    impl_size_rule!(AtLeastXBits<32>,
1006        32 33 34 35 36 37 38 39
1007        40 41 42 43 44 45 46 47
1008        48 49 50 51 52 53 54 55
1009        56 57 58 59 60 61 62 63
1010    );
1011
1012    // Anything 32 bits or more is also larger than 16.
1013    impl<T> AtLeastXBits<16> for T where T: AtLeastXBits<32> {}
1014    // Other numbers of bits at least as large as 16.
1015    impl_size_rule!(AtLeastXBits<16>,
1016        16 17 18 19 20 21 22 23
1017        24 25 26 27 28 29 30 31
1018    );
1019
1020    // Anything 16 bits or more is also larger than 8.
1021    impl<T> AtLeastXBits<8> for T where T: AtLeastXBits<16> {}
1022    // Other numbers of bits at least as large as 8.
1023    impl_size_rule!(AtLeastXBits<8>, 8 9 10 11 12 13 14 15);
1024}
1025
1026/// Generates `From` implementations from a primitive type into a [`Bounded`] with
1027/// enough bits to store any value of that type.
1028///
1029/// Note: The only reason for having this macro is that if we pass `$type` as a generic
1030/// parameter, we cannot use it in the const context of [`AtLeastXBits`]'s generic parameter. This
1031/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a
1032/// regular `impl` block.
1033macro_rules! impl_from_primitive {
1034    ($($type:ty)*) => {
1035        $(
1036        #[doc = ::core::concat!(
1037            "Conversion from a [`",
1038            ::core::stringify!($type),
1039            "`] into a [`Bounded`] of same signedness with enough bits to store it.")]
1040        impl<T, const N: u32> From<$type> for Bounded<T, N>
1041        where
1042            $type: Integer,
1043            T: Integer<Signedness = <$type as Integer>::Signedness> + From<$type>,
1044            Self: AtLeastXBits<{ <$type as Integer>::BITS as usize }>,
1045        {
1046            fn from(value: $type) -> Self {
1047                // SAFETY: The trait bound on `Self` guarantees that `N` bits is
1048                // enough to hold any value of the source type.
1049                unsafe { Self::__new(T::from(value)) }
1050            }
1051        }
1052        )*
1053    }
1054}
1055
1056impl_from_primitive!(
1057    u8 u16 u32 u64 usize
1058    i8 i16 i32 i64 isize
1059);
1060
1061/// Local trait expressing the fact that a given [`Bounded`] fits into a primitive type of `N` bits,
1062/// provided they have the same signedness.
1063trait FitsInXBits<const N: usize> {}
1064
1065/// Implementations for infallibly converting a [`Bounded`] into a primitive type that can contain
1066/// it.
1067///
1068/// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent
1069/// module.
1070mod fits_impls {
1071    use super::*;
1072
1073    // Number of bits that fit into a 8-bits primitive.
1074    impl_size_rule!(FitsInXBits<8>, 1 2 3 4 5 6 7 8);
1075
1076    // Anything that fits into 8 bits also fits into 16.
1077    impl<T> FitsInXBits<16> for T where T: FitsInXBits<8> {}
1078    // Other number of bits that fit into a 16-bits primitive.
1079    impl_size_rule!(FitsInXBits<16>, 9 10 11 12 13 14 15 16);
1080
1081    // Anything that fits into 16 bits also fits into 32.
1082    impl<T> FitsInXBits<32> for T where T: FitsInXBits<16> {}
1083    // Other number of bits that fit into a 32-bits primitive.
1084    impl_size_rule!(FitsInXBits<32>,
1085        17 18 19 20 21 22 23 24
1086        25 26 27 28 29 30 31 32
1087    );
1088
1089    // Anything that fits into 32 bits also fits into 64.
1090    impl<T> FitsInXBits<64> for T where T: FitsInXBits<32> {}
1091    // Other number of bits that fit into a 64-bits primitive.
1092    impl_size_rule!(FitsInXBits<64>,
1093        33 34 35 36 37 38 39 40
1094        41 42 43 44 45 46 47 48
1095        49 50 51 52 53 54 55 56
1096        57 58 59 60 61 62 63 64
1097    );
1098}
1099
1100/// Generates [`From`] implementations from a [`Bounded`] into a primitive type that is
1101/// guaranteed to contain it.
1102///
1103/// Note: The only reason for having this macro is that if we pass `$type` as a generic
1104/// parameter, we cannot use it in the const context of `AtLeastXBits`'s generic parameter. This
1105/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a
1106/// regular `impl` block.
1107macro_rules! impl_into_primitive {
1108    ($($type:ty)*) => {
1109        $(
1110        #[doc = ::core::concat!(
1111            "Conversion from a [`Bounded`] with no more bits than a [`",
1112            ::core::stringify!($type),
1113            "`] and of same signedness into [`",
1114            ::core::stringify!($type),
1115            "`]")]
1116        impl<T, const N: u32> From<Bounded<T, N>> for $type
1117        where
1118            $type: Integer + TryFrom<T>,
1119            T: Integer<Signedness = <$type as Integer>::Signedness>,
1120            Bounded<T, N>: FitsInXBits<{ <$type as Integer>::BITS as usize }>,
1121        {
1122            fn from(value: Bounded<T, N>) -> $type {
1123                // SAFETY: The trait bound on `Bounded` ensures that any value it holds (which
1124                // is constrained to `N` bits) can fit into the destination type, so this
1125                // conversion cannot fail.
1126                unsafe { <$type>::try_from(value.get()).unwrap_unchecked() }
1127            }
1128        }
1129        )*
1130    }
1131}
1132
1133impl_into_primitive!(
1134    u8 u16 u32 u64 usize
1135    i8 i16 i32 i64 isize
1136);
1137
1138// Unsigned single-bit `Bounded`s can be converted to a boolean.
1139
1140impl<T> From<Bounded<T, 1>> for bool
1141where
1142    T: Integer<Signedness = Unsigned> + Zeroable,
1143{
1144    fn from(value: Bounded<T, 1>) -> Self {
1145        value.get() != Zeroable::zeroed()
1146    }
1147}
1148
1149// Booleans can be converted to unsigned `Bounded`s.
1150
1151impl<T, const N: u32> From<bool> for Bounded<T, N>
1152where
1153    T: Integer<Signedness = Unsigned> + From<bool>,
1154{
1155    fn from(value: bool) -> Self {
1156        // SAFETY: A boolean is represented by `0` or `1`, so it fits within any valid unsigned
1157        // `Bounded` width.
1158        unsafe { Self::__new(T::from(value)) }
1159    }
1160}
1161
1162impl<T> Bounded<T, 1>
1163where
1164    T: Integer<Signedness = Unsigned> + Zeroable,
1165{
1166    /// Converts this [`Bounded`] into a [`bool`].
1167    ///
1168    /// This is a shorter way of writing `bool::from(self)`.
1169    ///
1170    /// # Examples
1171    ///
1172    /// ```
1173    /// use kernel::num::Bounded;
1174    ///
1175    /// assert_eq!(Bounded::<u8, 1>::new::<0>().into_bool(), false);
1176    /// assert_eq!(Bounded::<u8, 1>::new::<1>().into_bool(), true);
1177    /// ```
1178    pub fn into_bool(self) -> bool {
1179        self.into()
1180    }
1181}