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}