1use std::{i8, i16, i32, i64, isize};
6use std::error::Error;
7use std::fmt::{self, Display, Formatter};
8
9#[derive(Clone, Copy, Debug, Eq, PartialEq)]
11pub struct IntOverflow;
12
13const INT_OVERFLOW_STR: &'static str = "integer overflow";
14
15impl Display for IntOverflow {
16 fn fmt (&self, f: &mut Formatter) -> fmt::Result {
17 f.write_str(INT_OVERFLOW_STR)
18 }
19}
20
21impl Error for IntOverflow {
22 fn description (&self) -> &str { INT_OVERFLOW_STR }
23}
24
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub struct IntUnderflow;
28
29const INT_UNDERFLOW_STR: &'static str = "integer underflow";
30
31impl Display for IntUnderflow {
32 fn fmt (&self, f: &mut Formatter) -> fmt::Result {
33 f.write_str(INT_UNDERFLOW_STR)
34 }
35}
36
37impl Error for IntUnderflow {
38 fn description (&self) -> &str { INT_UNDERFLOW_STR }
39}
40
41#[derive(Clone, Copy, Debug, Eq, PartialEq)]
43pub enum IntRangeError {
44 Overflow,
45 Underflow,
46}
47
48impl IntRangeError {
49 fn as_str (self) -> &'static str {
50 match self {
51 IntRangeError::Overflow => INT_OVERFLOW_STR,
52 IntRangeError::Underflow => INT_UNDERFLOW_STR,
53 }
54 }
55}
56
57impl Display for IntRangeError {
58 fn fmt (&self, f: &mut Formatter) -> fmt::Result {
59 f.write_str(self.as_str())
60 }
61}
62
63impl Error for IntRangeError {
64 fn description (&self) -> &str { self.as_str() }
65}
66
67#[derive(Clone, Copy, Debug, Eq, PartialEq)]
69pub struct DivideByZero;
70
71const DIVIDE_BY_ZERO_STR: &'static str = "divide by zero";
72
73impl Display for DivideByZero {
74 fn fmt (&self, f: &mut Formatter) -> fmt::Result {
75 f.write_str(DIVIDE_BY_ZERO_STR)
76 }
77}
78
79impl Error for DivideByZero {
80 fn description (&self) -> &str { DIVIDE_BY_ZERO_STR }
81}
82
83pub trait TryAdd<RHS = Self> {
85 type Output;
86 type Err;
87
88 fn try_add (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
89}
90
91macro_rules! impl_try_add_unsigned {
92 ($($ty:ty),*) => { $(
93 impl TryAdd for $ty {
94 type Output = $ty;
95 type Err = IntOverflow;
96
97 fn try_add (self, rhs: $ty) -> Result<$ty, IntOverflow> {
98 match self.checked_add(rhs) {
99 None => Err(IntOverflow),
100 Some(n) => Ok(n),
101 }
102 }
103 }
104 )* };
105}
106
107macro_rules! impl_try_add_signed {
108 ($($ty:ty),*) => { $(
109 impl TryAdd for $ty {
110 type Output = $ty;
111 type Err = IntRangeError;
112
113 fn try_add (self, rhs: $ty) -> Result<$ty, IntRangeError> {
114 match self.checked_add(rhs) {
115 None => {
116 if rhs > 0 {
117 Err(IntRangeError::Overflow)
118 } else {
119 Err(IntRangeError::Underflow)
120 }
121 },
122 Some(n) => Ok(n),
123 }
124 }
125 }
126 )* };
127}
128
129impl_try_add_unsigned!(u8, u16, u32, u64, usize);
130impl_try_add_signed!(i8, i16, i32, i64, isize);
131
132#[test]
133fn test_try_add () {
134 assert_eq!(254u8.try_add(1), Ok(255u8));
135 assert_eq!(255u8.try_add(1), Err(IntOverflow));
136 assert_eq!(126i8.try_add(1), Ok(127i8));
137 assert_eq!(127i8.try_add(1), Err(IntRangeError::Overflow));
138 assert_eq!((-127i8).try_add(-1), Ok(-128i8));
139 assert_eq!((-128i8).try_add(-1), Err(IntRangeError::Underflow));
140}
141
142pub trait TrySub<RHS = Self> {
144 type Output;
145 type Err;
146
147 fn try_sub (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
148}
149
150macro_rules! impl_try_sub_unsigned {
151 ($($ty:ty),*) => { $(
152 impl TrySub for $ty {
153 type Output = $ty;
154 type Err = IntUnderflow;
155
156 fn try_sub (self, rhs: $ty) -> Result<$ty, IntUnderflow> {
157 match self.checked_sub(rhs) {
158 None => Err(IntUnderflow),
159 Some(n) => Ok(n),
160 }
161 }
162 }
163 )* };
164}
165
166macro_rules! impl_try_sub_signed {
167 ($($ty:ty),*) => { $(
168 impl TrySub for $ty {
169 type Output = $ty;
170 type Err = IntRangeError;
171
172 fn try_sub (self, rhs: $ty) -> Result<$ty, IntRangeError> {
173 match self.checked_sub(rhs) {
174 None => {
175 if rhs > 0 {
176 Err(IntRangeError::Underflow)
177 } else {
178 Err(IntRangeError::Overflow)
179 }
180 },
181 Some(n) => Ok(n),
182 }
183 }
184 }
185 )* };
186}
187
188impl_try_sub_unsigned!(u8, u16, u32, u64, usize);
189impl_try_sub_signed!(i8, i16, i32, i64, isize);
190
191#[test]
192fn test_try_sub () {
193 assert_eq!(1u8.try_sub(1), Ok(0u8));
194 assert_eq!(0u8.try_sub(1), Err(IntUnderflow));
195 assert_eq!((-127i8).try_sub(1), Ok(-128i8));
196 assert_eq!((-128i8).try_sub(1), Err(IntRangeError::Underflow));
197 assert_eq!(126i8.try_sub(-1), Ok(127i8));
198 assert_eq!(127i8.try_sub(-1), Err(IntRangeError::Overflow));
199}
200
201pub trait TryMul<RHS = Self> {
205 type Output;
206 type Err;
207
208 fn try_mul (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
209}
210
211macro_rules! impl_try_mul_unsigned {
212 ($($ty:ty),*) => { $(
213 impl TryMul for $ty {
214 type Output = $ty;
215 type Err = IntOverflow;
216
217 fn try_mul (self, rhs: $ty) -> Result<$ty, IntOverflow> {
218 match self.checked_mul(rhs) {
219 None => Err(IntOverflow),
220 Some(n) => Ok(n),
221 }
222 }
223 }
224 )* };
225}
226
227macro_rules! impl_try_mul_signed {
228 ($($ty:ty),*) => { $(
229 impl TryMul for $ty {
230 type Output = $ty;
231 type Err = IntRangeError;
232
233 fn try_mul (self, rhs: $ty) -> Result<$ty, IntRangeError> {
234 match self.checked_mul(rhs) {
235 None => {
236 if (self > 0) == (rhs > 0) {
237 Err(IntRangeError::Overflow)
238 } else {
239 Err(IntRangeError::Underflow)
240 }
241 },
242 Some(n) => Ok(n),
243 }
244 }
245 }
246 )* };
247}
248
249impl_try_mul_unsigned!(u8, u16, u32, u64, usize);
250impl_try_mul_signed!(i8, i16, i32, i64, isize);
251
252#[test]
253fn test_try_mul () {
254 assert_eq!(85u8.try_mul(3), Ok(255u8));
255 assert_eq!(64u8.try_mul(4), Err(IntOverflow));
256 assert_eq!(63i8.try_mul(2), Ok(126i8));
257 assert_eq!(64i8.try_mul(2), Err(IntRangeError::Overflow));
258 assert_eq!(64i8.try_mul(-2), Ok(-128i8));
259 assert_eq!(65i8.try_mul(-2), Err(IntRangeError::Underflow));
260 assert_eq!((-64i8).try_mul(2), Ok(-128i8));
261 assert_eq!((-65i8).try_mul(2), Err(IntRangeError::Underflow));
262 assert_eq!((-63i8).try_mul(-2), Ok(126i8));
263 assert_eq!((-64i8).try_mul(-2), Err(IntRangeError::Overflow));
264}
265
266pub trait TryDiv<RHS = Self> {
268 type Output;
269 type Err;
270
271 fn try_div (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
272}
273
274macro_rules! impl_try_div {
275 ($($ty:ty),*) => { $(
276 impl TryDiv for $ty {
277 type Output = $ty;
278 type Err = DivideByZero;
279
280 fn try_div (self, rhs: $ty) -> Result<$ty, DivideByZero> {
281 if rhs == 0 {
282 Err(DivideByZero)
283 } else {
284 Ok(self / rhs)
285 }
286 }
287 }
288 )* };
289}
290
291impl_try_div!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
292
293#[test]
294fn test_try_div () {
295 assert_eq!(255u8.try_div(3), Ok(85u8));
296 assert_eq!(255u8.try_div(0), Err(DivideByZero));
297}
298
299pub trait TryRem<RHS = Self> {
301 type Output;
302 type Err;
303
304 fn try_rem (self, rhs: RHS) -> Result<Self::Output, Self::Err>;
305}
306
307macro_rules! impl_try_rem {
308 ($($ty:ty),*) => { $(
309 impl TryRem for $ty {
310 type Output = $ty;
311 type Err = DivideByZero;
312
313 fn try_rem (self, rhs: $ty) -> Result<$ty, DivideByZero> {
314 if rhs == 0 {
315 Err(DivideByZero)
316 } else {
317 Ok(self % rhs)
318 }
319 }
320 }
321 )* };
322}
323
324impl_try_rem!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize);
325
326#[test]
327fn test_try_rem () {
328 assert_eq!(11u8.try_rem(5), Ok(1u8));
329 assert_eq!(11u8.try_rem(0), Err(DivideByZero));
330}
331
332pub trait TryNeg {
334 type Output;
335 type Err;
336
337 fn try_neg (self) -> Result<Self::Output, Self::Err>;
338}
339
340macro_rules! impl_try_neg {
341 ($($ty:ident),*) => { $(
342 impl TryNeg for $ty {
343 type Output = $ty;
344 type Err = IntOverflow;
345
346 fn try_neg (self) -> Result<$ty, IntOverflow> {
347 if self == $ty::MIN {
348 Err(IntOverflow)
349 } else {
350 Ok(-self)
351 }
352 }
353 }
354 )* };
355}
356
357impl_try_neg!(i8, i16, i32, i64, isize);
358
359#[test]
360fn test_try_neg () {
361 assert_eq!((-127i8).try_neg(), Ok(127i8));
362 assert_eq!((-128i8).try_neg(), Err(IntOverflow));
363}