Skip to main content

arithmetic_nonmax/
lib.rs

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