1mod iter;
70
71pub use iter::SafeArithIter;
72
73#[derive(Debug, PartialEq, Eq, Clone, Copy)]
75pub enum ArithError {
76 Overflow,
77 DivisionByZero,
78}
79
80pub type Result<T> = std::result::Result<T, ArithError>;
81
82macro_rules! assign_method {
83 ($name:ident, $op:ident, $doc_op:expr) => {
84 assign_method!($name, $op, Self, $doc_op);
85 };
86 ($name:ident, $op:ident, $rhs_ty:ty, $doc_op:expr) => {
87 #[doc = "Safe variant of `"]
88 #[doc = $doc_op]
89 #[doc = "`."]
90 #[inline]
91 fn $name(&mut self, other: $rhs_ty) -> Result<()> {
92 *self = self.$op(other)?;
93 Ok(())
94 }
95 };
96}
97
98pub trait SafeArith<Rhs = Self>: Sized + Copy {
100 const ZERO: Self;
101 const ONE: Self;
102
103 fn safe_add(&self, other: Rhs) -> Result<Self>;
105
106 fn safe_sub(&self, other: Rhs) -> Result<Self>;
108
109 fn safe_mul(&self, other: Rhs) -> Result<Self>;
111
112 fn safe_div(&self, other: Rhs) -> Result<Self>;
114
115 fn safe_rem(&self, other: Rhs) -> Result<Self>;
117
118 fn safe_shl(&self, other: u32) -> Result<Self>;
120
121 fn safe_shr(&self, other: u32) -> Result<Self>;
123
124 assign_method!(safe_add_assign, safe_add, Rhs, "+=");
125 assign_method!(safe_sub_assign, safe_sub, Rhs, "-=");
126 assign_method!(safe_mul_assign, safe_mul, Rhs, "*=");
127 assign_method!(safe_div_assign, safe_div, Rhs, "/=");
128 assign_method!(safe_rem_assign, safe_rem, Rhs, "%=");
129 assign_method!(safe_shl_assign, safe_shl, u32, "<<=");
130 assign_method!(safe_shr_assign, safe_shr, u32, ">>=");
131}
132
133macro_rules! impl_safe_arith {
134 ($typ:ty) => {
135 impl SafeArith for $typ {
136 const ZERO: Self = 0;
137 const ONE: Self = 1;
138
139 #[inline]
140 fn safe_add(&self, other: Self) -> Result<Self> {
141 self.checked_add(other).ok_or(ArithError::Overflow)
142 }
143
144 #[inline]
145 fn safe_sub(&self, other: Self) -> Result<Self> {
146 self.checked_sub(other).ok_or(ArithError::Overflow)
147 }
148
149 #[inline]
150 fn safe_mul(&self, other: Self) -> Result<Self> {
151 self.checked_mul(other).ok_or(ArithError::Overflow)
152 }
153
154 #[inline]
155 fn safe_div(&self, other: Self) -> Result<Self> {
156 self.checked_div(other).ok_or(ArithError::DivisionByZero)
157 }
158
159 #[inline]
160 fn safe_rem(&self, other: Self) -> Result<Self> {
161 self.checked_rem(other).ok_or(ArithError::DivisionByZero)
162 }
163
164 #[inline]
165 fn safe_shl(&self, other: u32) -> Result<Self> {
166 self.checked_shl(other).ok_or(ArithError::Overflow)
167 }
168
169 #[inline]
170 fn safe_shr(&self, other: u32) -> Result<Self> {
171 self.checked_shr(other).ok_or(ArithError::Overflow)
172 }
173 }
174 };
175}
176
177impl_safe_arith!(u8);
178impl_safe_arith!(u16);
179impl_safe_arith!(u32);
180impl_safe_arith!(u64);
181impl_safe_arith!(usize);
182impl_safe_arith!(i8);
183impl_safe_arith!(i16);
184impl_safe_arith!(i32);
185impl_safe_arith!(i64);
186impl_safe_arith!(isize);
187
188#[cfg(test)]
189mod test {
190 use super::*;
191
192 #[test]
193 fn basic() {
194 let x = 10u32;
195 let y = 11;
196 assert_eq!(x.safe_add(y), Ok(x + y));
197 assert_eq!(y.safe_sub(x), Ok(y - x));
198 assert_eq!(x.safe_mul(y), Ok(x * y));
199 assert_eq!(x.safe_div(y), Ok(x / y));
200 assert_eq!(x.safe_rem(y), Ok(x % y));
201
202 assert_eq!(x.safe_shl(1), Ok(x << 1));
203 assert_eq!(x.safe_shr(1), Ok(x >> 1));
204 }
205
206 #[test]
207 fn mutate() {
208 let mut x = 0u8;
209 x.safe_add_assign(2).unwrap();
210 assert_eq!(x, 2);
211 x.safe_sub_assign(1).unwrap();
212 assert_eq!(x, 1);
213 x.safe_shl_assign(1).unwrap();
214 assert_eq!(x, 2);
215 x.safe_mul_assign(3).unwrap();
216 assert_eq!(x, 6);
217 x.safe_div_assign(4).unwrap();
218 assert_eq!(x, 1);
219 x.safe_shr_assign(1).unwrap();
220 assert_eq!(x, 0);
221 }
222
223 #[test]
224 fn errors() {
225 assert!(u32::MAX.safe_add(1).is_err());
226 assert!(u32::MIN.safe_sub(1).is_err());
227 assert!(u32::MAX.safe_mul(2).is_err());
228 assert!(u32::MAX.safe_div(0).is_err());
229 assert!(u32::MAX.safe_rem(0).is_err());
230 assert!(u32::MAX.safe_shl(32).is_err());
231 assert!(u32::MAX.safe_shr(32).is_err());
232 }
233}