Skip to main content

arithmetic_nonmax/
lib.rs

1//! `NonMax` provides integer types that cannot be the maximum value of their underlying primitive type.
2//!
3//! # Memory Optimization
4//!
5//! The main benefit of `NonMax<T>` is that `Option<NonMax<T>>` has the same size as `T`.
6//! This is achieved through Rust's "niche optimization", where the bit pattern of the
7//! maximum value is used to represent `None`.
8//!
9//! | Primitive | `size_of::<T>()` | `size_of::<Option<T>>()` | `size_of::<Option<NonMax<T>>>()` |
10//! |-----------|------------------|--------------------------|---------------------------------|
11//! | `u32`     | 4                | 8                        | **4**                           |
12//! | `i32`     | 4                | 8                        | **4**                           |
13//! | `u8`      | 1                | 2                        | **1**                           |
14//!
15//! # Examples
16//!
17//! ```
18//! use arithmetic_nonmax::*;
19//! use core::mem::size_of;
20//!
21//! // The size of Option<NonMax*> is the same as the underlying primitive type.
22//! assert_eq!(size_of::<Option<NonMaxU32>>(), 4);
23//! assert_eq!(size_of::<Option<u32>>(), 8);
24//!
25//! assert_eq!(size_of::<Option<NonMaxI32>>(), 4);
26//! assert_eq!(size_of::<Option<i32>>(), 8);
27//!
28//! assert_eq!(size_of::<Option<NonMaxU8>>(), 1);
29//! assert_eq!(size_of::<Option<u8>>(), 2);
30//! ```
31
32#![no_std]
33
34use core::convert::TryFrom;
35use core::fmt::{self, Binary, Display, LowerHex, Octal, UpperHex};
36use core::hash::Hash;
37use core::marker::PhantomData;
38use core::num::NonZero;
39use core::ops::{
40    Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign,
41};
42
43#[cfg(feature = "alloc")]
44extern crate alloc;
45
46/// Creates a `NonMax` value at compile-time.
47///
48/// This macro checks at compile-time that the provided value is not the maximum
49/// value for its type. If the value is the maximum, the program will fail to compile.
50///
51/// # Examples
52/// ```
53/// # use arithmetic_nonmax::non_max;
54/// let x = non_max!(123u8);
55/// ```
56///
57/// ```compile_fail
58/// # use arithmetic_nonmax::non_max;
59/// let x = non_max!(255u8); // This fails to compile
60/// ```
61///
62/// ```compile_fail
63/// # use arithmetic_nonmax::non_max;
64/// let x = non_max!(127i8); // i8::MAX fails
65/// ```
66///
67/// ```compile_fail
68/// # use arithmetic_nonmax::non_max;
69/// let x = non_max!(u16::MAX); // Explicit MAX fails
70/// ```
71#[macro_export]
72macro_rules! non_max {
73    ($val:expr) => {{
74        const _: () = const {
75            if $val == <_ as $crate::NonMaxItem>::MAX {
76                panic!("provided value is the maximum value for this type");
77            }
78        };
79        unsafe { <_ as $crate::NonMaxItem>::create_nonmax_unchecked($val) }
80    }};
81}
82
83/// Error type returned when a value is the maximum for its type.
84#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub struct MaxValueError;
86
87impl Display for MaxValueError {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        write!(f, "provided value is the maximum value for this type")
90    }
91}
92
93impl core::error::Error for MaxValueError {}
94
95/// A wrapper type for an integer that cannot be its maximum value.
96///
97/// This type leverages Rust's `NonZero` optimization by mapping the maximum value to zero internally.
98/// As a result, `Option<NonMax<T>>` has the same size as the underlying primitive type `T`.
99///
100/// # Examples
101/// ```
102/// # use arithmetic_nonmax::NonMaxU32;
103/// # use core::mem::size_of;
104/// assert_eq!(size_of::<NonMaxU32>(), 4);
105/// assert_eq!(size_of::<Option<NonMaxU32>>(), 4);
106/// ```
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
108pub struct NonMax<T: NonMaxItem>(T::NonZero);
109
110impl<T: NonMaxItem + Copy> NonMax<T> {
111    /// Creates a new `NonMax` if the given value is not the maximum value.
112    ///
113    /// # Examples
114    /// ```
115    /// # use arithmetic_nonmax::NonMaxU8;
116    /// assert!(NonMaxU8::new(254).is_some());
117    /// assert!(NonMaxU8::new(255).is_none());
118    /// ```
119    pub fn new(value: T) -> Option<Self> {
120        Value::new(value).to_inner_repr().to_nonmax()
121    }
122
123    fn to_real_repr(self) -> Value<T, Real> {
124        T::from_nonzero(self.0).to_real_repr()
125    }
126
127    /// Returns the underlying primitive value.
128    ///
129    /// # Examples
130    /// ```
131    /// # use arithmetic_nonmax::NonMaxU32;
132    /// let x = NonMaxU32::new(123).unwrap();
133    /// assert_eq!(x.get(), 123);
134    /// ```
135    pub fn get(&self) -> T {
136        self.to_real_repr().value()
137    }
138}
139
140impl<T: NonMaxItem + Copy + PartialEq> NonMax<T> {
141    /// Returns `true` if this is the minimum value.
142    pub fn is_min(&self) -> bool {
143        self.to_real_repr() == Value::new(T::MIN_VALUE)
144    }
145
146    /// Returns `true` if this is the maximum possible value for this type.
147    pub fn is_max(&self) -> bool {
148        self.to_real_repr() == Value::new(T::MAX_SAFE)
149    }
150
151    /// Returns `true` if the value is zero.
152    pub fn is_zero(&self) -> bool {
153        self.to_real_repr() == Value::new(T::ZERO_VALUE)
154    }
155}
156
157impl<T: NonMaxItem + Copy> NonMax<T> {
158    /// Checked integer addition. Computes `self + rhs`, returning `None` if overflow occurred
159    /// or if the result is the maximum value.
160    pub fn checked_add(self, rhs: Self) -> Option<Self> {
161        self.to_real_repr()
162            .checked_add(rhs.to_real_repr())?
163            .to_inner_repr()
164            .to_nonmax()
165    }
166
167    /// Checked integer subtraction. Computes `self - rhs`, returning `None` if overflow occurred
168    /// or if the result is the maximum value.
169    pub fn checked_sub(self, rhs: Self) -> Option<Self> {
170        self.to_real_repr()
171            .checked_sub(rhs.to_real_repr())?
172            .to_inner_repr()
173            .to_nonmax()
174    }
175
176    /// Checked integer multiplication. Computes `self * rhs`, returning `None` if overflow occurred
177    /// or if the result is the maximum value.
178    pub fn checked_mul(self, rhs: Self) -> Option<Self> {
179        self.to_real_repr()
180            .checked_mul(rhs.to_real_repr())?
181            .to_inner_repr()
182            .to_nonmax()
183    }
184
185    /// Checked integer division. Computes `self / rhs`, returning `None` if the divisor is zero
186    /// or if the result is the maximum value.
187    pub fn checked_div(self, rhs: Self) -> Option<Self> {
188        self.to_real_repr()
189            .checked_div(rhs.to_real_repr())?
190            .to_inner_repr()
191            .to_nonmax()
192    }
193
194    /// Checked integer remainder. Computes `self % rhs`, returning `None` if the divisor is zero
195    /// or if the result is the maximum value.
196    pub fn checked_rem(self, rhs: Self) -> Option<Self> {
197        self.to_real_repr()
198            .checked_rem(rhs.to_real_repr())?
199            .to_inner_repr()
200            .to_nonmax()
201    }
202
203    /// Checked addition with a primitive value.
204    ///
205    /// # Examples
206    /// ```
207    /// # use arithmetic_nonmax::NonMaxU8;
208    /// let x = NonMaxU8::new(100).unwrap();
209    /// assert_eq!(x.checked_add_val(50).unwrap().get(), 150);
210    /// assert!(x.checked_add_val(155).is_none()); // 255 is MAX
211    /// ```
212    pub fn checked_add_val(self, rhs: T) -> Option<Self> {
213        self.to_real_repr()
214            .checked_add(Value::new(rhs))?
215            .to_inner_repr()
216            .to_nonmax()
217    }
218
219    /// Checked subtraction with a primitive value.
220    pub fn checked_sub_val(self, rhs: T) -> Option<Self> {
221        self.to_real_repr()
222            .checked_sub(Value::new(rhs))?
223            .to_inner_repr()
224            .to_nonmax()
225    }
226
227    /// Checked multiplication with a primitive value.
228    pub fn checked_mul_val(self, rhs: T) -> Option<Self> {
229        self.to_real_repr()
230            .checked_mul(Value::new(rhs))?
231            .to_inner_repr()
232            .to_nonmax()
233    }
234
235    /// Checked division with a primitive value.
236    pub fn checked_div_val(self, rhs: T) -> Option<Self> {
237        self.to_real_repr()
238            .checked_div(Value::new(rhs))?
239            .to_inner_repr()
240            .to_nonmax()
241    }
242
243    /// Checked remainder with a primitive value.
244    pub fn checked_rem_val(self, rhs: T) -> Option<Self> {
245        self.to_real_repr()
246            .checked_rem(Value::new(rhs))?
247            .to_inner_repr()
248            .to_nonmax()
249    }
250}
251
252impl<T: NonMaxItem + Copy + Add<Output = T>> Add for NonMax<T> {
253    type Output = Self;
254    fn add(self, rhs: Self) -> Self::Output {
255        self.checked_add(rhs)
256            .expect("attempt to add with overflow or to maximum value")
257    }
258}
259
260impl<T: NonMaxItem + Copy + Add<Output = T>> Add<T> for NonMax<T> {
261    type Output = Self;
262    fn add(self, rhs: T) -> Self::Output {
263        self.checked_add_val(rhs)
264            .expect("attempt to add with overflow or to maximum value")
265    }
266}
267
268impl<T: NonMaxItem + Copy + Add<Output = T>> AddAssign for NonMax<T> {
269    fn add_assign(&mut self, rhs: Self) {
270        *self = *self + rhs;
271    }
272}
273
274impl<T: NonMaxItem + Copy + Add<Output = T>> AddAssign<T> for NonMax<T> {
275    fn add_assign(&mut self, rhs: T) {
276        *self = *self + rhs;
277    }
278}
279
280impl<T: NonMaxItem + Copy + Sub<Output = T>> Sub for NonMax<T> {
281    type Output = Self;
282    fn sub(self, rhs: Self) -> Self::Output {
283        self.checked_sub(rhs)
284            .expect("attempt to subtract with overflow or to maximum value")
285    }
286}
287
288impl<T: NonMaxItem + Copy + Sub<Output = T>> Sub<T> for NonMax<T> {
289    type Output = Self;
290    fn sub(self, rhs: T) -> Self::Output {
291        self.checked_sub_val(rhs)
292            .expect("attempt to subtract with overflow or to maximum value")
293    }
294}
295
296impl<T: NonMaxItem + Copy + Sub<Output = T>> SubAssign for NonMax<T> {
297    fn sub_assign(&mut self, rhs: Self) {
298        *self = *self - rhs;
299    }
300}
301
302impl<T: NonMaxItem + Copy + Sub<Output = T>> SubAssign<T> for NonMax<T> {
303    fn sub_assign(&mut self, rhs: T) {
304        *self = *self - rhs;
305    }
306}
307
308impl<T: NonMaxItem + Copy + Mul<Output = T>> Mul for NonMax<T> {
309    type Output = Self;
310    fn mul(self, rhs: Self) -> Self::Output {
311        self.checked_mul(rhs)
312            .expect("attempt to multiply with overflow or to maximum value")
313    }
314}
315
316impl<T: NonMaxItem + Copy + Mul<Output = T>> Mul<T> for NonMax<T> {
317    type Output = Self;
318    fn mul(self, rhs: T) -> Self::Output {
319        self.checked_mul_val(rhs)
320            .expect("attempt to multiply with overflow or to maximum value")
321    }
322}
323
324impl<T: NonMaxItem + Copy + Mul<Output = T>> MulAssign for NonMax<T> {
325    fn mul_assign(&mut self, rhs: Self) {
326        *self = *self * rhs;
327    }
328}
329
330impl<T: NonMaxItem + Copy + Mul<Output = T>> MulAssign<T> for NonMax<T> {
331    fn mul_assign(&mut self, rhs: T) {
332        *self = *self * rhs;
333    }
334}
335
336impl<T: NonMaxItem + Copy + Div<Output = T>> Div for NonMax<T> {
337    type Output = Self;
338    fn div(self, rhs: Self) -> Self::Output {
339        self.checked_div(rhs)
340            .expect("attempt to divide by zero or to maximum value")
341    }
342}
343
344impl<T: NonMaxItem + Copy + Div<T, Output = T>> Div<T> for NonMax<T> {
345    type Output = Self;
346    fn div(self, rhs: T) -> Self::Output {
347        self.checked_div_val(rhs)
348            .expect("attempt to divide by zero or to maximum value")
349    }
350}
351
352impl<T: NonMaxItem + Copy + Div<Output = T>> DivAssign for NonMax<T> {
353    fn div_assign(&mut self, rhs: Self) {
354        *self = *self / rhs;
355    }
356}
357
358impl<T: NonMaxItem + Copy + Div<T, Output = T>> DivAssign<T> for NonMax<T> {
359    fn div_assign(&mut self, rhs: T) {
360        *self = *self / rhs;
361    }
362}
363
364impl<T: NonMaxItem + Copy + Rem<Output = T>> Rem for NonMax<T> {
365    type Output = Self;
366    fn rem(self, rhs: Self) -> Self::Output {
367        self.checked_rem(rhs)
368            .expect("attempt to calculate remainder by zero or to maximum value")
369    }
370}
371
372impl<T: NonMaxItem + Copy + Rem<T, Output = T>> Rem<T> for NonMax<T> {
373    type Output = Self;
374    fn rem(self, rhs: T) -> Self::Output {
375        self.checked_rem_val(rhs)
376            .expect("attempt to calculate remainder by zero or to maximum value")
377    }
378}
379
380impl<T: NonMaxItem + Copy + Rem<Output = T>> RemAssign for NonMax<T> {
381    fn rem_assign(&mut self, rhs: Self) {
382        *self = *self % rhs;
383    }
384}
385
386impl<T: NonMaxItem + Copy + Rem<T, Output = T>> RemAssign<T> for NonMax<T> {
387    fn rem_assign(&mut self, rhs: T) {
388        *self = *self % rhs;
389    }
390}
391
392impl<T: NonMaxItem + Copy + PartialOrd> PartialOrd for NonMax<T> {
393    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
394        self.to_real_repr().partial_cmp(&other.to_real_repr())
395    }
396}
397
398impl<T: NonMaxItem + Copy + Ord> Ord for NonMax<T> {
399    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
400        self.to_real_repr().cmp(&other.to_real_repr())
401    }
402}
403
404impl<T: NonMaxItem + Copy + Display> Display for NonMax<T> {
405    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
406        Display::fmt(&self.to_real_repr(), f)
407    }
408}
409
410impl<T: NonMaxItem + Copy + Binary> Binary for NonMax<T> {
411    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
412        Binary::fmt(&self.to_real_repr(), f)
413    }
414}
415
416impl<T: NonMaxItem + Copy + Octal> Octal for NonMax<T> {
417    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418        Octal::fmt(&self.to_real_repr(), f)
419    }
420}
421
422impl<T: NonMaxItem + Copy + LowerHex> LowerHex for NonMax<T> {
423    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424        LowerHex::fmt(&self.to_real_repr(), f)
425    }
426}
427
428impl<T: NonMaxItem + Copy + UpperHex> UpperHex for NonMax<T> {
429    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430        UpperHex::fmt(&self.to_real_repr(), f)
431    }
432}
433
434impl<T: NonMaxItem + Copy> Default for NonMax<T> {
435    fn default() -> Self {
436        Self::new(T::ZERO_VALUE).unwrap()
437    }
438}
439
440use core::iter::{Product, Sum};
441
442impl<T: NonMaxItem + Copy + Add<Output = T>> Sum for NonMax<T> {
443    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
444        iter.fold(Self::new(T::ZERO_VALUE).unwrap(), |a, b| a + b)
445    }
446}
447
448impl<'a, T: NonMaxItem + Copy + Add<Output = T>> Sum<&'a NonMax<T>> for NonMax<T> {
449    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
450        iter.fold(Self::new(T::ZERO_VALUE).unwrap(), |a, b| a + *b)
451    }
452}
453
454impl<T: NonMaxItem + Copy + Mul<Output = T>> Product for NonMax<T> {
455    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
456        iter.fold(Self::new(T::ONE_VALUE).unwrap(), |a, b| a * b)
457    }
458}
459
460impl<'a, T: NonMaxItem + Copy + Mul<Output = T>> Product<&'a NonMax<T>> for NonMax<T> {
461    fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
462        iter.fold(Self::new(T::ONE_VALUE).unwrap(), |a, b| a * *b)
463    }
464}
465
466#[doc(hidden)]
467pub trait NonMaxItem: Sized {
468    type NonZero: Copy + PartialEq + Eq + PartialOrd + Ord + Hash;
469    const MIN_VALUE: Self;
470    const MAX: Self;
471    const MAX_SAFE: Self;
472    const ZERO_VALUE: Self;
473    const ONE_VALUE: Self;
474    fn transform(self) -> Self;
475    fn to_nonzero(value: Value<Self, Inner>) -> Option<Self::NonZero>;
476    unsafe fn to_nonzero_unchecked(value: Value<Self, Inner>) -> Self::NonZero;
477    fn from_nonzero(value: Self::NonZero) -> Value<Self, Inner>;
478
479    fn checked_add(self, rhs: Self) -> Option<Self>;
480    fn checked_sub(self, rhs: Self) -> Option<Self>;
481    fn checked_mul(self, rhs: Self) -> Option<Self>;
482    fn checked_div(self, rhs: Self) -> Option<Self>;
483    fn checked_rem(self, rhs: Self) -> Option<Self>;
484
485    /// Creates a `NonMax` from this value without checking.
486    ///
487    /// # Safety
488    /// The value must not be the maximum value.
489    unsafe fn create_nonmax_unchecked(self) -> NonMax<Self>;
490}
491
492macro_rules! impl_non_max_item {
493    ($($t:ty, $name:ident, $doc:expr),*) => {
494        $(
495            impl NonMaxItem for $t {
496                type NonZero = NonZero<$t>;
497                const MIN_VALUE: Self = <$t>::MIN;
498                const MAX: Self = <$t>::MAX;
499                const MAX_SAFE: Self = <$t>::MAX - 1;
500                const ZERO_VALUE: Self = 0;
501                const ONE_VALUE: Self = 1;
502                fn transform(self) -> Self {
503                    self ^ <$t>::MAX
504                }
505                fn to_nonzero(value: Value<Self, Inner>) -> Option<Self::NonZero> {
506                    Self::NonZero::new(value.value())
507                }
508                unsafe fn to_nonzero_unchecked(value: Value<Self, Inner>) -> Self::NonZero {
509                    unsafe { Self::NonZero::new_unchecked(value.value()) }
510                }
511                fn from_nonzero(value: Self::NonZero) -> Value<Self, Inner> {
512                    Value::new(value.get())
513                }
514
515                fn checked_add(self, rhs: Self) -> Option<Self> { self.checked_add(rhs) }
516                fn checked_sub(self, rhs: Self) -> Option<Self> { self.checked_sub(rhs) }
517                fn checked_mul(self, rhs: Self) -> Option<Self> { self.checked_mul(rhs) }
518                fn checked_div(self, rhs: Self) -> Option<Self> { self.checked_div(rhs) }
519                fn checked_rem(self, rhs: Self) -> Option<Self> { self.checked_rem(rhs) }
520
521                unsafe fn create_nonmax_unchecked(self) -> NonMax<Self> {
522                    unsafe { NonMax::<$t>::new_unchecked(self) }
523                }
524            }
525
526            impl From<NonMax<$t>> for $t {
527                fn from(value: NonMax<$t>) -> Self {
528                    value.get()
529                }
530            }
531
532            impl TryFrom<$t> for NonMax<$t> {
533                type Error = MaxValueError;
534
535                fn try_from(value: $t) -> Result<Self, Self::Error> {
536                    Self::new(value).ok_or(MaxValueError)
537                }
538            }
539
540            #[doc = $doc]
541            pub type $name = NonMax<$t>;
542
543            impl $name {
544                /// The minimum value for this type.
545                pub const MIN: Self = unsafe { Self(NonZero::new_unchecked(<$t>::MIN ^ <$t>::MAX)) };
546                /// The maximum value for this type.
547                pub const MAX: Self = unsafe { Self(NonZero::new_unchecked((<$t>::MAX - 1) ^ <$t>::MAX)) };
548                /// The zero value for this type.
549                pub const ZERO: Self = unsafe { Self(NonZero::new_unchecked(0 ^ <$t>::MAX)) };
550
551                /// Creates a new `NonMax` without checking the value.
552                ///
553                /// # Safety
554                /// The value must not be the maximum value of the underlying type.
555                pub const unsafe fn new_unchecked(value: $t) -> Self {
556                    Self(unsafe { NonZero::new_unchecked(value ^ <$t>::MAX) })
557                }
558            }
559        )*
560    };
561}
562
563impl_non_max_item!(
564    u8,
565    NonMaxU8,
566    "An unsigned 8-bit integer that cannot be `u8::MAX`.",
567    u16,
568    NonMaxU16,
569    "An unsigned 16-bit integer that cannot be `u16::MAX`.",
570    u32,
571    NonMaxU32,
572    "An unsigned 32-bit integer that cannot be `u32::MAX`.",
573    u64,
574    NonMaxU64,
575    "An unsigned 64-bit integer that cannot be `u64::MAX`.",
576    u128,
577    NonMaxU128,
578    "An unsigned 128-bit integer that cannot be `u128::MAX`.",
579    usize,
580    NonMaxUsize,
581    "An unsigned pointer-sized integer that cannot be `usize::MAX`.",
582    i8,
583    NonMaxI8,
584    "A signed 8-bit integer that cannot be `i8::MAX`.",
585    i16,
586    NonMaxI16,
587    "A signed 16-bit integer that cannot be `i16::MAX`.",
588    i32,
589    NonMaxI32,
590    "A signed 32-bit integer that cannot be `i32::MAX`.",
591    i64,
592    NonMaxI64,
593    "A signed 64-bit integer that cannot be `i64::MAX`.",
594    i128,
595    NonMaxI128,
596    "A signed 128-bit integer that cannot be `i128::MAX`.",
597    isize,
598    NonMaxIsize,
599    "A signed pointer-sized integer that cannot be `isize::MAX`."
600);
601
602#[doc(hidden)]
603#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
604pub struct Real;
605#[doc(hidden)]
606#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
607pub struct Inner;
608
609#[doc(hidden)]
610#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
611pub struct Value<T, M> {
612    value: T,
613    _marker: PhantomData<M>,
614}
615
616impl<T: NonMaxItem + Copy, M> Value<T, M> {
617    fn new(value: T) -> Self {
618        Self {
619            value,
620            _marker: PhantomData,
621        }
622    }
623
624    fn value(&self) -> T {
625        self.value
626    }
627}
628
629impl<T: NonMaxItem + Copy> Value<T, Real> {
630    fn to_inner_repr(self) -> Value<T, Inner> {
631        Value::new(T::transform(self.value))
632    }
633
634    fn checked_add(self, rhs: Self) -> Option<Self> {
635        self.value().checked_add(rhs.value()).map(Self::new)
636    }
637
638    fn checked_sub(self, rhs: Self) -> Option<Self> {
639        self.value().checked_sub(rhs.value()).map(Self::new)
640    }
641
642    fn checked_mul(self, rhs: Self) -> Option<Self> {
643        self.value().checked_mul(rhs.value()).map(Self::new)
644    }
645
646    fn checked_div(self, rhs: Self) -> Option<Self> {
647        self.value().checked_div(rhs.value()).map(Self::new)
648    }
649
650    fn checked_rem(self, rhs: Self) -> Option<Self> {
651        self.value().checked_rem(rhs.value()).map(Self::new)
652    }
653}
654
655impl<T: NonMaxItem + Copy + Add<Output = T>> Add for Value<T, Real> {
656    type Output = Self;
657    fn add(self, rhs: Self) -> Self::Output {
658        Self::new(self.value() + rhs.value())
659    }
660}
661
662impl<T: NonMaxItem + Copy + Sub<Output = T>> Sub for Value<T, Real> {
663    type Output = Self;
664    fn sub(self, rhs: Self) -> Self::Output {
665        Self::new(self.value() - rhs.value())
666    }
667}
668
669impl<T: NonMaxItem + Copy + Mul<Output = T>> Mul for Value<T, Real> {
670    type Output = Self;
671    fn mul(self, rhs: Self) -> Self::Output {
672        Self::new(self.value() * rhs.value())
673    }
674}
675
676impl<T: NonMaxItem + Copy + Div<Output = T>> Div for Value<T, Real> {
677    type Output = Self;
678    fn div(self, rhs: Self) -> Self::Output {
679        Self::new(self.value() / rhs.value())
680    }
681}
682
683impl<T: NonMaxItem + Copy + Rem<Output = T>> Rem for Value<T, Real> {
684    type Output = Self;
685    fn rem(self, rhs: Self) -> Self::Output {
686        Self::new(self.value() % rhs.value())
687    }
688}
689
690impl<T: NonMaxItem + Copy> Value<T, Inner> {
691    fn to_real_repr(self) -> Value<T, Real> {
692        Value::new(T::transform(self.value))
693    }
694
695    fn to_nonmax(self) -> Option<NonMax<T>> {
696        T::to_nonzero(self).map(NonMax)
697    }
698}
699
700impl<T: NonMaxItem + Copy + PartialOrd> PartialOrd for Value<T, Real> {
701    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
702        self.value().partial_cmp(&other.value())
703    }
704}
705
706impl<T: NonMaxItem + Copy + Ord> Ord for Value<T, Real> {
707    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
708        self.value().cmp(&other.value())
709    }
710}
711
712impl<T: NonMaxItem + Copy + Display> Display for Value<T, Real> {
713    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
714        write!(f, "{}", self.value())
715    }
716}
717
718impl<T: NonMaxItem + Copy + Binary> Binary for Value<T, Real> {
719    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
720        Binary::fmt(&self.value(), f)
721    }
722}
723
724impl<T: NonMaxItem + Copy + Octal> Octal for Value<T, Real> {
725    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
726        Octal::fmt(&self.value(), f)
727    }
728}
729
730impl<T: NonMaxItem + Copy + LowerHex> LowerHex for Value<T, Real> {
731    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
732        LowerHex::fmt(&self.value(), f)
733    }
734}
735
736impl<T: NonMaxItem + Copy + UpperHex> UpperHex for Value<T, Real> {
737    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
738        UpperHex::fmt(&self.value(), f)
739    }
740}
741
742impl<T> Index<NonMaxUsize> for [T] {
743    type Output = T;
744    #[inline]
745    fn index(&self, index: NonMaxUsize) -> &Self::Output {
746        &self[index.get()]
747    }
748}
749
750impl<T> IndexMut<NonMaxUsize> for [T] {
751    #[inline]
752    fn index_mut(&mut self, index: NonMaxUsize) -> &mut Self::Output {
753        &mut self[index.get()]
754    }
755}
756
757#[cfg(feature = "alloc")]
758impl<T> Index<NonMaxUsize> for alloc::vec::Vec<T> {
759    type Output = T;
760    #[inline]
761    fn index(&self, index: NonMaxUsize) -> &Self::Output {
762        &self[index.get()]
763    }
764}
765
766#[cfg(feature = "alloc")]
767impl<T> IndexMut<NonMaxUsize> for alloc::vec::Vec<T> {
768    #[inline]
769    fn index_mut(&mut self, index: NonMaxUsize) -> &mut Self::Output {
770        &mut self[index.get()]
771    }
772}
773
774#[cfg(test)]
775mod tests {
776    extern crate std;
777    use super::*;
778    use core::mem::size_of;
779    use std::collections::HashSet;
780
781    #[test]
782    fn test_hash() {
783        let mut set = HashSet::new();
784        set.insert(NonMaxU32::new(1).unwrap());
785        set.insert(NonMaxU32::new(2).unwrap());
786        set.insert(NonMaxU32::new(1).unwrap());
787
788        assert_eq!(set.len(), 2);
789        assert!(set.contains(&NonMaxU32::new(1).unwrap()));
790    }
791
792    #[test]
793    fn test_sizes() {
794        assert_eq!(size_of::<NonMaxU32>(), 4);
795        assert_eq!(size_of::<Option<NonMaxU32>>(), 4);
796
797        assert_eq!(size_of::<NonMaxI32>(), 4);
798        assert_eq!(size_of::<Option<NonMaxI32>>(), 4);
799
800        assert_eq!(size_of::<NonMaxU8>(), 1);
801        assert_eq!(size_of::<Option<NonMaxU8>>(), 1);
802    }
803
804    #[test]
805    fn test_conversions() {
806        let x = NonMaxU8::try_from(100).unwrap();
807        assert_eq!(u8::from(x), 100);
808
809        let max_val = u8::MAX;
810        assert!(NonMaxU8::try_from(max_val).is_err());
811    }
812
813    #[test]
814    fn test_arithmetic_with_val() {
815        let x = NonMaxU8::new(100).unwrap();
816        let y = x + 50;
817        assert_eq!(u8::from(y), 150);
818
819        let mut z = NonMaxU8::new(10).unwrap();
820        z += 20;
821        assert_eq!(u8::from(z), 30);
822
823        let a = NonMaxU8::new(10).unwrap();
824        let b = a * 5;
825        assert_eq!(u8::from(b), 50);
826
827        let c = NonMaxU8::new(100).unwrap();
828        let d = c / 3;
829        assert_eq!(u8::from(d), 33);
830    }
831
832    #[test]
833    fn test_add_overflow() {
834        let x = NonMaxU8::try_from(250).unwrap();
835        // Now it should return None instead of panicking
836        assert!(x.checked_add_val(10).is_none());
837    }
838
839    #[test]
840    fn test_add_to_max() {
841        let x = NonMaxU8::try_from(250).unwrap();
842        // Result is 255 (MAX), so it should return None
843        assert!(x.checked_add_val(5).is_none());
844    }
845
846    #[test]
847    fn test_signed_integer() {
848        // i8: -128 to 127. MAX is 127.
849        let x = NonMaxI8::try_from(100).unwrap();
850        let y = x + 20;
851        assert_eq!(i8::from(y), 120);
852
853        let z = NonMaxI8::try_from(-50).unwrap();
854        let w = z + 10;
855        assert_eq!(i8::from(w), -40);
856
857        // MIN (-128) is allowed
858        let min_val = NonMaxI8::try_from(i8::MIN).unwrap();
859        assert_eq!(i8::from(min_val), -128);
860    }
861
862    #[test]
863    fn test_signed_overflow() {
864        let x = NonMaxI8::try_from(120).unwrap();
865        // Overflow detected
866        assert!(x.checked_add_val(10).is_none());
867    }
868
869    #[test]
870    fn test_signed_to_max() {
871        let x = NonMaxI8::try_from(120).unwrap();
872        // Result is 127 (MAX), so None
873        assert!(x.checked_add_val(7).is_none());
874    }
875
876    #[test]
877    fn test_formatting() {
878        let x = NonMaxU8::new(254).unwrap();
879        assert_eq!(std::format!("{}", x), "254");
880        assert_eq!(std::format!("{:b}", x), "11111110");
881        assert_eq!(std::format!("{:o}", x), "376");
882        assert_eq!(std::format!("{:x}", x), "fe");
883        assert_eq!(std::format!("{:X}", x), "FE");
884    }
885
886    #[test]
887    fn test_min_max_constants() {
888        assert_eq!(NonMaxU8::MIN.get(), 0);
889        assert_eq!(NonMaxU8::MAX.get(), 254);
890        assert!(NonMaxU8::MIN.is_min());
891        assert!(NonMaxU8::MAX.is_max());
892        assert!(!NonMaxU8::MIN.is_max());
893        assert!(!NonMaxU8::MAX.is_min());
894
895        assert_eq!(NonMaxI8::MIN.get(), -128);
896        assert_eq!(NonMaxI8::MAX.get(), 126);
897    }
898
899    #[test]
900    fn test_zero_constant() {
901        assert_eq!(NonMaxU8::ZERO.get(), 0);
902        assert!(NonMaxU8::ZERO.is_zero());
903        assert_eq!(NonMaxI32::ZERO.get(), 0);
904        assert!(NonMaxI32::ZERO.is_zero());
905    }
906
907    #[test]
908    fn test_non_max_macro() {
909        let x = non_max!(123u8);
910        assert_eq!(x.get(), 123);
911
912        let y = non_max!(456u32);
913        assert_eq!(y.get(), 456);
914
915        let z = non_max!(-10i32);
916        assert_eq!(z.get(), -10);
917    }
918
919    #[test]
920    fn test_indexing() {
921        let v = [1, 2, 3];
922        let idx = NonMaxUsize::new(1).unwrap();
923        assert_eq!(v[idx], 2);
924
925        let mut v_mut = [1, 2, 3];
926        v_mut[idx] = 10;
927        assert_eq!(v_mut[1], 10);
928
929        #[cfg(feature = "alloc")]
930        {
931            let v_vec = std::vec![1, 2, 3];
932            assert_eq!(v_vec[idx], 2);
933
934            let mut v_vec_mut = std::vec![1, 2, 3];
935            v_vec_mut[idx] = 20;
936            assert_eq!(v_vec_mut[1], 20);
937        }
938    }
939
940    #[test]
941    fn test_sum_product() {
942        let v = [
943            NonMaxU32::new(1).unwrap(),
944            NonMaxU32::new(2).unwrap(),
945            NonMaxU32::new(3).unwrap(),
946        ];
947
948        let sum: NonMaxU32 = v.iter().copied().sum();
949        assert_eq!(sum.get(), 6);
950
951        let sum_ref: NonMaxU32 = v.iter().sum();
952        assert_eq!(sum_ref.get(), 6);
953
954        let prod: NonMaxU32 = v.iter().copied().product();
955        assert_eq!(prod.get(), 6);
956
957        let prod_ref: NonMaxU32 = v.iter().product();
958        assert_eq!(prod_ref.get(), 6);
959
960        // Test empty iterator
961        let empty: [NonMaxU32; 0] = [];
962        let sum_empty: NonMaxU32 = empty.iter().sum();
963        assert_eq!(sum_empty.get(), 0);
964
965        let prod_empty: NonMaxU32 = empty.iter().product();
966        assert_eq!(prod_empty.get(), 1);
967    }
968}