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