1#![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#[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#[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#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub struct NonMax<T: NonMaxItem>(T::NonZero);
92
93impl<T: NonMaxItem + Copy> NonMax<T> {
94 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 pub fn get(&self) -> T {
119 self.to_real_repr().value()
120 }
121}
122
123impl<T: NonMaxItem + Copy + PartialEq> NonMax<T> {
124 pub fn is_min(&self) -> bool {
126 self.to_real_repr() == Value::new(T::MIN_VALUE)
127 }
128
129 pub fn is_max(&self) -> bool {
131 self.to_real_repr() == Value::new(T::MAX_SAFE)
132 }
133
134 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 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 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 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 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 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 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 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 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 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 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 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 pub const MIN: Self = unsafe { Self(NonZero::new_unchecked(<$t>::MIN ^ <$t>::MAX)) };
501 pub const MAX: Self = unsafe { Self(NonZero::new_unchecked((<$t>::MAX - 1) ^ <$t>::MAX)) };
503 pub const ZERO: Self = unsafe { Self(NonZero::new_unchecked(0 ^ <$t>::MAX)) };
505
506 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 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 assert!(x.checked_add_val(5).is_none());
799 }
800
801 #[test]
802 fn test_signed_integer() {
803 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 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 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 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}