saturating/
lib.rs

1//! Provides [`Saturating<T>`](`Saturating`), an intentionally-saturating arithmetic wrapper,
2//! similar to [`std::num::Wrapping`].
3//!
4//! # Examples
5//!
6//! ```
7//! use saturating::Saturating;
8//!
9//! let foo = Saturating(253u8);
10//! let bar = Saturating(100u8);
11//!
12//! assert_eq!(std::u8::MAX, (foo + bar).0);
13//! ```
14
15#![no_std]
16
17use core::fmt;
18use core::ops::*;
19
20/// Provides intentionally-saturating arithmetic on `T`.
21///
22/// The underlying value can be retrieved through the `.0` index of the
23/// `Saturating` tuple.
24#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
25#[repr(transparent)]
26pub struct Saturating<T>(pub T);
27
28impl<T: fmt::Debug> fmt::Debug for Saturating<T> {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        self.0.fmt(f)
31    }
32}
33
34impl<T: fmt::Display> fmt::Display for Saturating<T> {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        self.0.fmt(f)
37    }
38}
39
40impl<T: fmt::Binary> fmt::Binary for Saturating<T> {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        self.0.fmt(f)
43    }
44}
45
46impl<T: fmt::Octal> fmt::Octal for Saturating<T> {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        self.0.fmt(f)
49    }
50}
51
52impl<T: fmt::LowerHex> fmt::LowerHex for Saturating<T> {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        self.0.fmt(f)
55    }
56}
57
58impl<T: fmt::UpperHex> fmt::UpperHex for Saturating<T> {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        self.0.fmt(f)
61    }
62}
63
64// implements the unary operator "op &T"
65// based on "op T" where T is expected to be `Copy`able
66macro_rules! forward_ref_unop {
67    (impl $imp:ident, $method:ident for $t:ty) => {
68        impl $imp for &$t {
69            type Output = <$t as $imp>::Output;
70
71            #[inline]
72            fn $method(self) -> <$t as $imp>::Output {
73                $imp::$method(*self)
74            }
75        }
76    }
77}
78
79// implements binary operators "&T op U", "T op &U", "&T op &U"
80// based on "T op U" where T and U are expected to be `Copy`able
81macro_rules! forward_ref_binop {
82    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
83        impl<'a> $imp<$u> for &'a $t {
84            type Output = <$t as $imp<$u>>::Output;
85
86            #[inline]
87            fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
88                $imp::$method(*self, other)
89            }
90        }
91
92        impl $imp<&$u> for $t {
93            type Output = <$t as $imp<$u>>::Output;
94
95            #[inline]
96            fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
97                $imp::$method(self, *other)
98            }
99        }
100
101        impl $imp<&$u> for &$t {
102            type Output = <$t as $imp<$u>>::Output;
103
104            #[inline]
105            fn $method(self, other: &$u) -> <$t as $imp<$u>>::Output {
106                $imp::$method(*self, *other)
107            }
108        }
109    }
110}
111
112// implements "T op= &U", based on "T op= U"
113// where U is expected to be `Copy`able
114macro_rules! forward_ref_op_assign {
115    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
116        impl $imp<&$u> for $t {
117            #[inline]
118            fn $method(&mut self, other: &$u) {
119                $imp::$method(self, *other);
120            }
121        }
122    }
123}
124
125macro_rules! saturating_impl {
126    ($($t:ty)*) => ($(
127        impl Add for Saturating<$t> {
128            type Output = Saturating<$t>;
129
130            #[inline]
131            fn add(self, other: Saturating<$t>) -> Saturating<$t> {
132                Saturating(self.0.saturating_add(other.0))
133            }
134        }
135        forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t> }
136
137        impl AddAssign for Saturating<$t> {
138            #[inline]
139            fn add_assign(&mut self, other: Saturating<$t>) {
140                *self = *self + other;
141            }
142        }
143        forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> }
144
145        impl Sub for Saturating<$t> {
146            type Output = Saturating<$t>;
147
148            #[inline]
149            fn sub(self, other: Saturating<$t>) -> Saturating<$t> {
150                Saturating(self.0.saturating_sub(other.0))
151            }
152        }
153        forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t> }
154
155        impl SubAssign for Saturating<$t> {
156            #[inline]
157            fn sub_assign(&mut self, other: Saturating<$t>) {
158                *self = *self - other;
159            }
160        }
161        forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> }
162
163        impl Mul for Saturating<$t> {
164            type Output = Saturating<$t>;
165
166            #[inline]
167            fn mul(self, other: Saturating<$t>) -> Saturating<$t> {
168                Saturating(self.0.saturating_mul(other.0))
169            }
170        }
171        forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t> }
172
173        impl MulAssign for Saturating<$t> {
174            #[inline]
175            fn mul_assign(&mut self, other: Saturating<$t>) {
176                *self = *self * other;
177            }
178        }
179        forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> }
180
181        impl Neg for Saturating<$t> {
182            type Output = Self;
183            #[inline]
184            fn neg(self) -> Self {
185                Saturating(0) - self
186            }
187        }
188        forward_ref_unop! { impl Neg, neg for Saturating<$t> }
189
190    )*)
191}
192
193saturating_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }