Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122// 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 /// /// ``` /// use kernel::num::Bounded; /// /// let v = Bounded::<u32, 8>::new::<0xff>(); /// let v_shifted: Bounded::<u32, 16> = v.shl::<8, _>(); /// /// assert_eq!(v_shifted.get(), 0xff00); /// ``` pub fn shl<const SHIFT: u32, const RES: u32>(self) -> Bounded<T, RES> { const { assert!(RES >= N + SHIFT) }
// SAFETY: We shift the value left by `SHIFT`, augmenting 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) } }}
impl<T, const N: u32> Deref for Bounded<T, N>where T: Integer,{ type Target = T;
fn deref(&self) -> &Self::Target { // Enforce the invariant to inform the compiler of the bounds of the value. if !fits_within(self.0, N) { // SAFETY: Per the `Bounded` invariants, `fits_within` can never return `false` on the // value of a valid instance. unsafe { core::hint::unreachable_unchecked() } }
&self.0 }}
/// Trait similar to [`TryInto`] but for [`Bounded`], to avoid conflicting implementations.////// # Examples////// ```/// 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);/// ```pub trait TryIntoBounded<T: Integer, const N: u32> { /// Attempts to convert `self` into a [`Bounded`] using `N` bits. /// /// Returns [`None`] if `self` does not fit into the target type. fn try_into_bounded(self) -> Option<Bounded<T, N>>;}
/// Any integer value can be attempted to be converted into a [`Bounded`] of any size.impl<T, U, const N: u32> TryIntoBounded<T, N> for Uwhere T: Integer, U: TryInto<T>,{ fn try_into_bounded(self) -> Option<Bounded<T, N>> { self.try_into().ok().and_then(Bounded::try_new) }}
// Comparisons between `Bounded`s.
impl<T, U, const N: u32, const M: u32> PartialEq<Bounded<U, M>> for Bounded<T, N>where T: Integer, U: Integer, T: PartialEq<U>,{ fn eq(&self, other: &Bounded<U, M>) -> bool { self.get() == other.get() }}
impl<T, const N: u32> Eq for Bounded<T, N> where T: Integer {}
impl<T, U, const N: u32, const M: u32> PartialOrd<Bounded<U, M>> for Bounded<T, N>where T: Integer, U: Integer, T: PartialOrd<U>,{ fn partial_cmp(&self, other: &Bounded<U, M>) -> Option<cmp::Ordering> { self.get().partial_cmp(&other.get()) }}
impl<T, const N: u32> Ord for Bounded<T, N>where T: Integer, T: Ord,{ fn cmp(&self, other: &Self) -> cmp::Ordering { self.get().cmp(&other.get()) }}
// Comparisons between a `Bounded` and its backing type.
impl<T, const N: u32> PartialEq<T> for Bounded<T, N>where T: Integer, T: PartialEq,{ fn eq(&self, other: &T) -> bool { self.get() == *other }}
impl<T, const N: u32> PartialOrd<T> for Bounded<T, N>where T: Integer, T: PartialOrd,{ fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> { self.get().partial_cmp(other) }}
// Implementations of `core::ops` for two `Bounded` with the same backing type.
impl<T, const N: u32, const M: u32> ops::Add<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::Add<Output = T>,{ type Output = T;
fn add(self, rhs: Bounded<T, M>) -> Self::Output { self.get() + rhs.get() }}
impl<T, const N: u32, const M: u32> ops::BitAnd<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::BitAnd<Output = T>,{ type Output = T;
fn bitand(self, rhs: Bounded<T, M>) -> Self::Output { self.get() & rhs.get() }}
impl<T, const N: u32, const M: u32> ops::BitOr<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::BitOr<Output = T>,{ type Output = T;
fn bitor(self, rhs: Bounded<T, M>) -> Self::Output { self.get() | rhs.get() }}
impl<T, const N: u32, const M: u32> ops::BitXor<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::BitXor<Output = T>,{ type Output = T;
fn bitxor(self, rhs: Bounded<T, M>) -> Self::Output { self.get() ^ rhs.get() }}
impl<T, const N: u32, const M: u32> ops::Div<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::Div<Output = T>,{ type Output = T;
fn div(self, rhs: Bounded<T, M>) -> Self::Output { self.get() / rhs.get() }}
impl<T, const N: u32, const M: u32> ops::Mul<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::Mul<Output = T>,{ type Output = T;
fn mul(self, rhs: Bounded<T, M>) -> Self::Output { self.get() * rhs.get() }}
impl<T, const N: u32, const M: u32> ops::Rem<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::Rem<Output = T>,{ type Output = T;
fn rem(self, rhs: Bounded<T, M>) -> Self::Output { self.get() % rhs.get() }}
impl<T, const N: u32, const M: u32> ops::Sub<Bounded<T, M>> for Bounded<T, N>where T: Integer, T: ops::Sub<Output = T>,{ type Output = T;
fn sub(self, rhs: Bounded<T, M>) -> Self::Output { self.get() - rhs.get() }}
// Implementations of `core::ops` between a `Bounded` and its backing type.
impl<T, const N: u32> ops::Add<T> for Bounded<T, N>where T: Integer, T: ops::Add<Output = T>,{ type Output = T;
fn add(self, rhs: T) -> Self::Output { self.get() + rhs }}
impl<T, const N: u32> ops::BitAnd<T> for Bounded<T, N>where T: Integer, T: ops::BitAnd<Output = T>,{ type Output = T;
fn bitand(self, rhs: T) -> Self::Output { self.get() & rhs }}
impl<T, const N: u32> ops::BitOr<T> for Bounded<T, N>where T: Integer, T: ops::BitOr<Output = T>,{ type Output = T;
fn bitor(self, rhs: T) -> Self::Output { self.get() | rhs }}
impl<T, const N: u32> ops::BitXor<T> for Bounded<T, N>where T: Integer, T: ops::BitXor<Output = T>,{ type Output = T;
fn bitxor(self, rhs: T) -> Self::Output { self.get() ^ rhs }}
impl<T, const N: u32> ops::Div<T> for Bounded<T, N>where T: Integer, T: ops::Div<Output = T>,{ type Output = T;
fn div(self, rhs: T) -> Self::Output { self.get() / rhs }}
impl<T, const N: u32> ops::Mul<T> for Bounded<T, N>where T: Integer, T: ops::Mul<Output = T>,{ type Output = T;
fn mul(self, rhs: T) -> Self::Output { self.get() * rhs }}
impl<T, const N: u32> ops::Neg for Bounded<T, N>where T: Integer, T: ops::Neg<Output = T>,{ type Output = T;
fn neg(self) -> Self::Output { -self.get() }}
impl<T, const N: u32> ops::Not for Bounded<T, N>where T: Integer, T: ops::Not<Output = T>,{ type Output = T;
fn not(self) -> Self::Output { !self.get() }}
impl<T, const N: u32> ops::Rem<T> for Bounded<T, N>where T: Integer, T: ops::Rem<Output = T>,{ type Output = T;
fn rem(self, rhs: T) -> Self::Output { self.get() % rhs }}
impl<T, const N: u32> ops::Sub<T> for Bounded<T, N>where T: Integer, T: ops::Sub<Output = T>,{ type Output = T;
fn sub(self, rhs: T) -> Self::Output { self.get() - rhs }}
// Proxy implementations of `core::fmt`.
impl<T, const N: u32> fmt::Display for Bounded<T, N>where T: Integer, T: fmt::Display,{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) }}
impl<T, const N: u32> fmt::Binary for Bounded<T, N>where T: Integer, T: fmt::Binary,{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) }}
impl<T, const N: u32> fmt::LowerExp for Bounded<T, N>where T: Integer, T: fmt::LowerExp,{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) }}
impl<T, const N: u32> fmt::LowerHex for Bounded<T, N>where T: Integer, T: fmt::LowerHex,{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) }}
impl<T, const N: u32> fmt::Octal for Bounded<T, N>where T: Integer, T: fmt::Octal,{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) }}
impl<T, const N: u32> fmt::UpperExp for Bounded<T, N>where T: Integer, T: fmt::UpperExp,{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) }}
impl<T, const N: u32> fmt::UpperHex for Bounded<T, N>where T: Integer, T: fmt::UpperHex,{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.get().fmt(f) }}
/// Implements `$trait` for all [`Bounded`] types represented using `$num_bits`.////// This is used to declare size properties as traits that we can constrain against in impl blocks.macro_rules! impl_size_rule { ($trait:ty, $($num_bits:literal)*) => { $( impl<T> $trait for Bounded<T, $num_bits> where T: Integer {} )* };}
/// Local trait expressing the fact that a given [`Bounded`] has at least `N` bits used for value/// representation.trait AtLeastXBits<const N: usize> {}
/// Implementations for infallibly converting a primitive type into a [`Bounded`] that can contain/// it.////// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent/// module.mod atleast_impls { use super::*;
// Number of bits at least as large as 64. impl_size_rule!(AtLeastXBits<64>, 64);
// Anything 64 bits or more is also larger than 32. impl<T> AtLeastXBits<32> for T where T: AtLeastXBits<64> {} // Other numbers of bits at least as large as 32. impl_size_rule!(AtLeastXBits<32>, 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 );
// Anything 32 bits or more is also larger than 16. impl<T> AtLeastXBits<16> for T where T: AtLeastXBits<32> {} // Other numbers of bits at least as large as 16. impl_size_rule!(AtLeastXBits<16>, 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 );
// Anything 16 bits or more is also larger than 8. impl<T> AtLeastXBits<8> for T where T: AtLeastXBits<16> {} // Other numbers of bits at least as large as 8. impl_size_rule!(AtLeastXBits<8>, 8 9 10 11 12 13 14 15);}
/// Generates `From` implementations from a primitive type into a [`Bounded`] with/// enough bits to store any value of that type.////// Note: The only reason for having this macro is that if we pass `$type` as a generic/// parameter, we cannot use it in the const context of [`AtLeastXBits`]'s generic parameter. This/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a/// regular `impl` block.macro_rules! impl_from_primitive { ($($type:ty)*) => { $( #[doc = ::core::concat!( "Conversion from a [`", ::core::stringify!($type), "`] into a [`Bounded`] of same signedness with enough bits to store it.")] impl<T, const N: u32> From<$type> for Bounded<T, N> where $type: Integer, T: Integer<Signedness = <$type as Integer>::Signedness> + From<$type>, Self: AtLeastXBits<{ <$type as Integer>::BITS as usize }>, { fn from(value: $type) -> Self { // SAFETY: The trait bound on `Self` guarantees that `N` bits is // enough to hold any value of the source type. unsafe { Self::__new(T::from(value)) } } } )* }}
impl_from_primitive!( u8 u16 u32 u64 usize i8 i16 i32 i64 isize);
/// Local trait expressing the fact that a given [`Bounded`] fits into a primitive type of `N` bits,/// provided they have the same signedness.trait FitsInXBits<const N: usize> {}
/// Implementations for infallibly converting a [`Bounded`] into a primitive type that can contain/// it.////// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent/// module.mod fits_impls { use super::*;
// Number of bits that fit into a 8-bits primitive. impl_size_rule!(FitsInXBits<8>, 1 2 3 4 5 6 7 8);
// Anything that fits into 8 bits also fits into 16. impl<T> FitsInXBits<16> for T where T: FitsInXBits<8> {} // Other number of bits that fit into a 16-bits primitive. impl_size_rule!(FitsInXBits<16>, 9 10 11 12 13 14 15 16);
// Anything that fits into 16 bits also fits into 32. impl<T> FitsInXBits<32> for T where T: FitsInXBits<16> {} // Other number of bits that fit into a 32-bits primitive. impl_size_rule!(FitsInXBits<32>, 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 );
// Anything that fits into 32 bits also fits into 64. impl<T> FitsInXBits<64> for T where T: FitsInXBits<32> {} // Other number of bits that fit into a 64-bits primitive. impl_size_rule!(FitsInXBits<64>, 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 );}
/// Generates [`From`] implementations from a [`Bounded`] into a primitive type that is/// guaranteed to contain it.////// Note: The only reason for having this macro is that if we pass `$type` as a generic/// parameter, we cannot use it in the const context of `AtLeastXBits`'s generic parameter. This/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a/// regular `impl` block.macro_rules! impl_into_primitive { ($($type:ty)*) => { $( #[doc = ::core::concat!( "Conversion from a [`Bounded`] with no more bits than a [`", ::core::stringify!($type), "`] and of same signedness into [`", ::core::stringify!($type), "`]")] impl<T, const N: u32> From<Bounded<T, N>> for $type where $type: Integer + TryFrom<T>, T: Integer<Signedness = <$type as Integer>::Signedness>, Bounded<T, N>: FitsInXBits<{ <$type as Integer>::BITS as usize }>, { fn from(value: Bounded<T, N>) -> $type { // SAFETY: The trait bound on `Bounded` ensures that any value it holds (which // is constrained to `N` bits) can fit into the destination type, so this // conversion cannot fail. unsafe { <$type>::try_from(value.get()).unwrap_unchecked() } } } )* }}
impl_into_primitive!( u8 u16 u32 u64 usize i8 i16 i32 i64 isize);
// Single-bit `Bounded`s can be converted from/to a boolean.
impl<T> From<Bounded<T, 1>> for boolwhere T: Integer + Zeroable,{ fn from(value: Bounded<T, 1>) -> Self { value.get() != Zeroable::zeroed() }}
impl<T, const N: u32> From<bool> for Bounded<T, N>where T: Integer + From<bool>,{ fn from(value: bool) -> Self { // SAFETY: A boolean can be represented using a single bit, and thus fits within any // integer type for any `N` > 0. unsafe { Self::__new(T::from(value)) } }}
impl<T> Bounded<T, 1>where T: Integer + Zeroable,{ /// Converts this [`Bounded`] into a [`bool`]. /// /// This is a shorter way of writing `bool::from(self)`. /// /// # Examples /// /// ``` /// use kernel::num::Bounded; /// /// assert_eq!(Bounded::<u8, 1>::new::<0>().into_bool(), false); /// assert_eq!(Bounded::<u8, 1>::new::<1>().into_bool(), true); /// ``` pub fn into_bool(self) -> bool { self.into() }}