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