ext_ops/
wrapping_ops.rs

1/*
2 * Copyright (c) 2023 Martin Mills <daggerbot@gmail.com>
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 */
8
9/// Addition operator which wraps around the type's boundaries in case of overflow or underflow.
10pub trait WrappingAdd<Rhs = Self> {
11    type Output;
12    fn wrapping_add(self, rhs: Rhs) -> Self::Output;
13}
14
15/// Multiplication operator which wraps around the type's boundaries in case of overflow or
16/// underflow.
17pub trait WrappingMul<Rhs = Self> {
18    type Output;
19    fn wrapping_mul(self, rhs: Rhs) -> Self::Output;
20}
21
22/// Negation operator which wraps around the type's boundaries in case of overflow or underflow.
23pub trait WrappingNeg {
24    type Output;
25    fn wrapping_neg(self) -> Self::Output;
26}
27
28/// Subtraction operator which wraps around the type's boundaries in case of overflow or underflow.
29pub trait WrappingSub<Rhs = Self> {
30    type Output;
31    fn wrapping_sub(self, rhs: Rhs) -> Self::Output;
32}
33
34//--------------------------------------------------------------------------------------------------
35
36/// Implements unary wrapping operators.
37macro_rules! impl_unary_ops {
38    { $(impl $trait:ident::$fn:ident for $ty:ident;)* } => { $(
39        impl $trait for $ty {
40            type Output = $ty;
41
42            fn $fn(self) -> $ty {
43                self.$fn()
44            }
45        }
46
47        impl<'a> $trait for &'a $ty {
48            type Output = $ty;
49
50            fn $fn(self) -> $ty {
51                $trait::$fn(*self)
52            }
53        }
54    )* };
55}
56
57/// Implements binary wrapping operators.
58macro_rules! impl_binary_ops {
59    { $(impl $trait:ident::$fn:ident for $ty:ident;)* } => { $(
60        impl $trait for $ty {
61            type Output = $ty;
62
63            fn $fn(self, rhs: $ty) -> $ty {
64                self.$fn(rhs)
65            }
66        }
67
68        impl<'a> $trait<$ty> for &'a $ty {
69            type Output = $ty;
70
71            fn $fn(self, rhs: $ty) -> $ty {
72                $trait::$fn(*self, rhs)
73            }
74        }
75
76        impl<'r> $trait<&'r $ty> for $ty {
77            type Output = $ty;
78
79            fn $fn(self, rhs: &'r $ty) -> $ty {
80                $trait::$fn(self, *rhs)
81            }
82        }
83
84        impl<'a, 'r> $trait<&'r $ty> for &'a $ty {
85            type Output = $ty;
86
87            fn $fn(self, rhs: &'r $ty) -> $ty {
88                $trait::$fn(*self, *rhs)
89            }
90        }
91    )* };
92}
93
94/// Implements operators for integer types.
95macro_rules! impl_int_ops {
96    ($($ty:ident),*) => { $(
97        impl_unary_ops! {
98            impl WrappingNeg::wrapping_neg for $ty;
99        }
100
101        impl_binary_ops! {
102            impl WrappingAdd::wrapping_add for $ty;
103            impl WrappingMul::wrapping_mul for $ty;
104            impl WrappingSub::wrapping_sub for $ty;
105        }
106    )* };
107}
108
109impl_int_ops!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize);
110
111//--------------------------------------------------------------------------------------------------
112
113#[test]
114fn test_wrapping_add() {
115    assert_eq!(WrappingAdd::wrapping_add(100i8, 27), 127);
116    assert_eq!(WrappingAdd::wrapping_add(100i8, 28), -128);
117    assert_eq!(WrappingAdd::wrapping_add(-100i8, -28), -128);
118    assert_eq!(WrappingAdd::wrapping_add(-100i8, -29), 127);
119    assert_eq!(WrappingAdd::wrapping_add(200u8, 55), 255);
120    assert_eq!(WrappingAdd::wrapping_add(200u8, 56), 0);
121}
122
123#[test]
124fn test_wrapping_mul() {
125    assert_eq!(WrappingMul::wrapping_mul(8i8, 15), 120);
126    assert_eq!(WrappingMul::wrapping_mul(8i8, 16), -128);
127    assert_eq!(WrappingMul::wrapping_mul(8i8, -16), -128);
128    assert_eq!(WrappingMul::wrapping_mul(3i8, -43), 127);
129    assert_eq!(WrappingMul::wrapping_mul(-1i8, -127), 127);
130    assert_eq!(WrappingMul::wrapping_mul(-1i8, -128), -128);
131    assert_eq!(WrappingMul::wrapping_mul(85u8, 3), 255);
132    assert_eq!(WrappingMul::wrapping_mul(16u8, 16), 0);
133}
134
135#[test]
136fn test_wrapping_neg() {
137    assert_eq!(WrappingNeg::wrapping_neg(127i8), -127);
138    assert_eq!(WrappingNeg::wrapping_neg(-127i8), 127);
139    assert_eq!(WrappingNeg::wrapping_neg(-128i8), -128);
140    assert_eq!(WrappingNeg::wrapping_neg(0u8), 0);
141    assert_eq!(WrappingNeg::wrapping_neg(1u8), 255);
142    assert_eq!(WrappingNeg::wrapping_neg(255u8), 1);
143}
144
145#[test]
146fn test_wrapping_sub() {
147    assert_eq!(WrappingSub::wrapping_sub(100i8, -27), 127);
148    assert_eq!(WrappingSub::wrapping_sub(100i8, -28), -128);
149    assert_eq!(WrappingSub::wrapping_sub(-100i8, 28), -128);
150    assert_eq!(WrappingSub::wrapping_sub(-100i8, 29), 127);
151    assert_eq!(WrappingSub::wrapping_sub(100u8, 100), 0);
152    assert_eq!(WrappingSub::wrapping_sub(100u8, 101), 255);
153}