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