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