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::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
23
24#[macro_export]
50macro_rules! non_max {
51 ($val:expr) => {{
52 const _: () = const {
53 if $val == <_ as $crate::NonMaxItem>::MAX {
54 panic!("provided value is the maximum value for this type");
55 }
56 };
57 unsafe { <_ as $crate::NonMaxItem>::create_nonmax_unchecked($val) }
58 }};
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct MaxValueError;
64
65impl Display for MaxValueError {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "provided value is the maximum value for this type")
68 }
69}
70
71impl core::error::Error for MaxValueError {}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86pub struct NonMax<T: NonMaxItem>(T::NonZero);
87
88impl<T: NonMaxItem + Copy> NonMax<T> {
89 pub fn new(value: T) -> Option<Self> {
98 Value::new(value).to_inner_repr().to_nonmax()
99 }
100
101 fn to_real_repr(self) -> Value<T, Real> {
102 T::from_nonzero(self.0).to_real_repr()
103 }
104
105 pub fn get(&self) -> T {
114 self.to_real_repr().value()
115 }
116}
117
118impl<T: NonMaxItem + Copy + PartialEq> NonMax<T> {
119 pub fn is_min(&self) -> bool {
121 self.get() == T::MIN_VALUE
122 }
123
124 pub fn is_max(&self) -> bool {
126 self.get() == T::MAX_SAFE
127 }
128
129 pub fn is_zero(&self) -> bool {
131 self.get() == T::ZERO_VALUE
132 }
133}
134
135impl<T: NonMaxItem + Copy> NonMax<T> {
136 pub fn checked_add(self, rhs: Self) -> Option<Self> {
139 self.get().checked_add(rhs.get()).and_then(Self::new)
140 }
141
142 pub fn checked_sub(self, rhs: Self) -> Option<Self> {
145 self.get().checked_sub(rhs.get()).and_then(Self::new)
146 }
147
148 pub fn checked_mul(self, rhs: Self) -> Option<Self> {
151 self.get().checked_mul(rhs.get()).and_then(Self::new)
152 }
153
154 pub fn checked_div(self, rhs: Self) -> Option<Self> {
157 self.get().checked_div(rhs.get()).and_then(Self::new)
158 }
159
160 pub fn checked_rem(self, rhs: Self) -> Option<Self> {
163 self.get().checked_rem(rhs.get()).and_then(Self::new)
164 }
165
166 pub fn checked_add_val(self, rhs: T) -> Option<Self> {
176 self.get().checked_add(rhs).and_then(Self::new)
177 }
178
179 pub fn checked_sub_val(self, rhs: T) -> Option<Self> {
181 self.get().checked_sub(rhs).and_then(Self::new)
182 }
183
184 pub fn checked_mul_val(self, rhs: T) -> Option<Self> {
186 self.get().checked_mul(rhs).and_then(Self::new)
187 }
188
189 pub fn checked_div_val(self, rhs: T) -> Option<Self> {
191 self.get().checked_div(rhs).and_then(Self::new)
192 }
193
194 pub fn checked_rem_val(self, rhs: T) -> Option<Self> {
196 self.get().checked_rem(rhs).and_then(Self::new)
197 }
198}
199
200impl<T: NonMaxItem + Copy + Add<Output = T>> Add for NonMax<T> {
201 type Output = Self;
202 fn add(self, rhs: Self) -> Self::Output {
203 self.checked_add(rhs)
204 .expect("attempt to add with overflow or to maximum value")
205 }
206}
207
208impl<T: NonMaxItem + Copy + Add<Output = T>> Add<T> for NonMax<T> {
209 type Output = Self;
210 fn add(self, rhs: T) -> Self::Output {
211 self.checked_add_val(rhs)
212 .expect("attempt to add with overflow or to maximum value")
213 }
214}
215
216impl<T: NonMaxItem + Copy + Add<Output = T>> AddAssign for NonMax<T> {
217 fn add_assign(&mut self, rhs: Self) {
218 *self = *self + rhs;
219 }
220}
221
222impl<T: NonMaxItem + Copy + Add<Output = T>> AddAssign<T> for NonMax<T> {
223 fn add_assign(&mut self, rhs: T) {
224 *self = *self + rhs;
225 }
226}
227
228impl<T: NonMaxItem + Copy + Sub<Output = T>> Sub for NonMax<T> {
229 type Output = Self;
230 fn sub(self, rhs: Self) -> Self::Output {
231 self.checked_sub(rhs)
232 .expect("attempt to subtract with overflow or to maximum value")
233 }
234}
235
236impl<T: NonMaxItem + Copy + Sub<Output = T>> Sub<T> for NonMax<T> {
237 type Output = Self;
238 fn sub(self, rhs: T) -> Self::Output {
239 self.checked_sub_val(rhs)
240 .expect("attempt to subtract with overflow or to maximum value")
241 }
242}
243
244impl<T: NonMaxItem + Copy + Sub<Output = T>> SubAssign for NonMax<T> {
245 fn sub_assign(&mut self, rhs: Self) {
246 *self = *self - rhs;
247 }
248}
249
250impl<T: NonMaxItem + Copy + Sub<Output = T>> SubAssign<T> for NonMax<T> {
251 fn sub_assign(&mut self, rhs: T) {
252 *self = *self - rhs;
253 }
254}
255
256impl<T: NonMaxItem + Copy + Mul<Output = T>> Mul for NonMax<T> {
257 type Output = Self;
258 fn mul(self, rhs: Self) -> Self::Output {
259 self.checked_mul(rhs)
260 .expect("attempt to multiply with overflow or to maximum value")
261 }
262}
263
264impl<T: NonMaxItem + Copy + Mul<Output = T>> Mul<T> for NonMax<T> {
265 type Output = Self;
266 fn mul(self, rhs: T) -> Self::Output {
267 self.checked_mul_val(rhs)
268 .expect("attempt to multiply with overflow or to maximum value")
269 }
270}
271
272impl<T: NonMaxItem + Copy + Mul<Output = T>> MulAssign for NonMax<T> {
273 fn mul_assign(&mut self, rhs: Self) {
274 *self = *self * rhs;
275 }
276}
277
278impl<T: NonMaxItem + Copy + Mul<Output = T>> MulAssign<T> for NonMax<T> {
279 fn mul_assign(&mut self, rhs: T) {
280 *self = *self * rhs;
281 }
282}
283
284impl<T: NonMaxItem + Copy + Div<Output = T>> Div for NonMax<T> {
285 type Output = Self;
286 fn div(self, rhs: Self) -> Self::Output {
287 self.checked_div(rhs)
288 .expect("attempt to divide by zero or to maximum value")
289 }
290}
291
292impl<T: NonMaxItem + Copy + Div<T, Output = T>> Div<T> for NonMax<T> {
293 type Output = Self;
294 fn div(self, rhs: T) -> Self::Output {
295 self.checked_div_val(rhs)
296 .expect("attempt to divide by zero or to maximum value")
297 }
298}
299
300impl<T: NonMaxItem + Copy + Div<Output = T>> DivAssign for NonMax<T> {
301 fn div_assign(&mut self, rhs: Self) {
302 *self = *self / rhs;
303 }
304}
305
306impl<T: NonMaxItem + Copy + Div<T, Output = T>> DivAssign<T> for NonMax<T> {
307 fn div_assign(&mut self, rhs: T) {
308 *self = *self / rhs;
309 }
310}
311
312impl<T: NonMaxItem + Copy + Rem<Output = T>> Rem for NonMax<T> {
313 type Output = Self;
314 fn rem(self, rhs: Self) -> Self::Output {
315 self.checked_rem(rhs)
316 .expect("attempt to calculate remainder by zero or to maximum value")
317 }
318}
319
320impl<T: NonMaxItem + Copy + Rem<T, Output = T>> Rem<T> for NonMax<T> {
321 type Output = Self;
322 fn rem(self, rhs: T) -> Self::Output {
323 self.checked_rem_val(rhs)
324 .expect("attempt to calculate remainder by zero or to maximum value")
325 }
326}
327
328impl<T: NonMaxItem + Copy + Rem<Output = T>> RemAssign for NonMax<T> {
329 fn rem_assign(&mut self, rhs: Self) {
330 *self = *self % rhs;
331 }
332}
333
334impl<T: NonMaxItem + Copy + Rem<T, Output = T>> RemAssign<T> for NonMax<T> {
335 fn rem_assign(&mut self, rhs: T) {
336 *self = *self % rhs;
337 }
338}
339
340impl<T: NonMaxItem + Copy + PartialOrd> PartialOrd for NonMax<T> {
341 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
342 self.to_real_repr().partial_cmp(&other.to_real_repr())
343 }
344}
345
346impl<T: NonMaxItem + Copy + Ord> Ord for NonMax<T> {
347 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
348 self.to_real_repr().cmp(&other.to_real_repr())
349 }
350}
351
352impl<T: NonMaxItem + Copy + Display> Display for NonMax<T> {
353 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
354 Display::fmt(&self.get(), f)
355 }
356}
357
358impl<T: NonMaxItem + Copy + Binary> Binary for NonMax<T> {
359 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360 Binary::fmt(&self.get(), f)
361 }
362}
363
364impl<T: NonMaxItem + Copy + Octal> Octal for NonMax<T> {
365 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366 Octal::fmt(&self.get(), f)
367 }
368}
369
370impl<T: NonMaxItem + Copy + LowerHex> LowerHex for NonMax<T> {
371 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
372 LowerHex::fmt(&self.get(), f)
373 }
374}
375
376impl<T: NonMaxItem + Copy + UpperHex> UpperHex for NonMax<T> {
377 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
378 UpperHex::fmt(&self.get(), f)
379 }
380}
381
382impl<T: NonMaxItem + Copy> Default for NonMax<T> {
383 fn default() -> Self {
384 Self::new(T::ZERO_VALUE).unwrap()
385 }
386}
387
388#[doc(hidden)]
389pub trait NonMaxItem: Sized {
390 type NonZero: Copy + PartialEq + Eq + PartialOrd + Ord + Hash;
391 const MIN_VALUE: Self;
392 const MAX: Self;
393 const MAX_SAFE: Self;
394 const ZERO_VALUE: Self;
395 fn transform(self) -> Self;
396 fn to_nonzero(value: Value<Self, Inner>) -> Option<Self::NonZero>;
397 unsafe fn to_nonzero_unchecked(value: Value<Self, Inner>) -> Self::NonZero;
398 fn from_nonzero(value: Self::NonZero) -> Value<Self, Inner>;
399
400 fn checked_add(self, rhs: Self) -> Option<Self>;
401 fn checked_sub(self, rhs: Self) -> Option<Self>;
402 fn checked_mul(self, rhs: Self) -> Option<Self>;
403 fn checked_div(self, rhs: Self) -> Option<Self>;
404 fn checked_rem(self, rhs: Self) -> Option<Self>;
405
406 unsafe fn create_nonmax_unchecked(self) -> NonMax<Self>;
411}
412
413macro_rules! impl_non_max_item {
414 ($($t:ty, $name:ident, $doc:expr),*) => {
415 $(
416 impl NonMaxItem for $t {
417 type NonZero = NonZero<$t>;
418 const MIN_VALUE: Self = <$t>::MIN;
419 const MAX: Self = <$t>::MAX;
420 const MAX_SAFE: Self = <$t>::MAX - 1;
421 const ZERO_VALUE: Self = 0;
422 fn transform(self) -> Self {
423 self ^ <$t>::MAX
424 }
425 fn to_nonzero(value: Value<Self, Inner>) -> Option<Self::NonZero> {
426 Self::NonZero::new(value.value())
427 }
428 unsafe fn to_nonzero_unchecked(value: Value<Self, Inner>) -> Self::NonZero {
429 unsafe { Self::NonZero::new_unchecked(value.value()) }
430 }
431 fn from_nonzero(value: Self::NonZero) -> Value<Self, Inner> {
432 Value::new(value.get())
433 }
434
435 fn checked_add(self, rhs: Self) -> Option<Self> { self.checked_add(rhs) }
436 fn checked_sub(self, rhs: Self) -> Option<Self> { self.checked_sub(rhs) }
437 fn checked_mul(self, rhs: Self) -> Option<Self> { self.checked_mul(rhs) }
438 fn checked_div(self, rhs: Self) -> Option<Self> { self.checked_div(rhs) }
439 fn checked_rem(self, rhs: Self) -> Option<Self> { self.checked_rem(rhs) }
440
441 unsafe fn create_nonmax_unchecked(self) -> NonMax<Self> {
442 unsafe { NonMax::<$t>::new_unchecked(self) }
443 }
444 }
445
446 impl From<NonMax<$t>> for $t {
447 fn from(value: NonMax<$t>) -> Self {
448 value.get()
449 }
450 }
451
452 impl TryFrom<$t> for NonMax<$t> {
453 type Error = MaxValueError;
454
455 fn try_from(value: $t) -> Result<Self, Self::Error> {
456 Self::new(value).ok_or(MaxValueError)
457 }
458 }
459
460 #[doc = $doc]
461 pub type $name = NonMax<$t>;
462
463 impl $name {
464 pub const MIN: Self = unsafe { Self(NonZero::new_unchecked(<$t>::MIN ^ <$t>::MAX)) };
466 pub const MAX: Self = unsafe { Self(NonZero::new_unchecked((<$t>::MAX - 1) ^ <$t>::MAX)) };
468 pub const ZERO: Self = unsafe { Self(NonZero::new_unchecked(0 ^ <$t>::MAX)) };
470
471 pub const unsafe fn new_unchecked(value: $t) -> Self {
476 Self(unsafe { NonZero::new_unchecked(value ^ <$t>::MAX) })
477 }
478 }
479 )*
480 };
481}
482
483impl_non_max_item!(
484 u8,
485 NonMaxU8,
486 "An unsigned 8-bit integer that cannot be `u8::MAX`.",
487 u16,
488 NonMaxU16,
489 "An unsigned 16-bit integer that cannot be `u16::MAX`.",
490 u32,
491 NonMaxU32,
492 "An unsigned 32-bit integer that cannot be `u32::MAX`.",
493 u64,
494 NonMaxU64,
495 "An unsigned 64-bit integer that cannot be `u64::MAX`.",
496 u128,
497 NonMaxU128,
498 "An unsigned 128-bit integer that cannot be `u128::MAX`.",
499 usize,
500 NonMaxUsize,
501 "An unsigned pointer-sized integer that cannot be `usize::MAX`.",
502 i8,
503 NonMaxI8,
504 "A signed 8-bit integer that cannot be `i8::MAX`.",
505 i16,
506 NonMaxI16,
507 "A signed 16-bit integer that cannot be `i16::MAX`.",
508 i32,
509 NonMaxI32,
510 "A signed 32-bit integer that cannot be `i32::MAX`.",
511 i64,
512 NonMaxI64,
513 "A signed 64-bit integer that cannot be `i64::MAX`.",
514 i128,
515 NonMaxI128,
516 "A signed 128-bit integer that cannot be `i128::MAX`.",
517 isize,
518 NonMaxIsize,
519 "A signed pointer-sized integer that cannot be `isize::MAX`."
520);
521
522#[doc(hidden)]
523#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
524pub struct Real;
525#[doc(hidden)]
526#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
527pub struct Inner;
528
529#[doc(hidden)]
530#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
531pub struct Value<T, M> {
532 value: T,
533 _marker: PhantomData<M>,
534}
535
536impl<T: NonMaxItem + Copy, M> Value<T, M> {
537 fn new(value: T) -> Self {
538 Self {
539 value,
540 _marker: PhantomData,
541 }
542 }
543
544 fn value(&self) -> T {
545 self.value
546 }
547}
548
549impl<T: NonMaxItem + Copy> Value<T, Real> {
550 fn to_inner_repr(self) -> Value<T, Inner> {
551 Value::new(T::transform(self.value))
552 }
553}
554
555impl<T: NonMaxItem + Copy + Add<Output = T>> Add for Value<T, Real> {
556 type Output = Self;
557 fn add(self, rhs: Self) -> Self::Output {
558 Self::new(self.value() + rhs.value())
559 }
560}
561
562impl<T: NonMaxItem + Copy + Sub<Output = T>> Sub for Value<T, Real> {
563 type Output = Self;
564 fn sub(self, rhs: Self) -> Self::Output {
565 Self::new(self.value() - rhs.value())
566 }
567}
568
569impl<T: NonMaxItem + Copy + Mul<Output = T>> Mul for Value<T, Real> {
570 type Output = Self;
571 fn mul(self, rhs: Self) -> Self::Output {
572 Self::new(self.value() * rhs.value())
573 }
574}
575
576impl<T: NonMaxItem + Copy + Div<Output = T>> Div for Value<T, Real> {
577 type Output = Self;
578 fn div(self, rhs: Self) -> Self::Output {
579 Self::new(self.value() / rhs.value())
580 }
581}
582
583impl<T: NonMaxItem + Copy + Rem<Output = T>> Rem for Value<T, Real> {
584 type Output = Self;
585 fn rem(self, rhs: Self) -> Self::Output {
586 Self::new(self.value() % rhs.value())
587 }
588}
589
590impl<T: NonMaxItem + Copy> Value<T, Inner> {
591 fn to_real_repr(self) -> Value<T, Real> {
592 Value::new(T::transform(self.value))
593 }
594
595 fn to_nonmax(self) -> Option<NonMax<T>> {
596 T::to_nonzero(self).map(NonMax)
597 }
598}
599
600impl<T: NonMaxItem + Copy + PartialOrd> PartialOrd for Value<T, Real> {
601 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
602 self.value().partial_cmp(&other.value())
603 }
604}
605
606impl<T: NonMaxItem + Copy + Ord> Ord for Value<T, Real> {
607 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
608 self.value().cmp(&other.value())
609 }
610}
611
612impl<T: NonMaxItem + Copy + Display> Display for Value<T, Real> {
613 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
614 write!(f, "{}", self.value())
615 }
616}
617
618#[cfg(test)]
619mod tests {
620 extern crate std;
621 use super::*;
622 use core::mem::size_of;
623 use std::collections::HashSet;
624
625 #[test]
626 fn test_hash() {
627 let mut set = HashSet::new();
628 set.insert(NonMaxU32::new(1).unwrap());
629 set.insert(NonMaxU32::new(2).unwrap());
630 set.insert(NonMaxU32::new(1).unwrap());
631
632 assert_eq!(set.len(), 2);
633 assert!(set.contains(&NonMaxU32::new(1).unwrap()));
634 }
635
636 #[test]
637 fn test_sizes() {
638 assert_eq!(size_of::<NonMaxU32>(), 4);
639 assert_eq!(size_of::<Option<NonMaxU32>>(), 4);
640
641 assert_eq!(size_of::<NonMaxI32>(), 4);
642 assert_eq!(size_of::<Option<NonMaxI32>>(), 4);
643
644 assert_eq!(size_of::<NonMaxU8>(), 1);
645 assert_eq!(size_of::<Option<NonMaxU8>>(), 1);
646 }
647
648 #[test]
649 fn test_conversions() {
650 let x = NonMaxU8::try_from(100).unwrap();
651 assert_eq!(u8::from(x), 100);
652
653 let max_val = u8::MAX;
654 assert!(NonMaxU8::try_from(max_val).is_err());
655 }
656
657 #[test]
658 fn test_arithmetic_with_val() {
659 let x = NonMaxU8::new(100).unwrap();
660 let y = x + 50;
661 assert_eq!(u8::from(y), 150);
662
663 let mut z = NonMaxU8::new(10).unwrap();
664 z += 20;
665 assert_eq!(u8::from(z), 30);
666
667 let a = NonMaxU8::new(10).unwrap();
668 let b = a * 5;
669 assert_eq!(u8::from(b), 50);
670
671 let c = NonMaxU8::new(100).unwrap();
672 let d = c / 3;
673 assert_eq!(u8::from(d), 33);
674 }
675
676 #[test]
677 fn test_add_overflow() {
678 let x = NonMaxU8::try_from(250).unwrap();
679 assert!(x.checked_add_val(10).is_none());
681 }
682
683 #[test]
684 fn test_add_to_max() {
685 let x = NonMaxU8::try_from(250).unwrap();
686 assert!(x.checked_add_val(5).is_none());
688 }
689
690 #[test]
691 fn test_signed_integer() {
692 let x = NonMaxI8::try_from(100).unwrap();
694 let y = x + 20;
695 assert_eq!(i8::from(y), 120);
696
697 let z = NonMaxI8::try_from(-50).unwrap();
698 let w = z + 10;
699 assert_eq!(i8::from(w), -40);
700
701 let min_val = NonMaxI8::try_from(i8::MIN).unwrap();
703 assert_eq!(i8::from(min_val), -128);
704 }
705
706 #[test]
707 fn test_signed_overflow() {
708 let x = NonMaxI8::try_from(120).unwrap();
709 assert!(x.checked_add_val(10).is_none());
711 }
712
713 #[test]
714 fn test_signed_to_max() {
715 let x = NonMaxI8::try_from(120).unwrap();
716 assert!(x.checked_add_val(7).is_none());
718 }
719
720 #[test]
721 fn test_formatting() {
722 let x = NonMaxU8::new(254).unwrap();
723 assert_eq!(std::format!("{}", x), "254");
724 assert_eq!(std::format!("{:b}", x), "11111110");
725 assert_eq!(std::format!("{:o}", x), "376");
726 assert_eq!(std::format!("{:x}", x), "fe");
727 assert_eq!(std::format!("{:X}", x), "FE");
728 }
729
730 #[test]
731 fn test_min_max_constants() {
732 assert_eq!(NonMaxU8::MIN.get(), 0);
733 assert_eq!(NonMaxU8::MAX.get(), 254);
734 assert!(NonMaxU8::MIN.is_min());
735 assert!(NonMaxU8::MAX.is_max());
736 assert!(!NonMaxU8::MIN.is_max());
737 assert!(!NonMaxU8::MAX.is_min());
738
739 assert_eq!(NonMaxI8::MIN.get(), -128);
740 assert_eq!(NonMaxI8::MAX.get(), 126);
741 }
742
743 #[test]
744 fn test_zero_constant() {
745 assert_eq!(NonMaxU8::ZERO.get(), 0);
746 assert!(NonMaxU8::ZERO.is_zero());
747 assert_eq!(NonMaxI32::ZERO.get(), 0);
748 assert!(NonMaxI32::ZERO.is_zero());
749 }
750
751 #[test]
752 fn test_non_max_macro() {
753 let x = non_max!(123u8);
754 assert_eq!(x.get(), 123);
755
756 let y = non_max!(456u32);
757 assert_eq!(y.get(), 456);
758
759 let z = non_max!(-10i32);
760 assert_eq!(z.get(), -10);
761 }
762}