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}