// SPDX-License-Identifier: GPL-2.0 //! Implementation of [`Bounded`], a wrapper around integer types limiting the number of bits//! usable for value representation. use core::{ cmp, fmt, ops::{ self, Deref, // }, //,}; use kernel::{ num::Integer, prelude::*, //}; /// Evaluates to `true` if `$value` can be represented using at most `$n` bits in a `$type`.////// `expr` must be of type `type`, or the result will be incorrect.////// Can be used in const context.macro_rules! fits_within { ($value:expr, $type:ty, $n:expr) => {{ let shift: u32 = <$type>::BITS - $n; // `value` fits within `$n` bits if shifting it left by the number of unused bits, then // right by the same number, doesn't change it. // // This method has the benefit of working for both unsigned and signed values. ($value << shift) >> shift == $value }};} /// Returns `true` if `value` can be represented with at most `N` bits in a `T`.#[inline(always)]fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool { fits_within!(value, T, num_bits)} /// An integer value that requires only the `N` least significant bits of the wrapped type to be/// encoded.////// This limits the number of usable bits in the wrapped integer type, and thus the stored value to/// a narrower range, which provides guarantees that can be useful when working within e.g./// bitfields.////// # Invariants////// - `N` is greater than `0`./// - `N` is less than or equal to `T::BITS`./// - Stored values can be represented with at most `N` bits.////// # Examples////// The preferred way to create values is through constants and the [`Bounded::new`] family of/// constructors, as they trigger a build error if the type invariants cannot be upheld.////// ```/// use kernel::num::Bounded;////// // An unsigned 8-bit integer, of which only the 4 LSBs are used./// // The value `15` is statically validated to fit that constraint at build time./// let v = Bounded::<u8, 4>::new::<15>();/// assert_eq!(v.get(), 15);////// // Same using signed values./// let v = Bounded::<i8, 4>::new::<-8>();/// assert_eq!(v.get(), -8);////// // This doesn't build: a `u8` is smaller than the requested 9 bits./// // let _ = Bounded::<u8, 9>::new::<10>();////// // This also doesn't build: the requested value doesn't fit within 4 signed bits./// // let _ = Bounded::<i8, 4>::new::<8>();/// ```////// Values can also be validated at runtime with [`Bounded::try_new`].////// ```/// use kernel::num::Bounded;////// // This succeeds because `15` can be represented with 4 unsigned bits./// assert!(Bounded::<u8, 4>::try_new(15).is_some());////// // This fails because `16` cannot be represented with 4 unsigned bits./// assert!(Bounded::<u8, 4>::try_new(16).is_none());/// ```////// Non-constant expressions can be validated at build-time thanks to compiler optimizations. This/// should be used with caution, on simple expressions only.////// ```/// use kernel::num::Bounded;/// # fn some_number() -> u32 { 0xffffffff }////// // Here the compiler can infer from the mask that the type invariants are not violated, even/// // though the value returned by `some_number` is not statically known./// let v = Bounded::<u32, 4>::from_expr(some_number() & 0xf);/// ```////// Comparison and arithmetic operations are supported on [`Bounded`]s with a compatible backing/// type, regardless of their number of valid bits.////// ```/// use kernel::num::Bounded;////// let v1 = Bounded::<u32, 8>::new::<4>();/// let v2 = Bounded::<u32, 4>::new::<15>();////// assert!(v1 != v2);/// assert!(v1 < v2);/// assert_eq!(v1 + v2, 19);/// assert_eq!(v2 % v1, 3);/// ```////// These operations are also supported between a [`Bounded`] and its backing type.////// ```/// use kernel::num::Bounded;////// let v = Bounded::<u8, 4>::new::<15>();////// assert!(v == 15);/// assert!(v > 12);/// assert_eq!(v + 5, 20);/// assert_eq!(v / 3, 5);/// ```////// A change of backing types is possible using [`Bounded::cast`], and the number of valid bits can/// be extended or reduced with [`Bounded::extend`] and [`Bounded::try_shrink`].////// ```/// use kernel::num::Bounded;////// let v = Bounded::<u32, 12>::new::<127>();////// // Changes backing type from `u32` to `u16`./// let _: Bounded<u16, 12> = v.cast();////// // This does not build, as `u8` is smaller than 12 bits./// // let _: Bounded<u8, 12> = v.cast();////// // We can safely extend the number of bits.../// let _ = v.extend::<15>();////// // ... to the limits of the backing type. This doesn't build as a `u32` cannot contain 33 bits./// // let _ = v.extend::<33>();////// // Reducing the number of bits is validated at runtime. This works because `127` can be/// // represented with 8 bits./// assert!(v.try_shrink::<8>().is_some());////// // ... but not with 6, so this fails./// assert!(v.try_shrink::<6>().is_none());/// ```////// Infallible conversions from a primitive integer to a large-enough [`Bounded`] are supported.////// ```/// use kernel::num::Bounded;////// // This unsigned `Bounded` has 8 bits, so it can represent any `u8`./// let v = Bounded::<u32, 8>::from(128u8);/// assert_eq!(v.get(), 128);////// // This signed `Bounded` has 8 bits, so it can represent any `i8`./// let v = Bounded::<i32, 8>::from(-128i8);/// assert_eq!(v.get(), -128);////// // This doesn't build, as this 6-bit `Bounded` does not have enough capacity to represent a/// // `u8` (regardless of the passed value)./// // let _ = Bounded::<u32, 6>::from(10u8);////// // Booleans can be converted into single-bit `Bounded`s.////// let v = Bounded::<u64, 1>::from(false);/// assert_eq!(v.get(), 0);////// let v = Bounded::<u64, 1>::from(true);/// assert_eq!(v.get(), 1);/// ```////// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and/// dependent on the number of bits used for value representation, not on the backing type.////// ```/// use kernel::num::Bounded;////// // Even though its backing type is `u32`, this `Bounded` only uses 6 bits and thus can safely/// // be converted to a `u8`./// let v = Bounded::<u32, 6>::new::<63>();/// assert_eq!(u8::from(v), 63);////// // Same using signed values./// let v = Bounded::<i32, 8>::new::<-128>();/// assert_eq!(i8::from(v), -128);////// // This however does not build, as 10 bits won't fit into a `u8` (regardless of the actually/// // contained value)./// let _v = Bounded::<u32, 10>::new::<10>();/// // assert_eq!(u8::from(_v), 10);////// // Single-bit `Bounded`s can be converted into a boolean./// let v = Bounded::<u8, 1>::new::<1>();/// assert_eq!(bool::from(v), true);////// let v = Bounded::<u8, 1>::new::<0>();/// assert_eq!(bool::from(v), false);/// ```////// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the/// [`TryIntoBounded`] trait.////// ```/// use kernel::num::{Bounded, TryIntoBounded};////// // Succeeds because `128` fits into 8 bits./// let v: Option<Bounded<u16, 8>> = 128u32.try_into_bounded();/// assert_eq!(v.as_deref().copied(), Some(128));////// // Fails because `128` doesn't fit into 6 bits./// let v: Option<Bounded<u16, 6>> = 128u32.try_into_bounded();/// assert_eq!(v, None);/// ```#[repr(transparent)]#[derive(Clone, Copy, Debug, Default, Hash)]pub struct Bounded<T: Integer, const N: u32>(T); /// Validating the value as a const expression cannot be done as a regular method, as the/// arithmetic operations we rely on to check the bounds are not const. Thus, implement/// [`Bounded::new`] using a macro.macro_rules! impl_const_new { ($($type:ty)*) => { $( impl<const N: u32> Bounded<$type, N> { /// Creates a [`Bounded`] for the constant `VALUE`. /// /// Fails at build time if `VALUE` cannot be represented with `N` bits. /// /// This method should be preferred to [`Self::from_expr`] whenever possible. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// #[doc = ::core::concat!( "let v = Bounded::<", ::core::stringify!($type), ", 4>::new::<7>();")] /// assert_eq!(v.get(), 7); /// ``` pub const fn new<const VALUE: $type>() -> Self { // Statically assert that `VALUE` fits within the set number of bits. const_assert!(fits_within!(VALUE, $type, N)); // SAFETY: `fits_within` confirmed that `VALUE` can be represented within // `N` bits. unsafe { Self::__new(VALUE) } } } )* };} impl_const_new!( u8 u16 u32 u64 usize i8 i16 i32 i64 isize); impl<T, const N: u32> Bounded<T, N>where T: Integer,{ /// Private constructor enforcing the type invariants. /// /// All instances of [`Bounded`] must be created through this method as it enforces most of the /// type invariants. /// /// # Safety /// /// The caller must ensure that `value` can be represented within `N` bits. const unsafe fn __new(value: T) -> Self { // Enforce the type invariants. // `N` cannot be zero. const_assert!(N != 0); // The backing type is at least as large as `N` bits. const_assert!(N <= T::BITS); // INVARIANT: The caller ensures `value` fits within `N` bits. Self(value) } /// Attempts to turn `value` into a `Bounded` using `N` bits. /// /// Returns [`None`] if `value` doesn't fit within `N` bits. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u8, 1>::try_new(1); /// assert_eq!(v.as_deref().copied(), Some(1)); /// /// let v = Bounded::<i8, 4>::try_new(-2); /// assert_eq!(v.as_deref().copied(), Some(-2)); /// /// // `0x1ff` doesn't fit into 8 unsigned bits. /// let v = Bounded::<u32, 8>::try_new(0x1ff); /// assert_eq!(v, None); /// /// // The range of values representable with 4 bits is `[-8..=7]`. The following tests these /// // limits. /// let v = Bounded::<i8, 4>::try_new(-8); /// assert_eq!(v.map(Bounded::get), Some(-8)); /// let v = Bounded::<i8, 4>::try_new(-9); /// assert_eq!(v, None); /// let v = Bounded::<i8, 4>::try_new(7); /// assert_eq!(v.map(Bounded::get), Some(7)); /// let v = Bounded::<i8, 4>::try_new(8); /// assert_eq!(v, None); /// ``` pub fn try_new(value: T) -> Option<Self> { fits_within(value, N).then(|| { // SAFETY: `fits_within` confirmed that `value` can be represented within `N` bits. unsafe { Self::__new(value) } }) } /// Checks that `expr` is valid for this type at compile-time and build a new value. /// /// This relies on [`build_assert!`] and guaranteed optimization to perform validation at /// compile-time. If `expr` cannot be proved to be within the requested bounds at compile-time, /// use the fallible [`Self::try_new`] instead. /// /// Limit this to simple, easily provable expressions, and prefer one of the [`Self::new`] /// constructors whenever possible as they statically validate the value instead of relying on /// compiler optimizations. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// # fn some_number() -> u32 { 0xffffffff } /// /// // Some undefined number. /// let v: u32 = some_number(); /// /// // Triggers a build error as `v` cannot be asserted to fit within 4 bits... /// // let _ = Bounded::<u32, 4>::from_expr(v); /// /// // ... but this works as the compiler can assert the range from the mask. /// let _ = Bounded::<u32, 4>::from_expr(v & 0xf); /// /// // These expressions are simple enough to be proven correct, but since they are static the /// // `new` constructor should be preferred. /// assert_eq!(Bounded::<u8, 1>::from_expr(1).get(), 1); /// assert_eq!(Bounded::<u16, 8>::from_expr(0xff).get(), 0xff); /// ``` // Always inline to optimize out error path of `build_assert`. #[inline(always)] pub fn from_expr(expr: T) -> Self { crate::build_assert::build_assert!( fits_within(expr, N), "Requested value larger than maximal representable value." ); // SAFETY: `fits_within` confirmed that `expr` can be represented within `N` bits. unsafe { Self::__new(expr) } } /// Returns the wrapped value as the backing type. /// /// This is similar to the [`Deref`] implementation, but doesn't enforce the size invariant of /// the [`Bounded`], which might produce slightly less optimal code. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 4>::new::<7>(); /// assert_eq!(v.get(), 7u32); /// ``` pub const fn get(self) -> T { self.0 } /// Increases the number of bits usable for `self`. /// /// This operation cannot fail. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 4>::new::<7>(); /// let larger_v = v.extend::<12>(); /// // The contained values are equal even though `larger_v` has a bigger capacity. /// assert_eq!(larger_v, v); /// ``` pub const fn extend<const M: u32>(self) -> Bounded<T, M> { const_assert!( M >= N, "Requested number of bits is less than the current representation." ); // SAFETY: The value did fit within `N` bits, so it will all the more fit within // the larger `M` bits. unsafe { Bounded::__new(self.0) } } /// Attempts to shrink the number of bits usable for `self`. /// /// Returns [`None`] if the value of `self` cannot be represented within `M` bits. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 12>::new::<7>(); /// /// // `7` can be represented using 3 unsigned bits... /// let smaller_v = v.try_shrink::<3>(); /// assert_eq!(smaller_v.as_deref().copied(), Some(7)); /// /// // ... but doesn't fit within `2` bits. /// assert_eq!(v.try_shrink::<2>(), None); /// ``` pub fn try_shrink<const M: u32>(self) -> Option<Bounded<T, M>> { Bounded::<T, M>::try_new(self.get()) } /// Casts `self` into a [`Bounded`] backed by a different storage type, but using the same /// number of valid bits. /// /// Both `T` and `U` must be of same signedness, and `U` must be at least as large as /// `N` bits, or a build error will occur. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 12>::new::<127>(); /// /// let u16_v: Bounded<u16, 12> = v.cast(); /// assert_eq!(u16_v.get(), 127); /// /// // This won't build: a `u8` is smaller than the required 12 bits. /// // let _: Bounded<u8, 12> = v.cast(); /// ``` pub fn cast<U>(self) -> Bounded<U, N> where U: TryFrom<T> + Integer, T: Integer, U: Integer<Signedness = T::Signedness>, { // SAFETY: The converted value is represented using `N` bits, `U` can contain `N` bits, and // `U` and `T` have the same sign, hence this conversion cannot fail. let value = unsafe { U::try_from(self.get()).unwrap_unchecked() }; // SAFETY: Although the backing type has changed, the value is still represented within // `N` bits, and with the same signedness. unsafe { Bounded::__new(value) } } /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, RES>`, where `RES >= /// N - SHIFT`. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 16>::new::<0xff00>(); /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>(); /// /// assert_eq!(v_shifted.get(), 0xff); /// ``` pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> { const { assert!(RES + SHIFT >= N) } // SAFETY: We shift the value right by `SHIFT`, reducing the number of bits needed to // represent the shifted value by as much, and just asserted that `RES >= N - SHIFT`. unsafe { Bounded::__new(self.0 >> SHIFT) } } /// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, RES>`, where `RES >= /// N + SHIFT`. /// /// # Examples /// /// ```Lines 1–500 of 1121. Load more
// SPDX-License-Identifier: GPL-2.0 //! Implementation of [`Bounded`], a wrapper around integer types limiting the number of bits //! usable for value representation. use core::{ cmp, fmt, ops::{ self, Deref, // }, //, }; use kernel::{ num::Integer, prelude::*, // }; /// Evaluates to `true` if `$value` can be represented using at most `$n` bits in a `$type`. /// /// `expr` must be of type `type`, or the result will be incorrect. /// /// Can be used in const context. macro_rules! fits_within { ($value:expr, $type:ty, $n:expr) => {{ let shift: u32 = <$type>::BITS - $n; // `value` fits within `$n` bits if shifting it left by the number of unused bits, then // right by the same number, doesn't change it. // // This method has the benefit of working for both unsigned and signed values. ($value << shift) >> shift == $value }}; } /// Returns `true` if `value` can be represented with at most `N` bits in a `T`. #[inline(always)] fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool { fits_within!(value, T, num_bits) } /// An integer value that requires only the `N` least significant bits of the wrapped type to be /// encoded. /// /// This limits the number of usable bits in the wrapped integer type, and thus the stored value to /// a narrower range, which provides guarantees that can be useful when working within e.g. /// bitfields. /// /// # Invariants /// /// - `N` is greater than `0`. /// - `N` is less than or equal to `T::BITS`. /// - Stored values can be represented with at most `N` bits. /// /// # Examples /// /// The preferred way to create values is through constants and the [`Bounded::new`] family of /// constructors, as they trigger a build error if the type invariants cannot be upheld. /// /// ``` /// use kernel::num::Bounded; /// /// // An unsigned 8-bit integer, of which only the 4 LSBs are used. /// // The value `15` is statically validated to fit that constraint at build time. /// let v = Bounded::<u8, 4>::new::<15>(); /// assert_eq!(v.get(), 15); /// /// // Same using signed values. /// let v = Bounded::<i8, 4>::new::<-8>(); /// assert_eq!(v.get(), -8); /// /// // This doesn't build: a `u8` is smaller than the requested 9 bits. /// // let _ = Bounded::<u8, 9>::new::<10>(); /// /// // This also doesn't build: the requested value doesn't fit within 4 signed bits. /// // let _ = Bounded::<i8, 4>::new::<8>(); /// ``` /// /// Values can also be validated at runtime with [`Bounded::try_new`]. /// /// ``` /// use kernel::num::Bounded; /// /// // This succeeds because `15` can be represented with 4 unsigned bits. /// assert!(Bounded::<u8, 4>::try_new(15).is_some()); /// /// // This fails because `16` cannot be represented with 4 unsigned bits. /// assert!(Bounded::<u8, 4>::try_new(16).is_none()); /// ``` /// /// Non-constant expressions can be validated at build-time thanks to compiler optimizations. This /// should be used with caution, on simple expressions only. /// /// ``` /// use kernel::num::Bounded; /// # fn some_number() -> u32 { 0xffffffff } /// /// // Here the compiler can infer from the mask that the type invariants are not violated, even /// // though the value returned by `some_number` is not statically known. /// let v = Bounded::<u32, 4>::from_expr(some_number() & 0xf); /// ``` /// /// Comparison and arithmetic operations are supported on [`Bounded`]s with a compatible backing /// type, regardless of their number of valid bits. /// /// ``` /// use kernel::num::Bounded; /// /// let v1 = Bounded::<u32, 8>::new::<4>(); /// let v2 = Bounded::<u32, 4>::new::<15>(); /// /// assert!(v1 != v2); /// assert!(v1 < v2); /// assert_eq!(v1 + v2, 19); /// assert_eq!(v2 % v1, 3); /// ``` /// /// These operations are also supported between a [`Bounded`] and its backing type. /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u8, 4>::new::<15>(); /// /// assert!(v == 15); /// assert!(v > 12); /// assert_eq!(v + 5, 20); /// assert_eq!(v / 3, 5); /// ``` /// /// A change of backing types is possible using [`Bounded::cast`], and the number of valid bits can /// be extended or reduced with [`Bounded::extend`] and [`Bounded::try_shrink`]. /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 12>::new::<127>(); /// /// // Changes backing type from `u32` to `u16`. /// let _: Bounded<u16, 12> = v.cast(); /// /// // This does not build, as `u8` is smaller than 12 bits. /// // let _: Bounded<u8, 12> = v.cast(); /// /// // We can safely extend the number of bits... /// let _ = v.extend::<15>(); /// /// // ... to the limits of the backing type. This doesn't build as a `u32` cannot contain 33 bits. /// // let _ = v.extend::<33>(); /// /// // Reducing the number of bits is validated at runtime. This works because `127` can be /// // represented with 8 bits. /// assert!(v.try_shrink::<8>().is_some()); /// /// // ... but not with 6, so this fails. /// assert!(v.try_shrink::<6>().is_none()); /// ``` /// /// Infallible conversions from a primitive integer to a large-enough [`Bounded`] are supported. /// /// ``` /// use kernel::num::Bounded; /// /// // This unsigned `Bounded` has 8 bits, so it can represent any `u8`. /// let v = Bounded::<u32, 8>::from(128u8); /// assert_eq!(v.get(), 128); /// /// // This signed `Bounded` has 8 bits, so it can represent any `i8`. /// let v = Bounded::<i32, 8>::from(-128i8); /// assert_eq!(v.get(), -128); /// /// // This doesn't build, as this 6-bit `Bounded` does not have enough capacity to represent a /// // `u8` (regardless of the passed value). /// // let _ = Bounded::<u32, 6>::from(10u8); /// /// // Booleans can be converted into single-bit `Bounded`s. /// /// let v = Bounded::<u64, 1>::from(false); /// assert_eq!(v.get(), 0); /// /// let v = Bounded::<u64, 1>::from(true); /// assert_eq!(v.get(), 1); /// ``` /// /// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and /// dependent on the number of bits used for value representation, not on the backing type. /// /// ``` /// use kernel::num::Bounded; /// /// // Even though its backing type is `u32`, this `Bounded` only uses 6 bits and thus can safely /// // be converted to a `u8`. /// let v = Bounded::<u32, 6>::new::<63>(); /// assert_eq!(u8::from(v), 63); /// /// // Same using signed values. /// let v = Bounded::<i32, 8>::new::<-128>(); /// assert_eq!(i8::from(v), -128); /// /// // This however does not build, as 10 bits won't fit into a `u8` (regardless of the actually /// // contained value). /// let _v = Bounded::<u32, 10>::new::<10>(); /// // assert_eq!(u8::from(_v), 10); /// /// // Single-bit `Bounded`s can be converted into a boolean. /// let v = Bounded::<u8, 1>::new::<1>(); /// assert_eq!(bool::from(v), true); /// /// let v = Bounded::<u8, 1>::new::<0>(); /// assert_eq!(bool::from(v), false); /// ``` /// /// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the /// [`TryIntoBounded`] trait. /// /// ``` /// use kernel::num::{Bounded, TryIntoBounded}; /// /// // Succeeds because `128` fits into 8 bits. /// let v: Option<Bounded<u16, 8>> = 128u32.try_into_bounded(); /// assert_eq!(v.as_deref().copied(), Some(128)); /// /// // Fails because `128` doesn't fit into 6 bits. /// let v: Option<Bounded<u16, 6>> = 128u32.try_into_bounded(); /// assert_eq!(v, None); /// ``` #[repr(transparent)] #[derive(Clone, Copy, Debug, Default, Hash)] pub struct Bounded<T: Integer, const N: u32>(T); /// Validating the value as a const expression cannot be done as a regular method, as the /// arithmetic operations we rely on to check the bounds are not const. Thus, implement /// [`Bounded::new`] using a macro. macro_rules! impl_const_new { ($($type:ty)*) => { $( impl<const N: u32> Bounded<$type, N> { /// Creates a [`Bounded`] for the constant `VALUE`. /// /// Fails at build time if `VALUE` cannot be represented with `N` bits. /// /// This method should be preferred to [`Self::from_expr`] whenever possible. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// #[doc = ::core::concat!( "let v = Bounded::<", ::core::stringify!($type), ", 4>::new::<7>();")] /// assert_eq!(v.get(), 7); /// ``` pub const fn new<const VALUE: $type>() -> Self { // Statically assert that `VALUE` fits within the set number of bits. const_assert!(fits_within!(VALUE, $type, N)); // SAFETY: `fits_within` confirmed that `VALUE` can be represented within // `N` bits. unsafe { Self::__new(VALUE) } } } )* }; } impl_const_new!( u8 u16 u32 u64 usize i8 i16 i32 i64 isize ); impl<T, const N: u32> Bounded<T, N> where T: Integer, { /// Private constructor enforcing the type invariants. /// /// All instances of [`Bounded`] must be created through this method as it enforces most of the /// type invariants. /// /// # Safety /// /// The caller must ensure that `value` can be represented within `N` bits. const unsafe fn __new(value: T) -> Self { // Enforce the type invariants. // `N` cannot be zero. const_assert!(N != 0); // The backing type is at least as large as `N` bits. const_assert!(N <= T::BITS); // INVARIANT: The caller ensures `value` fits within `N` bits. Self(value) } /// Attempts to turn `value` into a `Bounded` using `N` bits. /// /// Returns [`None`] if `value` doesn't fit within `N` bits. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u8, 1>::try_new(1); /// assert_eq!(v.as_deref().copied(), Some(1)); /// /// let v = Bounded::<i8, 4>::try_new(-2); /// assert_eq!(v.as_deref().copied(), Some(-2)); /// /// // `0x1ff` doesn't fit into 8 unsigned bits. /// let v = Bounded::<u32, 8>::try_new(0x1ff); /// assert_eq!(v, None); /// /// // The range of values representable with 4 bits is `[-8..=7]`. The following tests these /// // limits. /// let v = Bounded::<i8, 4>::try_new(-8); /// assert_eq!(v.map(Bounded::get), Some(-8)); /// let v = Bounded::<i8, 4>::try_new(-9); /// assert_eq!(v, None); /// let v = Bounded::<i8, 4>::try_new(7); /// assert_eq!(v.map(Bounded::get), Some(7)); /// let v = Bounded::<i8, 4>::try_new(8); /// assert_eq!(v, None); /// ``` pub fn try_new(value: T) -> Option<Self> { fits_within(value, N).then(|| { // SAFETY: `fits_within` confirmed that `value` can be represented within `N` bits. unsafe { Self::__new(value) } }) } /// Checks that `expr` is valid for this type at compile-time and build a new value. /// /// This relies on [`build_assert!`] and guaranteed optimization to perform validation at /// compile-time. If `expr` cannot be proved to be within the requested bounds at compile-time, /// use the fallible [`Self::try_new`] instead. /// /// Limit this to simple, easily provable expressions, and prefer one of the [`Self::new`] /// constructors whenever possible as they statically validate the value instead of relying on /// compiler optimizations. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// # fn some_number() -> u32 { 0xffffffff } /// /// // Some undefined number. /// let v: u32 = some_number(); /// /// // Triggers a build error as `v` cannot be asserted to fit within 4 bits... /// // let _ = Bounded::<u32, 4>::from_expr(v); /// /// // ... but this works as the compiler can assert the range from the mask. /// let _ = Bounded::<u32, 4>::from_expr(v & 0xf); /// /// // These expressions are simple enough to be proven correct, but since they are static the /// // `new` constructor should be preferred. /// assert_eq!(Bounded::<u8, 1>::from_expr(1).get(), 1); /// assert_eq!(Bounded::<u16, 8>::from_expr(0xff).get(), 0xff); /// ``` // Always inline to optimize out error path of `build_assert`. #[inline(always)] pub fn from_expr(expr: T) -> Self { crate::build_assert::build_assert!( fits_within(expr, N), "Requested value larger than maximal representable value." ); // SAFETY: `fits_within` confirmed that `expr` can be represented within `N` bits. unsafe { Self::__new(expr) } } /// Returns the wrapped value as the backing type. /// /// This is similar to the [`Deref`] implementation, but doesn't enforce the size invariant of /// the [`Bounded`], which might produce slightly less optimal code. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 4>::new::<7>(); /// assert_eq!(v.get(), 7u32); /// ``` pub const fn get(self) -> T { self.0 } /// Increases the number of bits usable for `self`. /// /// This operation cannot fail. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 4>::new::<7>(); /// let larger_v = v.extend::<12>(); /// // The contained values are equal even though `larger_v` has a bigger capacity. /// assert_eq!(larger_v, v); /// ``` pub const fn extend<const M: u32>(self) -> Bounded<T, M> { const_assert!( M >= N, "Requested number of bits is less than the current representation." ); // SAFETY: The value did fit within `N` bits, so it will all the more fit within // the larger `M` bits. unsafe { Bounded::__new(self.0) } } /// Attempts to shrink the number of bits usable for `self`. /// /// Returns [`None`] if the value of `self` cannot be represented within `M` bits. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 12>::new::<7>(); /// /// // `7` can be represented using 3 unsigned bits... /// let smaller_v = v.try_shrink::<3>(); /// assert_eq!(smaller_v.as_deref().copied(), Some(7)); /// /// // ... but doesn't fit within `2` bits. /// assert_eq!(v.try_shrink::<2>(), None); /// ``` pub fn try_shrink<const M: u32>(self) -> Option<Bounded<T, M>> { Bounded::<T, M>::try_new(self.get()) } /// Casts `self` into a [`Bounded`] backed by a different storage type, but using the same /// number of valid bits. /// /// Both `T` and `U` must be of same signedness, and `U` must be at least as large as /// `N` bits, or a build error will occur. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 12>::new::<127>(); /// /// let u16_v: Bounded<u16, 12> = v.cast(); /// assert_eq!(u16_v.get(), 127); /// /// // This won't build: a `u8` is smaller than the required 12 bits. /// // let _: Bounded<u8, 12> = v.cast(); /// ``` pub fn cast<U>(self) -> Bounded<U, N> where U: TryFrom<T> + Integer, T: Integer, U: Integer<Signedness = T::Signedness>, { // SAFETY: The converted value is represented using `N` bits, `U` can contain `N` bits, and // `U` and `T` have the same sign, hence this conversion cannot fail. let value = unsafe { U::try_from(self.get()).unwrap_unchecked() }; // SAFETY: Although the backing type has changed, the value is still represented within // `N` bits, and with the same signedness. unsafe { Bounded::__new(value) } } /// Right-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, RES>`, where `RES >= /// N - SHIFT`. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 16>::new::<0xff00>(); /// let v_shifted: Bounded::<u32, 8> = v.shr::<8, _>(); /// /// assert_eq!(v_shifted.get(), 0xff); /// ``` pub fn shr<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> { const { assert!(RES + SHIFT >= N) } // SAFETY: We shift the value right by `SHIFT`, reducing the number of bits needed to // represent the shifted value by as much, and just asserted that `RES >= N - SHIFT`. unsafe { Bounded::__new(self.0 >> SHIFT) } } /// Left-shifts `self` by `SHIFT` and returns the result as a `Bounded<_, RES>`, where `RES >= /// N + SHIFT`. /// /// # Examples /// /// ```