1#![deny(missing_docs)]
26#![no_std]
27use core::fmt::Debug;
28
29macro_rules! _stringify_or_default {
30 (default: $default:tt; $val:ident) => (stringify!($val));
31 (default: $default:tt;) => ($default);
32}
33
34macro_rules! unwrap_num_ops {
35 ($($op:ident {
36 $(arg: $arg:ty,)?
37 res: $res:ty,
38 begin_doc: $begin_doc:literal,
39 basic_example: $basic_example:literal,
40 panic_example: $panic_example:literal,
41 $(example_type: $example_type:ident,)?
42 },)+ $(,)?) => (paste::paste! {$(
43 #[doc = $begin_doc]
44 #[doc = concat!(
47 "which offers equivalent methods for each primitive integer type (ex. [`",
48 _stringify_or_default!(default: "i32"; $($example_type)*),
49 "::strict_",
50 stringify!($op),
51 "`])."
52 )]
53 #[doc = $basic_example]
66 #[doc = $panic_example]
73 #[must_use = "this returns the result of the operation, without modifying the original"]
75 fn [<unwrap_ $op>](self, $(arg: $arg)*) -> $res;
76 )*});
77
78}
79
80
81pub unsafe trait UnwrapOverflowOps: Copy + Debug + Sized + sealed::Sealed {
96 unwrap_num_ops! {
97 add {
98 arg: Self,
99 res: Self,
100 begin_doc: "Strict integer addition. Computes `self + rhs`, panicking if overflow occurred.",
101 basic_example: "assert_eq!((i32::MAX - 2).unwrap_add(1), i32::MAX - 1);",
102 panic_example: "let _ = (i32::MAX - 2).unwrap_add(3);",
103 },
104 sub {
105 arg: Self,
106 res: Self,
107 begin_doc: "Strict integer subtraction. Computes `self - rhs`, panicking if overflow occurred.",
108 basic_example: "assert_eq!((i32::MIN + 2).unwrap_sub(1), i32::MIN + 1);",
109 panic_example: "let _ = (i32::MIN + 2).unwrap_sub(3);",
110 },
111 mul {
112 arg: Self,
113 res: Self,
114 begin_doc: "Strict integer multiplication. Computes `self * rhs`, panicking if overflow occurred.",
115 basic_example: "assert_eq!(i32::MAX.unwrap_mul(1), i32::MAX);",
116 panic_example: "let _ = i32::MAX.unwrap_mul(2);",
117 },
118 div {
119 arg: Self,
120 res: Self,
121 begin_doc: "Strict integer division. Computes `self / rhs`, panicking if overflow occurred.",
122 basic_example: "assert_eq!((i32::MIN + 1).unwrap_div(-1), 2147483647);",
123 panic_example: "let _ = i32::MIN.unwrap_div(-1);",
124 },
125 rem {
126 arg: Self,
127 res: Self,
128 begin_doc: "Strict integer remainder. Computes `self % rhs`, panicking if the division results in overflow.",
129 basic_example: "assert_eq!(5i32.unwrap_rem(2), 1);",
130 panic_example: "let _ = 5i32.unwrap_rem(0);",
131 },
132 shr {
133 arg: u32,
134 res: Self,
135 begin_doc: "Strict shift right. Computes `self >> rhs`, panicking `rhs` is larger than or equal to the number of bits in `self`.",
136 basic_example: "assert_eq!(0x10i32.unwrap_shr(4), 0x1);",
137 panic_example: "let _ = 0x10i32.unwrap_shr(128);",
138 },
139 shl {
140 arg: u32,
141 res: Self,
142 begin_doc: "Strict shift left. Computes self << rhs, panicking if `rhs` is larger than or equal to the number of bits in `self`.",
143 basic_example: "assert_eq!(0x1i32.unwrap_shl(4), 0x10);",
144 panic_example: "let _ = 0x1i32.unwrap_shl(129);",
145 },
146 pow {
147 arg: u32,
148 res: Self,
149 begin_doc: "Strict exponentiation. Computes `self.pow(exp)`, panicking if overflow occurred.",
150 basic_example: "assert_eq!(8i32.unwrap_pow(2), 64);",
151 panic_example: "let _ = i32::MAX.unwrap_pow(2);",
152 },
153 }
154}
155
156pub unsafe trait UnwrapOverflowOpsSigned: UnwrapOverflowOps {
173 type Unsigned: UnwrapOverflowOpsUnsigned;
175 unwrap_num_ops! {
176 add_unsigned {
177 arg: Self::Unsigned,
178 res: Self,
179 begin_doc: "Strict addition with an unsigned integer. Computes `self + rhs`, panicking if overflow occurred.",
180 basic_example: "assert_eq!(1i32.unwrap_add_unsigned(2), 3);",
181 panic_example: "let _ = 1u32.unwrap_add_signed(-2);",
182 },
183 sub_unsigned {
184 arg: Self::Unsigned,
185 res: Self,
186 begin_doc: "Strict subtraction with an unsigned integer. Computes `self - rhs`, panicking if overflow occurred.",
187 basic_example: "assert_eq!(1i32.unwrap_sub_unsigned(2), -1);",
188 panic_example: "let _ = (i32::MIN + 2).unwrap_sub_unsigned(3);",
189 },
190 neg {
191 res: Self,
192 begin_doc: "Strict negation. Computes `-self`, panicking if `self == MIN`.",
193 basic_example: "assert_eq!(5i32.unwrap_neg(), -5);",
194 panic_example: "let _ = i32::MIN.unwrap_neg();",
195 },
196 }
197}
198
199pub unsafe trait UnwrapOverflowOpsUnsigned: UnwrapOverflowOps {
217 type Signed: UnwrapOverflowOpsSigned;
219 unwrap_num_ops! {
220 add_signed {
221 arg: Self::Signed,
222 res: Self,
223 begin_doc: "Strict addition with a signed integer. Computes `self + rhs`, panicking if overflow occurred.",
224 basic_example: "assert_eq!(1u32.unwrap_add_signed(2), 3);",
225 panic_example: "let _ = 1u32.unwrap_add_signed(-2);",
226 example_type: u32,
227 },
228 }
229}
230macro_rules! common_methods_impl {
231 () => (common_methods_impl! {
232 add(Self) -> Self,
233 sub(Self) -> Self,
234 mul(Self) -> Self,
235 div(Self) -> Self,
236 rem(Self) -> Self,
237 shr(u32) -> Self,
238 shl(u32) -> Self,
239 pow(u32) -> Self,
240 });
241 ($($op:ident($arg:ty) -> $res:ty),+ $(,)?) => (paste::paste! {$(
242 #[inline]
243 #[track_caller]
244 fn [<unwrap_ $op>](self, other: $arg) -> $res {
245 match self.[<checked_ $op>](other) {
246 Some(res) => res,
247 None => overflow_ops::$op(),
248 }
249 }
250 )*});
251
252}
253macro_rules! impl_signed_ints {
254 ($($size:tt),+) => (paste::paste!{ $(
255 unsafe impl UnwrapOverflowOps for [<i $size>] {
256 common_methods_impl!();
257 }
258 unsafe impl UnwrapOverflowOpsSigned for [<i $size>] {
259 type Unsigned = [<u $size>];
260 common_methods_impl! {
261 add_unsigned(Self::Unsigned) -> Self,
262 sub_unsigned(Self::Unsigned) -> Self,
263 }
264
265 #[inline]
266 #[track_caller]
267 fn unwrap_neg(self) -> Self {
268 match self.checked_neg() {
269 Some(res) => res,
270 None => overflow_ops::neg(),
271 }
272 }
273 }
274 impl sealed::Sealed for [<i $size>] {}
275 )* });
276}
277impl_signed_ints!(8, 16, 32, 64, 128, size);
278macro_rules! impl_unsigned_ints {
279 ($($size:tt),+) => (paste::paste!{ $(
280 unsafe impl UnwrapOverflowOps for [<u $size>] {
281 common_methods_impl!();
282 }
283
284 unsafe impl UnwrapOverflowOpsUnsigned for [<u $size>] {
285 type Signed = [<i $size>];
286 common_methods_impl!(add_signed(Self::Signed) -> Self);
287 }
288 impl sealed::Sealed for [<u $size>] {}
289 )* })
290}
291impl_unsigned_ints!(8, 16, 32, 64, 128, size);
292
293mod sealed {
294 pub trait Sealed {}
295}
296
297mod overflow_ops {
302 macro_rules! overflow_panic_msg {
303 ($($op:ident => $name:literal),+ $(,)?) => {$(
304 #[cold]
305 #[track_caller]
306 pub fn $op() -> ! {
307 panic!(concat!("attempt to ", $name, " with overflow"))
308 }
309 )*};
310 }
311
312 overflow_panic_msg! {
313 add => "add",
314 sub => "subtract",
315 mul => "multiply",
316 div => "divide",
317 rem => "calculate the remainder",
318 neg => "negate",
319 shr => "shift right",
320 shl => "shift left",
321 pow => "take integer power",
322 }
323
324 pub use self::add as add_signed;
326 pub use self::add as add_unsigned;
327 pub use self::sub as sub_unsigned;
328}
329