pub struct Bounded<T: Integer, const N: u32>(/* private fields */);Expand description
An integer value that requires only the N less 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 with in e.g. bitfields.
§Invariants
Nis greater than0.Nis less than or equal toT::BITS.- Stored values can be represented with at most
Nbits.
§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 withheld.
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;
// 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 Boundeds 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_bitint();
assert_eq!(v.as_deref().copied(), Some(128));
// Fails because `128` doesn't fits into 6 bits.
let v: Option<Bounded<u16, 6>> = 128u32.try_into_bitint();
assert_eq!(v, None);Implementations§
Source§impl<const N: u32> Bounded<u8, N>
impl<const N: u32> Bounded<u8, N>
Sourcepub const fn new<const VALUE: u8>() -> Self
pub const fn new<const VALUE: u8>() -> Self
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;
let v = Bounded::<u8, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<u16, N>
impl<const N: u32> Bounded<u16, N>
Sourcepub const fn new<const VALUE: u16>() -> Self
pub const fn new<const VALUE: u16>() -> Self
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;
let v = Bounded::<u16, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<u32, N>
impl<const N: u32> Bounded<u32, N>
Sourcepub const fn new<const VALUE: u32>() -> Self
pub const fn new<const VALUE: u32>() -> Self
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;
let v = Bounded::<u32, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<u64, N>
impl<const N: u32> Bounded<u64, N>
Sourcepub const fn new<const VALUE: u64>() -> Self
pub const fn new<const VALUE: u64>() -> Self
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;
let v = Bounded::<u64, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<usize, N>
impl<const N: u32> Bounded<usize, N>
Sourcepub const fn new<const VALUE: usize>() -> Self
pub const fn new<const VALUE: usize>() -> Self
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;
let v = Bounded::<usize, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<i8, N>
impl<const N: u32> Bounded<i8, N>
Sourcepub const fn new<const VALUE: i8>() -> Self
pub const fn new<const VALUE: i8>() -> Self
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;
let v = Bounded::<i8, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<i16, N>
impl<const N: u32> Bounded<i16, N>
Sourcepub const fn new<const VALUE: i16>() -> Self
pub const fn new<const VALUE: i16>() -> Self
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;
let v = Bounded::<i16, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<i32, N>
impl<const N: u32> Bounded<i32, N>
Sourcepub const fn new<const VALUE: i32>() -> Self
pub const fn new<const VALUE: i32>() -> Self
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;
let v = Bounded::<i32, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<i64, N>
impl<const N: u32> Bounded<i64, N>
Sourcepub const fn new<const VALUE: i64>() -> Self
pub const fn new<const VALUE: i64>() -> Self
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;
let v = Bounded::<i64, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<const N: u32> Bounded<isize, N>
impl<const N: u32> Bounded<isize, N>
Sourcepub const fn new<const VALUE: isize>() -> Self
pub const fn new<const VALUE: isize>() -> Self
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;
let v = Bounded::<isize, 4>::new::<7>();
assert_eq!(v.get(), 7);Source§impl<T, const N: u32> Bounded<T, N>where
T: Integer,
impl<T, const N: u32> Bounded<T, N>where
T: Integer,
Sourcepub fn try_new(value: T) -> Option<Self>
pub fn try_new(value: T) -> Option<Self>
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);Sourcepub fn from_expr(expr: T) -> Self
pub fn from_expr(expr: T) -> Self
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;
// 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);Sourcepub fn get(self) -> T
pub fn get(self) -> T
Returns the wrapped value as the backing type.
§Examples
use kernel::num::Bounded;
let v = Bounded::<u32, 4>::new::<7>();
assert_eq!(v.get(), 7u32);Sourcepub const fn extend<const M: u32>(self) -> Bounded<T, M>
pub const fn extend<const M: u32>(self) -> Bounded<T, M>
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);Sourcepub fn try_shrink<const M: u32>(self) -> Option<Bounded<T, M>>
pub fn try_shrink<const M: u32>(self) -> Option<Bounded<T, M>>
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);Sourcepub fn cast<U>(self) -> Bounded<U, N>
pub fn cast<U>(self) -> Bounded<U, N>
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();Trait Implementations§
Source§impl<T, const N: u32> Ord for Bounded<T, N>
impl<T, const N: u32> Ord for Bounded<T, N>
Source§impl<T, U, const N: u32, const M: u32> PartialOrd<Bounded<U, M>> for Bounded<T, N>
impl<T, U, const N: u32, const M: u32> PartialOrd<Bounded<U, M>> for Bounded<T, N>
Source§impl<T, const N: u32> PartialOrd<T> for Bounded<T, N>where
T: Integer + PartialOrd,
impl<T, const N: u32> PartialOrd<T> for Bounded<T, N>where
T: Integer + PartialOrd,
impl<T: Copy + Integer, const N: u32> Copy for Bounded<T, N>
impl<T, const N: u32> Eq for Bounded<T, N>where
T: Integer,
Auto Trait Implementations§
impl<T, const N: u32> Freeze for Bounded<T, N>where
T: Freeze,
impl<T, const N: u32> RefUnwindSafe for Bounded<T, N>where
T: RefUnwindSafe,
impl<T, const N: u32> Send for Bounded<T, N>where
T: Send,
impl<T, const N: u32> Sync for Bounded<T, N>where
T: Sync,
impl<T, const N: u32> Unpin for Bounded<T, N>where
T: Unpin,
impl<T, const N: u32> UnwindSafe for Bounded<T, N>where
T: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> PinInit<T> for T
impl<T> PinInit<T> for T
Source§unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible>
unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), Infallible>
slot. Read more