1#![no_std]
45#![cfg_attr(docsrs, feature(doc_cfg))]
46#![warn(clippy::unwrap_in_result)]
47#![warn(rustdoc::all)]
48#![deny(unsafe_code)]
49#![warn(missing_docs)]
50#![warn(clippy::dbg_macro)]
51#![warn(clippy::cargo)]
52#![warn(clippy::perf)]
53#![warn(clippy::pedantic)]
54#![warn(clippy::all)]
55#![allow(rustdoc::missing_doc_code_examples)]
56
57use core::ops::{Add, Mul, MulAssign, Rem, Sub};
58
59#[allow(clippy::doc_markdown)]
60pub trait CheckedAdd: Add + Sized {
63 fn checked_add(self, rhs: Self) -> Option<Self>;
75}
76
77#[allow(clippy::doc_markdown)]
78pub trait CheckedSub: Sub + Sized {
81 fn checked_sub(self, rhs: Self) -> Option<Self>;
91}
92
93#[allow(clippy::doc_markdown)]
94pub trait CheckedMul: Mul + Sized {
97 fn checked_mul(self, rhs: Self) -> Option<Self>;
107}
108
109#[allow(clippy::doc_markdown)]
110pub trait CheckedPow: Sized {
113 fn checked_pow(self, exp: u32) -> Option<Self>;
115}
116
117macro_rules! checked_impl {
118 ($t:ty) => {
119 impl CheckedAdd for $t {
120 #[inline]
121 fn checked_add(self, rhs: Self) -> Option<Self> {
122 Self::checked_add(self, rhs)
123 }
124 }
125
126 impl CheckedSub for $t {
127 #[inline]
128 fn checked_sub(self, rhs: Self) -> Option<Self> {
129 Self::checked_sub(self, rhs)
130 }
131 }
132
133 impl CheckedMul for $t {
134 #[inline]
135 fn checked_mul(self, rhs: Self) -> Option<Self> {
136 Self::checked_mul(self, rhs)
137 }
138 }
139
140 impl CheckedPow for $t {
141 #[inline]
142 fn checked_pow(self, exp: u32) -> Option<Self> {
143 Self::checked_pow(self, exp)
144 }
145 }
146 };
147}
148
149checked_impl!(u8);
150checked_impl!(u16);
151checked_impl!(u32);
152checked_impl!(u64);
153checked_impl!(i8);
154checked_impl!(i16);
155checked_impl!(i32);
156checked_impl!(i64);
157
158pub trait Pow: Sized {
164 #[must_use]
166 fn pow(self, exp: u32) -> Self;
167}
168
169macro_rules! pow_impl {
170 ($t:ty) => {
171 impl Pow for $t {
172 #[inline]
173 fn pow(self, exp: u32) -> Self {
174 Self::pow(self, exp)
175 }
176 }
177 };
178}
179
180pow_impl!(u8);
181pow_impl!(u16);
182pow_impl!(u32);
183pow_impl!(u64);
184pow_impl!(u128);
185pow_impl!(i8);
186pow_impl!(i16);
187pow_impl!(i32);
188pow_impl!(i64);
189pow_impl!(i128);
190
191pub trait Upcast: Sized {
195 type Higher;
197
198 fn upcast(self) -> Self::Higher;
200 fn downcast(inp: Self::Higher) -> Option<Self>;
203}
204
205macro_rules! upcast_impl {
206 ($t:ty, $h:ty) => {
207 impl Upcast for $t {
208 type Higher = $h;
209
210 #[inline]
211 fn upcast(self) -> Self::Higher {
212 self.into()
213 }
214
215 #[inline]
216 fn downcast(inp: Self::Higher) -> Option<Self> {
217 inp.try_into().ok()
218 }
219 }
220 };
221}
222
223upcast_impl!(u8, u16);
224upcast_impl!(u16, u32);
225upcast_impl!(u32, u64);
226upcast_impl!(u64, u128);
227upcast_impl!(i8, i16);
228upcast_impl!(i16, i32);
229upcast_impl!(i32, i64);
230upcast_impl!(i64, i128);
231
232pub trait One {
234 const ONE: Self;
236}
237
238macro_rules! one_impl {
239 ($t:ty) => {
240 impl One for $t {
241 const ONE: Self = 1;
242 }
243 };
244}
245
246one_impl!(u8);
247one_impl!(u16);
248one_impl!(u32);
249one_impl!(u64);
250one_impl!(u128);
251one_impl!(i8);
252one_impl!(i16);
253one_impl!(i32);
254one_impl!(i64);
255one_impl!(i128);
256
257pub trait UpcastAdd<H: Add<Output = H> + Rem<Output = H>>:
259 Upcast<Higher = H> + CheckedAdd + Copy
260{
261 #[must_use]
275 #[inline]
276 fn upcast_add(self, rhs: Self) -> H {
277 self.checked_add(rhs)
278 .map_or_else(|| self.upcast() + rhs.upcast(), Upcast::upcast)
279 }
280
281 #[must_use]
294 #[inline]
295 fn upcast_add_mod(self, rhs: Self, modulo: Self) -> Self {
296 Self::downcast(Self::upcast_add(self, rhs).rem(modulo.upcast())).unwrap()
297 }
298}
299
300pub trait UpcastSub<H: Sub<Output = H> + Rem<Output = H>>:
302 Upcast<Higher = H> + CheckedSub + Copy
303{
304 #[must_use]
328 #[inline]
329 fn upcast_sub(self, rhs: Self) -> H {
330 self.checked_sub(rhs)
331 .map_or_else(|| self.upcast() - rhs.upcast(), Upcast::upcast)
332 }
333
334 #[must_use]
348 #[inline]
349 fn upcast_sub_mod(self, rhs: Self, modulo: Self) -> Self {
350 Self::downcast(Self::upcast_sub(self, rhs).rem(modulo.upcast())).unwrap()
351 }
352}
353
354pub trait UpcastMul<H: Mul<Output = H> + Rem<Output = H>>:
356 Upcast<Higher = H> + CheckedMul + Rem<Output = Self> + Copy
357{
358 #[must_use]
371 #[inline]
372 fn upcast_mul(self, rhs: Self) -> H {
373 self.checked_mul(rhs)
374 .map_or_else(|| self.upcast() * rhs.upcast(), Upcast::upcast)
375 }
376
377 #[must_use]
379 #[inline]
380 fn upcast_mul_mod(self, rhs: Self, modulo: Self) -> Self {
381 Self::downcast(Self::upcast_mul(self, rhs).rem(modulo.upcast())).unwrap()
382 }
383}
384
385pub trait UpcastPow<H>: Upcast<Higher = H> + CheckedPow + Copy + Rem<Output = Self>
392where
393 H: Pow + One + PartialOrd + Rem<Output = H> + MulAssign + Copy,
394{
395 #[must_use]
397 #[inline]
398 fn upcast_pow(self, exp: u32) -> H {
399 self.checked_pow(exp)
400 .map_or_else(|| self.upcast().pow(32), Upcast::upcast)
401 }
402
403 #[must_use]
408 #[inline]
409 fn upcast_pow_mod(self, mut exp: u32, modulo: Self) -> Self {
410 self.checked_pow(exp).map_or_else(
411 || {
412 let mut res: H = H::ONE;
413 let mut x_upcast = self.upcast();
414 while exp > 0 {
415 if exp % 2 == 1 {
416 res *= x_upcast;
417 }
418 exp >>= 1;
419 x_upcast *= x_upcast;
420 }
421 Self::downcast(res % modulo.upcast()).unwrap()
422 },
423 |e| e % modulo,
424 )
425 }
426}
427
428macro_rules! upcast_arith_impl {
429 ($t:ty, $h:ty) => {
430 impl UpcastAdd<$h> for $t {}
431 impl UpcastMul<$h> for $t {}
432 impl UpcastPow<$h> for $t {}
433 impl UpcastSub<$h> for $t {}
434 };
435}
436
437upcast_arith_impl!(u8, u16);
438upcast_arith_impl!(u16, u32);
439upcast_arith_impl!(u32, u64);
440upcast_arith_impl!(u64, u128);
441upcast_arith_impl!(i8, i16);
442upcast_arith_impl!(i16, i32);
443upcast_arith_impl!(i32, i64);
444upcast_arith_impl!(i64, i128);
445
446#[cfg(any(feature = "const", doc))]
448#[cfg_attr(docsrs, doc(cfg(feature = "const")))]
449#[allow(rustdoc::missing_doc_code_examples)]
450pub mod constant {
451 macro_rules! gen_upcast_arith {
452 ($t:ty, $h:ty, $i:ident, $o:ident, $m:ident, $e:tt, $d:meta, $mo:meta) => {
453 #[$d]
454 #[must_use]
455 pub const fn $i(lhs: $t, rhs: $t) -> $h {
456 match lhs.$m(rhs) {
457 Some(e) => e as $h,
458 None => (lhs as $h) $e (rhs as $h),
459 }
460 }
461
462 #[$mo]
463 #[must_use]
464 pub const fn $o(lhs: $t, rhs: $t, modulo: $t) -> $t {
465 match lhs.$m(rhs) {
466 Some(e) => e % modulo,
467 None => (((lhs as $h) $e (rhs as $h)) % (modulo as $h)) as $t,
468 }
469 }
470 };
471 }
472 macro_rules! gen_upcast_add_impl {
473 ($t:ty, $h:ty, $i:ident, $o:ident) => {
474 gen_upcast_arith!($t, $h, $i, $o, checked_add, +, doc = "const equivalent of [`UpcastAdd::upcast_add`](crate::UpcastAdd::upcast_add).", doc = "const equivalent of [`UpcastAdd::upcast_add_mod`](crate::UpcastAdd::upcast_add_mod).");
475 };
476 }
477 macro_rules! gen_upcast_sub_impl {
478 ($t:ty, $h:ty, $i:ident, $o:ident) => {
479 gen_upcast_arith!($t, $h, $i, $o, checked_sub, -, doc = "const equivalent of [`UpcastSub::upcast_sub`](crate::UpcastSub::upcast_sub).", doc = "const equivalent of [`UpcastSub::upcast_sub_mod`](crate::UpcastSub::upcast_sub_mod).");
480 };
481 }
482
483 macro_rules! gen_upcast_mul_impl {
484 ($t:ty, $h:ty, $i:ident, $o:ident) => {
485 gen_upcast_arith!($t, $h, $i, $o, checked_mul, *, doc = "const equivalent of [`UpcastMul::upcast_mul`](crate::UpcastMul::upcast_mul).", doc = "const equivalent of [`UpcastMul::upcast_mul_mod`](crate::UpcastMul::upcast_mul_mod).");
486 };
487 }
488
489 gen_upcast_add_impl!(u8, u16, upcast_add_u8, upcast_add_mod_u8);
490 gen_upcast_add_impl!(u16, u32, upcast_add_u16, upcast_add_mod_u16);
491 gen_upcast_add_impl!(u32, u64, upcast_add_u32, upcast_add_mod_u32);
492 gen_upcast_add_impl!(u64, u128, upcast_add_u64, upcast_add_mod_u64);
493 gen_upcast_add_impl!(i8, i16, upcast_add_i8, upcast_add_mod_i8);
494 gen_upcast_add_impl!(i16, i32, upcast_add_i16, upcast_add_mod_i16);
495 gen_upcast_add_impl!(i32, i64, upcast_add_i32, upcast_add_mod_i32);
496 gen_upcast_add_impl!(i64, i128, upcast_add_i64, upcast_add_mod_i64);
497
498 gen_upcast_sub_impl!(u8, u16, upcast_sub_u8, upcast_sub_mod_u8);
499 gen_upcast_sub_impl!(u16, u32, upcast_sub_u16, upcast_sub_mod_u16);
500 gen_upcast_sub_impl!(u32, u64, upcast_sub_u32, upcast_sub_mod_u32);
501 gen_upcast_sub_impl!(u64, u128, upcast_sub_u64, upcast_sub_mod_u64);
502 gen_upcast_sub_impl!(i8, i16, upcast_sub_i8, upcast_sub_mod_i8);
503 gen_upcast_sub_impl!(i16, i32, upcast_sub_i16, upcast_sub_mod_i16);
504 gen_upcast_sub_impl!(i32, i64, upcast_sub_i32, upcast_sub_mod_i32);
505 gen_upcast_sub_impl!(i64, i128, upcast_sub_i64, upcast_sub_mod_i64);
506
507 gen_upcast_mul_impl!(u8, u16, upcast_mul_u8, upcast_mul_mod_u8);
508 gen_upcast_mul_impl!(u16, u32, upcast_mul_u16, upcast_mul_mod_u16);
509 gen_upcast_mul_impl!(u32, u64, upcast_mul_u32, upcast_mul_mod_u32);
510 gen_upcast_mul_impl!(u64, u128, upcast_mul_u64, upcast_mul_mod_u64);
511 gen_upcast_mul_impl!(i8, i16, upcast_mul_i8, upcast_mul_mod_i8);
512 gen_upcast_mul_impl!(i16, i32, upcast_mul_i16, upcast_mul_mod_i16);
513 gen_upcast_mul_impl!(i32, i64, upcast_mul_i32, upcast_mul_mod_i32);
514 gen_upcast_mul_impl!(i64, i128, upcast_mul_i64, upcast_mul_mod_i64);
515}