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}