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