xref: /aosp_15_r20/bootable/libbootloader/gbl/libsafemath/src/lib.rs (revision 5225e6b173e52d2efc6bcf950c27374fd72adabc)
1*5225e6b1SAndroid Build Coastguard Worker // Copyright (C) 2024 The Android Open Source Project
2*5225e6b1SAndroid Build Coastguard Worker //
3*5225e6b1SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*5225e6b1SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*5225e6b1SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*5225e6b1SAndroid Build Coastguard Worker //
7*5225e6b1SAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*5225e6b1SAndroid Build Coastguard Worker //
9*5225e6b1SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*5225e6b1SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*5225e6b1SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*5225e6b1SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*5225e6b1SAndroid Build Coastguard Worker // limitations under the License.
14*5225e6b1SAndroid Build Coastguard Worker 
15*5225e6b1SAndroid Build Coastguard Worker //! # safemath library
16*5225e6b1SAndroid Build Coastguard Worker //!
17*5225e6b1SAndroid Build Coastguard Worker //! This library provides an API to safely work with unsigned integers. At a high level, all math
18*5225e6b1SAndroid Build Coastguard Worker //! operations are checked by default rather than having to remember to call specific `checked_*`
19*5225e6b1SAndroid Build Coastguard Worker //! functions, so that the burden is on the programmer if they want to perform unchecked math
20*5225e6b1SAndroid Build Coastguard Worker //! rather than the other way around:
21*5225e6b1SAndroid Build Coastguard Worker //!
22*5225e6b1SAndroid Build Coastguard Worker //! ```
23*5225e6b1SAndroid Build Coastguard Worker //! use safemath::SafeNum;
24*5225e6b1SAndroid Build Coastguard Worker //!
25*5225e6b1SAndroid Build Coastguard Worker //! let safe = SafeNum::from(0);
26*5225e6b1SAndroid Build Coastguard Worker //! let result = safe - 1;
27*5225e6b1SAndroid Build Coastguard Worker //! assert!(u32::try_from(result).is_err());
28*5225e6b1SAndroid Build Coastguard Worker //!
29*5225e6b1SAndroid Build Coastguard Worker //! let safe_chain = (SafeNum::from(BIG_NUMBER) * HUGE_NUMBER) / MAYBE_ZERO;
30*5225e6b1SAndroid Build Coastguard Worker //! // If any operation would have caused an overflow or division by zero,
31*5225e6b1SAndroid Build Coastguard Worker //! // the number is flagged and the lexical location is specified for logging.
32*5225e6b1SAndroid Build Coastguard Worker //! if safe_chain.has_error() {
33*5225e6b1SAndroid Build Coastguard Worker //!     eprintln!("safe_chain error = {:#?}", safe_chain);
34*5225e6b1SAndroid Build Coastguard Worker //! }
35*5225e6b1SAndroid Build Coastguard Worker //! ```
36*5225e6b1SAndroid Build Coastguard Worker //!
37*5225e6b1SAndroid Build Coastguard Worker //! In addition to checked-by-default arithmetic, the API exposed here support
38*5225e6b1SAndroid Build Coastguard Worker //! more natural usage than the `checked_*` functions by allowing chaining
39*5225e6b1SAndroid Build Coastguard Worker //! of operations without having to check the result at each step.
40*5225e6b1SAndroid Build Coastguard Worker //! This is similar to how floating-point `NaN` works - you can continue to use the
41*5225e6b1SAndroid Build Coastguard Worker //! value, but continued operations will just propagate `NaN`.
42*5225e6b1SAndroid Build Coastguard Worker //!
43*5225e6b1SAndroid Build Coastguard Worker //! ## Supported Operations
44*5225e6b1SAndroid Build Coastguard Worker //!
45*5225e6b1SAndroid Build Coastguard Worker //! ### Arithmetic
46*5225e6b1SAndroid Build Coastguard Worker //! The basic arithmetic operations are supported:
47*5225e6b1SAndroid Build Coastguard Worker //! addition, subtraction, multiplication, division, and remainder.
48*5225e6b1SAndroid Build Coastguard Worker //! The right hand side may be another SafeNum or any integer,
49*5225e6b1SAndroid Build Coastguard Worker //! and the result is always another SafeNum.
50*5225e6b1SAndroid Build Coastguard Worker //! If the operation would result in an overflow or division by zero,
51*5225e6b1SAndroid Build Coastguard Worker //! or if converting the right hand element to a `u64` would cause an error,
52*5225e6b1SAndroid Build Coastguard Worker //! the result is an error-tagged SafeNum that tracks the lexical origin of the error.
53*5225e6b1SAndroid Build Coastguard Worker //!
54*5225e6b1SAndroid Build Coastguard Worker //! ### Conversion from and to SafeNum
55*5225e6b1SAndroid Build Coastguard Worker //! SafeNums support conversion to and from all integer types.
56*5225e6b1SAndroid Build Coastguard Worker //! Conversion to SafeNum from signed integers and from usize and u128
57*5225e6b1SAndroid Build Coastguard Worker //! can fail, generating an error value that is then propagated.
58*5225e6b1SAndroid Build Coastguard Worker //! Conversion from SafeNum to all integers is only exposed via `try_from`
59*5225e6b1SAndroid Build Coastguard Worker //! in order to force the user to handle potential resultant errors.
60*5225e6b1SAndroid Build Coastguard Worker //!
61*5225e6b1SAndroid Build Coastguard Worker //! E.g.
62*5225e6b1SAndroid Build Coastguard Worker //! ```
63*5225e6b1SAndroid Build Coastguard Worker //! fn call_func(_: u32, _: u32) {
64*5225e6b1SAndroid Build Coastguard Worker //! }
65*5225e6b1SAndroid Build Coastguard Worker //!
66*5225e6b1SAndroid Build Coastguard Worker //! fn do_a_thing(a: SafeNum) -> Result<(), safemath::Error> {
67*5225e6b1SAndroid Build Coastguard Worker //!     call_func(16, a.try_into()?);
68*5225e6b1SAndroid Build Coastguard Worker //!     Ok(())
69*5225e6b1SAndroid Build Coastguard Worker //! }
70*5225e6b1SAndroid Build Coastguard Worker //! ```
71*5225e6b1SAndroid Build Coastguard Worker //!
72*5225e6b1SAndroid Build Coastguard Worker //! ### Comparison
73*5225e6b1SAndroid Build Coastguard Worker //! SafeNums can be checked for equality against each other.
74*5225e6b1SAndroid Build Coastguard Worker //! Valid numbers are equal to other numbers of the same magnitude.
75*5225e6b1SAndroid Build Coastguard Worker //! Errored SafeNums are only equal to themselves.
76*5225e6b1SAndroid Build Coastguard Worker //! Note that because errors propagate from their first introduction in an
77*5225e6b1SAndroid Build Coastguard Worker //! arithmetic chain this can lead to surprising results.
78*5225e6b1SAndroid Build Coastguard Worker //!
79*5225e6b1SAndroid Build Coastguard Worker //! E.g.
80*5225e6b1SAndroid Build Coastguard Worker //! ```
81*5225e6b1SAndroid Build Coastguard Worker //! let overflow = SafeNum::MAX + 1;
82*5225e6b1SAndroid Build Coastguard Worker //! let otherflow = SafeNum::MAX + 1;
83*5225e6b1SAndroid Build Coastguard Worker //!
84*5225e6b1SAndroid Build Coastguard Worker //! assert_ne!(overflow, otherflow);
85*5225e6b1SAndroid Build Coastguard Worker //! assert_eq!(overflow + otherflow, overflow);
86*5225e6b1SAndroid Build Coastguard Worker //! assert_eq!(otherflow + overflow, otherflow);
87*5225e6b1SAndroid Build Coastguard Worker //! ```
88*5225e6b1SAndroid Build Coastguard Worker //!
89*5225e6b1SAndroid Build Coastguard Worker //! Inequality comparison operators are deliberately not provided.
90*5225e6b1SAndroid Build Coastguard Worker //! By necessity they would have similar caveats to floating point comparisons,
91*5225e6b1SAndroid Build Coastguard Worker //! which are easy to use incorrectly and unintuitive to use correctly.
92*5225e6b1SAndroid Build Coastguard Worker //!
93*5225e6b1SAndroid Build Coastguard Worker //! The required alternative is to convert to a real integer type before comparing,
94*5225e6b1SAndroid Build Coastguard Worker //! forcing any errors upwards.
95*5225e6b1SAndroid Build Coastguard Worker //!
96*5225e6b1SAndroid Build Coastguard Worker //! E.g.
97*5225e6b1SAndroid Build Coastguard Worker //! ```
98*5225e6b1SAndroid Build Coastguard Worker //! impl From<safemath::Error> for &'static str {
99*5225e6b1SAndroid Build Coastguard Worker //!     fn from(_: safemath::Error) -> Self {
100*5225e6b1SAndroid Build Coastguard Worker //!         "checked arithmetic error"
101*5225e6b1SAndroid Build Coastguard Worker //!     }
102*5225e6b1SAndroid Build Coastguard Worker //! }
103*5225e6b1SAndroid Build Coastguard Worker //!
104*5225e6b1SAndroid Build Coastguard Worker //! fn my_op(a: SafeNum, b: SafeNum, c: SafeNum, d: SafeNum) -> Result<bool, &'static str> {
105*5225e6b1SAndroid Build Coastguard Worker //!     Ok(safemath::Primitive::try_from(a)? < b.try_into()?
106*5225e6b1SAndroid Build Coastguard Worker //!        && safemath::Primitive::try_from(c)? >= d.try_into()?)
107*5225e6b1SAndroid Build Coastguard Worker //! }
108*5225e6b1SAndroid Build Coastguard Worker //! ```
109*5225e6b1SAndroid Build Coastguard Worker //!
110*5225e6b1SAndroid Build Coastguard Worker //! ### Miscellaneous
111*5225e6b1SAndroid Build Coastguard Worker //! SafeNums also provide helper methods to round up or down
112*5225e6b1SAndroid Build Coastguard Worker //! to the nearest multiple of another number
113*5225e6b1SAndroid Build Coastguard Worker //! and helper predicate methods that indicate whether the SafeNum
114*5225e6b1SAndroid Build Coastguard Worker //! is valid or is tracking an error.
115*5225e6b1SAndroid Build Coastguard Worker //!
116*5225e6b1SAndroid Build Coastguard Worker //! Also provided are constants `SafeNum::MAX`, `SafeNum::MIN`, and `SafeNum::ZERO`.
117*5225e6b1SAndroid Build Coastguard Worker //!
118*5225e6b1SAndroid Build Coastguard Worker //! Warning: SafeNums can help prevent, isolate, and detect arithmetic overflow
119*5225e6b1SAndroid Build Coastguard Worker //!          but they are not a panacea. In particular, chains of different operations
120*5225e6b1SAndroid Build Coastguard Worker //!          are not guaranteed to be associative or commutative.
121*5225e6b1SAndroid Build Coastguard Worker //!
122*5225e6b1SAndroid Build Coastguard Worker //! E.g.
123*5225e6b1SAndroid Build Coastguard Worker //! ```
124*5225e6b1SAndroid Build Coastguard Worker //! let a = SafeNum::MAX - 1 + 1;
125*5225e6b1SAndroid Build Coastguard Worker //! let b = SafeNum::MAX + 1 - 1;
126*5225e6b1SAndroid Build Coastguard Worker //! assert_ne!(a, b);
127*5225e6b1SAndroid Build Coastguard Worker //! assert!(a.is_valid());
128*5225e6b1SAndroid Build Coastguard Worker //! assert!(b.has_error());
129*5225e6b1SAndroid Build Coastguard Worker //!
130*5225e6b1SAndroid Build Coastguard Worker //! let c = (SafeNum::MAX + 31) / 31;
131*5225e6b1SAndroid Build Coastguard Worker //! let d = SafeNum::MAX / 31 + 31 / 31;
132*5225e6b1SAndroid Build Coastguard Worker //! assert_ne!(c, d);
133*5225e6b1SAndroid Build Coastguard Worker //! assert!(c.has_error());
134*5225e6b1SAndroid Build Coastguard Worker //! assert!(d.is_valid());
135*5225e6b1SAndroid Build Coastguard Worker //! ```
136*5225e6b1SAndroid Build Coastguard Worker //!
137*5225e6b1SAndroid Build Coastguard Worker //! Note:    SafeNum arithmetic is much slower than arithmetic on integer primitives.
138*5225e6b1SAndroid Build Coastguard Worker //!          If you are concerned about performance, be sure to run benchmarks.
139*5225e6b1SAndroid Build Coastguard Worker 
140*5225e6b1SAndroid Build Coastguard Worker #![cfg_attr(not(test), no_std)]
141*5225e6b1SAndroid Build Coastguard Worker 
142*5225e6b1SAndroid Build Coastguard Worker use core::convert::TryFrom;
143*5225e6b1SAndroid Build Coastguard Worker use core::fmt;
144*5225e6b1SAndroid Build Coastguard Worker use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Rem, RemAssign, Sub, SubAssign};
145*5225e6b1SAndroid Build Coastguard Worker use core::panic::Location;
146*5225e6b1SAndroid Build Coastguard Worker 
147*5225e6b1SAndroid Build Coastguard Worker /// The underlying primitive type used for [SafeNum] operations.
148*5225e6b1SAndroid Build Coastguard Worker pub type Primitive = u64;
149*5225e6b1SAndroid Build Coastguard Worker /// Safe math error type, which points to the location of the original failed operation.
150*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
151*5225e6b1SAndroid Build Coastguard Worker pub struct Error(&'static Location<'static>);
152*5225e6b1SAndroid Build Coastguard Worker 
153*5225e6b1SAndroid Build Coastguard Worker impl From<&'static Location<'static>> for Error {
from(loc: &'static Location<'static>) -> Self154*5225e6b1SAndroid Build Coastguard Worker     fn from(loc: &'static Location<'static>) -> Self {
155*5225e6b1SAndroid Build Coastguard Worker         Self(loc)
156*5225e6b1SAndroid Build Coastguard Worker     }
157*5225e6b1SAndroid Build Coastguard Worker }
158*5225e6b1SAndroid Build Coastguard Worker 
159*5225e6b1SAndroid Build Coastguard Worker impl From<Error> for &'static Location<'static> {
from(err: Error) -> Self160*5225e6b1SAndroid Build Coastguard Worker     fn from(err: Error) -> Self {
161*5225e6b1SAndroid Build Coastguard Worker         err.0
162*5225e6b1SAndroid Build Coastguard Worker     }
163*5225e6b1SAndroid Build Coastguard Worker }
164*5225e6b1SAndroid Build Coastguard Worker 
165*5225e6b1SAndroid Build Coastguard Worker impl From<core::num::TryFromIntError> for Error {
166*5225e6b1SAndroid Build Coastguard Worker     #[track_caller]
from(_err: core::num::TryFromIntError) -> Self167*5225e6b1SAndroid Build Coastguard Worker     fn from(_err: core::num::TryFromIntError) -> Self {
168*5225e6b1SAndroid Build Coastguard Worker         Self(Location::caller())
169*5225e6b1SAndroid Build Coastguard Worker     }
170*5225e6b1SAndroid Build Coastguard Worker }
171*5225e6b1SAndroid Build Coastguard Worker 
172*5225e6b1SAndroid Build Coastguard Worker /// Wraps a raw [Primitive] type for safe-by-default math. See module docs for info and usage.
173*5225e6b1SAndroid Build Coastguard Worker #[derive(Copy, Clone, PartialEq, Eq)]
174*5225e6b1SAndroid Build Coastguard Worker pub struct SafeNum(Result<Primitive, Error>);
175*5225e6b1SAndroid Build Coastguard Worker 
176*5225e6b1SAndroid Build Coastguard Worker impl fmt::Debug for SafeNum {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result177*5225e6b1SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
178*5225e6b1SAndroid Build Coastguard Worker         match self.0 {
179*5225e6b1SAndroid Build Coastguard Worker             Ok(val) => write!(f, "{}", val),
180*5225e6b1SAndroid Build Coastguard Worker             Err(location) => write!(f, "error at {}", location),
181*5225e6b1SAndroid Build Coastguard Worker         }
182*5225e6b1SAndroid Build Coastguard Worker     }
183*5225e6b1SAndroid Build Coastguard Worker }
184*5225e6b1SAndroid Build Coastguard Worker 
185*5225e6b1SAndroid Build Coastguard Worker impl fmt::Display for Error {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result186*5225e6b1SAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187*5225e6b1SAndroid Build Coastguard Worker         self.0.fmt(f)
188*5225e6b1SAndroid Build Coastguard Worker     }
189*5225e6b1SAndroid Build Coastguard Worker }
190*5225e6b1SAndroid Build Coastguard Worker 
191*5225e6b1SAndroid Build Coastguard Worker impl SafeNum {
192*5225e6b1SAndroid Build Coastguard Worker     /// The maximum [SafeNum].
193*5225e6b1SAndroid Build Coastguard Worker     pub const MAX: SafeNum = SafeNum(Ok(u64::MAX));
194*5225e6b1SAndroid Build Coastguard Worker     /// The minimum [SafeNum].
195*5225e6b1SAndroid Build Coastguard Worker     pub const MIN: SafeNum = SafeNum(Ok(u64::MIN));
196*5225e6b1SAndroid Build Coastguard Worker     /// Zero as a [SafeNum].
197*5225e6b1SAndroid Build Coastguard Worker     pub const ZERO: SafeNum = SafeNum(Ok(0));
198*5225e6b1SAndroid Build Coastguard Worker 
199*5225e6b1SAndroid Build Coastguard Worker     /// Round `self` down to the nearest multiple of `rhs`.
200*5225e6b1SAndroid Build Coastguard Worker     #[track_caller]
round_down<T>(self, rhs: T) -> Self where Self: Rem<T, Output = Self>,201*5225e6b1SAndroid Build Coastguard Worker     pub fn round_down<T>(self, rhs: T) -> Self
202*5225e6b1SAndroid Build Coastguard Worker     where
203*5225e6b1SAndroid Build Coastguard Worker         Self: Rem<T, Output = Self>,
204*5225e6b1SAndroid Build Coastguard Worker     {
205*5225e6b1SAndroid Build Coastguard Worker         self - (self % rhs)
206*5225e6b1SAndroid Build Coastguard Worker     }
207*5225e6b1SAndroid Build Coastguard Worker 
208*5225e6b1SAndroid Build Coastguard Worker     /// Round `self` up to the nearest multiple of `rhs`.
209*5225e6b1SAndroid Build Coastguard Worker     #[track_caller]
round_up<T>(self, rhs: T) -> Self where Self: Add<T, Output = Self>, T: Copy + Into<Self>,210*5225e6b1SAndroid Build Coastguard Worker     pub fn round_up<T>(self, rhs: T) -> Self
211*5225e6b1SAndroid Build Coastguard Worker     where
212*5225e6b1SAndroid Build Coastguard Worker         Self: Add<T, Output = Self>,
213*5225e6b1SAndroid Build Coastguard Worker         T: Copy + Into<Self>,
214*5225e6b1SAndroid Build Coastguard Worker     {
215*5225e6b1SAndroid Build Coastguard Worker         ((self + rhs) - 1).round_down(rhs)
216*5225e6b1SAndroid Build Coastguard Worker     }
217*5225e6b1SAndroid Build Coastguard Worker 
218*5225e6b1SAndroid Build Coastguard Worker     /// Returns whether self is the result of an operation that has errored.
has_error(&self) -> bool219*5225e6b1SAndroid Build Coastguard Worker     pub const fn has_error(&self) -> bool {
220*5225e6b1SAndroid Build Coastguard Worker         self.0.is_err()
221*5225e6b1SAndroid Build Coastguard Worker     }
222*5225e6b1SAndroid Build Coastguard Worker 
223*5225e6b1SAndroid Build Coastguard Worker     /// Returns whether self represents a valid, non-overflowed integer.
is_valid(&self) -> bool224*5225e6b1SAndroid Build Coastguard Worker     pub const fn is_valid(&self) -> bool {
225*5225e6b1SAndroid Build Coastguard Worker         self.0.is_ok()
226*5225e6b1SAndroid Build Coastguard Worker     }
227*5225e6b1SAndroid Build Coastguard Worker }
228*5225e6b1SAndroid Build Coastguard Worker 
229*5225e6b1SAndroid Build Coastguard Worker macro_rules! try_conversion_func {
230*5225e6b1SAndroid Build Coastguard Worker     ($other_type:tt) => {
231*5225e6b1SAndroid Build Coastguard Worker         impl TryFrom<SafeNum> for $other_type {
232*5225e6b1SAndroid Build Coastguard Worker             type Error = Error;
233*5225e6b1SAndroid Build Coastguard Worker 
234*5225e6b1SAndroid Build Coastguard Worker             #[track_caller]
235*5225e6b1SAndroid Build Coastguard Worker             fn try_from(val: SafeNum) -> Result<Self, Self::Error> {
236*5225e6b1SAndroid Build Coastguard Worker                 Self::try_from(val.0?).map_err(|_| Location::caller().into())
237*5225e6b1SAndroid Build Coastguard Worker             }
238*5225e6b1SAndroid Build Coastguard Worker         }
239*5225e6b1SAndroid Build Coastguard Worker     };
240*5225e6b1SAndroid Build Coastguard Worker }
241*5225e6b1SAndroid Build Coastguard Worker 
242*5225e6b1SAndroid Build Coastguard Worker macro_rules! conversion_func {
243*5225e6b1SAndroid Build Coastguard Worker     ($from_type:tt) => {
244*5225e6b1SAndroid Build Coastguard Worker         impl From<$from_type> for SafeNum {
245*5225e6b1SAndroid Build Coastguard Worker             fn from(val: $from_type) -> SafeNum {
246*5225e6b1SAndroid Build Coastguard Worker                 Self(Ok(val.into()))
247*5225e6b1SAndroid Build Coastguard Worker             }
248*5225e6b1SAndroid Build Coastguard Worker         }
249*5225e6b1SAndroid Build Coastguard Worker 
250*5225e6b1SAndroid Build Coastguard Worker         try_conversion_func!($from_type);
251*5225e6b1SAndroid Build Coastguard Worker     };
252*5225e6b1SAndroid Build Coastguard Worker }
253*5225e6b1SAndroid Build Coastguard Worker 
254*5225e6b1SAndroid Build Coastguard Worker macro_rules! conversion_func_maybe_error {
255*5225e6b1SAndroid Build Coastguard Worker     ($from_type:tt) => {
256*5225e6b1SAndroid Build Coastguard Worker         impl From<$from_type> for SafeNum {
257*5225e6b1SAndroid Build Coastguard Worker             #[track_caller]
258*5225e6b1SAndroid Build Coastguard Worker             fn from(val: $from_type) -> Self {
259*5225e6b1SAndroid Build Coastguard Worker                 Self(Primitive::try_from(val).map_err(|_| Location::caller().into()))
260*5225e6b1SAndroid Build Coastguard Worker             }
261*5225e6b1SAndroid Build Coastguard Worker         }
262*5225e6b1SAndroid Build Coastguard Worker 
263*5225e6b1SAndroid Build Coastguard Worker         try_conversion_func!($from_type);
264*5225e6b1SAndroid Build Coastguard Worker     };
265*5225e6b1SAndroid Build Coastguard Worker }
266*5225e6b1SAndroid Build Coastguard Worker 
267*5225e6b1SAndroid Build Coastguard Worker macro_rules! arithmetic_impl {
268*5225e6b1SAndroid Build Coastguard Worker     ($trait_name:ident, $op:ident, $assign_trait_name:ident, $assign_op:ident, $func:ident) => {
269*5225e6b1SAndroid Build Coastguard Worker         impl<T: Into<SafeNum>> $trait_name<T> for SafeNum {
270*5225e6b1SAndroid Build Coastguard Worker             type Output = Self;
271*5225e6b1SAndroid Build Coastguard Worker             #[track_caller]
272*5225e6b1SAndroid Build Coastguard Worker             fn $op(self, rhs: T) -> Self {
273*5225e6b1SAndroid Build Coastguard Worker                 let rhs: Self = rhs.into();
274*5225e6b1SAndroid Build Coastguard Worker 
275*5225e6b1SAndroid Build Coastguard Worker                 match (self.0, rhs.0) {
276*5225e6b1SAndroid Build Coastguard Worker                     (Err(_), _) => self,
277*5225e6b1SAndroid Build Coastguard Worker                     (_, Err(_)) => rhs,
278*5225e6b1SAndroid Build Coastguard Worker                     (Ok(lhs), Ok(rhs)) => {
279*5225e6b1SAndroid Build Coastguard Worker                         Self(lhs.$func(rhs).ok_or_else(|| Location::caller().into()))
280*5225e6b1SAndroid Build Coastguard Worker                     }
281*5225e6b1SAndroid Build Coastguard Worker                 }
282*5225e6b1SAndroid Build Coastguard Worker             }
283*5225e6b1SAndroid Build Coastguard Worker         }
284*5225e6b1SAndroid Build Coastguard Worker 
285*5225e6b1SAndroid Build Coastguard Worker         impl<T> $assign_trait_name<T> for SafeNum
286*5225e6b1SAndroid Build Coastguard Worker         where
287*5225e6b1SAndroid Build Coastguard Worker             Self: $trait_name<T, Output = Self>,
288*5225e6b1SAndroid Build Coastguard Worker         {
289*5225e6b1SAndroid Build Coastguard Worker             #[track_caller]
290*5225e6b1SAndroid Build Coastguard Worker             fn $assign_op(&mut self, rhs: T) {
291*5225e6b1SAndroid Build Coastguard Worker                 *self = self.$op(rhs)
292*5225e6b1SAndroid Build Coastguard Worker             }
293*5225e6b1SAndroid Build Coastguard Worker         }
294*5225e6b1SAndroid Build Coastguard Worker     };
295*5225e6b1SAndroid Build Coastguard Worker }
296*5225e6b1SAndroid Build Coastguard Worker 
297*5225e6b1SAndroid Build Coastguard Worker conversion_func!(u8);
298*5225e6b1SAndroid Build Coastguard Worker conversion_func!(u16);
299*5225e6b1SAndroid Build Coastguard Worker conversion_func!(u32);
300*5225e6b1SAndroid Build Coastguard Worker conversion_func!(u64);
301*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(usize);
302*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(u128);
303*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(i8);
304*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(i16);
305*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(i32);
306*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(i64);
307*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(i128);
308*5225e6b1SAndroid Build Coastguard Worker conversion_func_maybe_error!(isize);
309*5225e6b1SAndroid Build Coastguard Worker arithmetic_impl!(Add, add, AddAssign, add_assign, checked_add);
310*5225e6b1SAndroid Build Coastguard Worker arithmetic_impl!(Sub, sub, SubAssign, sub_assign, checked_sub);
311*5225e6b1SAndroid Build Coastguard Worker arithmetic_impl!(Mul, mul, MulAssign, mul_assign, checked_mul);
312*5225e6b1SAndroid Build Coastguard Worker arithmetic_impl!(Div, div, DivAssign, div_assign, checked_div);
313*5225e6b1SAndroid Build Coastguard Worker arithmetic_impl!(Rem, rem, RemAssign, rem_assign, checked_rem);
314*5225e6b1SAndroid Build Coastguard Worker 
315*5225e6b1SAndroid Build Coastguard Worker #[cfg(test)]
316*5225e6b1SAndroid Build Coastguard Worker mod test {
317*5225e6b1SAndroid Build Coastguard Worker     use super::*;
318*5225e6b1SAndroid Build Coastguard Worker 
319*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_addition()320*5225e6b1SAndroid Build Coastguard Worker     fn test_addition() {
321*5225e6b1SAndroid Build Coastguard Worker         let a: SafeNum = 2100.into();
322*5225e6b1SAndroid Build Coastguard Worker         let b: SafeNum = 12.into();
323*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a + b, 2112.into());
324*5225e6b1SAndroid Build Coastguard Worker     }
325*5225e6b1SAndroid Build Coastguard Worker 
326*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_subtraction()327*5225e6b1SAndroid Build Coastguard Worker     fn test_subtraction() {
328*5225e6b1SAndroid Build Coastguard Worker         let a: SafeNum = 667.into();
329*5225e6b1SAndroid Build Coastguard Worker         let b: SafeNum = 1.into();
330*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a - b, 666.into());
331*5225e6b1SAndroid Build Coastguard Worker     }
332*5225e6b1SAndroid Build Coastguard Worker 
333*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_multiplication()334*5225e6b1SAndroid Build Coastguard Worker     fn test_multiplication() {
335*5225e6b1SAndroid Build Coastguard Worker         let a: SafeNum = 17.into();
336*5225e6b1SAndroid Build Coastguard Worker         let b: SafeNum = 3.into();
337*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a * b, 51.into());
338*5225e6b1SAndroid Build Coastguard Worker     }
339*5225e6b1SAndroid Build Coastguard Worker 
340*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_division()341*5225e6b1SAndroid Build Coastguard Worker     fn test_division() {
342*5225e6b1SAndroid Build Coastguard Worker         let a: SafeNum = 1066.into();
343*5225e6b1SAndroid Build Coastguard Worker         let b: SafeNum = 41.into();
344*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a / b, 26.into());
345*5225e6b1SAndroid Build Coastguard Worker     }
346*5225e6b1SAndroid Build Coastguard Worker 
347*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_remainder()348*5225e6b1SAndroid Build Coastguard Worker     fn test_remainder() {
349*5225e6b1SAndroid Build Coastguard Worker         let a: SafeNum = 613.into();
350*5225e6b1SAndroid Build Coastguard Worker         let b: SafeNum = 10.into();
351*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a % b, 3.into());
352*5225e6b1SAndroid Build Coastguard Worker     }
353*5225e6b1SAndroid Build Coastguard Worker 
354*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_addition_poison()355*5225e6b1SAndroid Build Coastguard Worker     fn test_addition_poison() {
356*5225e6b1SAndroid Build Coastguard Worker         let base: SafeNum = 2.into();
357*5225e6b1SAndroid Build Coastguard Worker         let poison = base + SafeNum::MAX;
358*5225e6b1SAndroid Build Coastguard Worker         assert!(u64::try_from(poison).is_err());
359*5225e6b1SAndroid Build Coastguard Worker 
360*5225e6b1SAndroid Build Coastguard Worker         let a = poison - 1;
361*5225e6b1SAndroid Build Coastguard Worker         let b = poison - 2;
362*5225e6b1SAndroid Build Coastguard Worker 
363*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a, poison);
364*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(b, poison);
365*5225e6b1SAndroid Build Coastguard Worker     }
366*5225e6b1SAndroid Build Coastguard Worker 
367*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_subtraction_poison()368*5225e6b1SAndroid Build Coastguard Worker     fn test_subtraction_poison() {
369*5225e6b1SAndroid Build Coastguard Worker         let base: SafeNum = 2.into();
370*5225e6b1SAndroid Build Coastguard Worker         let poison = base - SafeNum::MAX;
371*5225e6b1SAndroid Build Coastguard Worker         assert!(u64::try_from(poison).is_err());
372*5225e6b1SAndroid Build Coastguard Worker 
373*5225e6b1SAndroid Build Coastguard Worker         let a = poison + 1;
374*5225e6b1SAndroid Build Coastguard Worker         let b = poison + 2;
375*5225e6b1SAndroid Build Coastguard Worker 
376*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a, poison);
377*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(b, poison);
378*5225e6b1SAndroid Build Coastguard Worker     }
379*5225e6b1SAndroid Build Coastguard Worker 
380*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_multiplication_poison()381*5225e6b1SAndroid Build Coastguard Worker     fn test_multiplication_poison() {
382*5225e6b1SAndroid Build Coastguard Worker         let base: SafeNum = 2.into();
383*5225e6b1SAndroid Build Coastguard Worker         let poison = base * SafeNum::MAX;
384*5225e6b1SAndroid Build Coastguard Worker         assert!(u64::try_from(poison).is_err());
385*5225e6b1SAndroid Build Coastguard Worker 
386*5225e6b1SAndroid Build Coastguard Worker         let a = poison / 2;
387*5225e6b1SAndroid Build Coastguard Worker         let b = poison / 4;
388*5225e6b1SAndroid Build Coastguard Worker 
389*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a, poison);
390*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(b, poison);
391*5225e6b1SAndroid Build Coastguard Worker     }
392*5225e6b1SAndroid Build Coastguard Worker 
393*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_division_poison()394*5225e6b1SAndroid Build Coastguard Worker     fn test_division_poison() {
395*5225e6b1SAndroid Build Coastguard Worker         let base: SafeNum = 2.into();
396*5225e6b1SAndroid Build Coastguard Worker         let poison = base / 0;
397*5225e6b1SAndroid Build Coastguard Worker         assert!(u64::try_from(poison).is_err());
398*5225e6b1SAndroid Build Coastguard Worker 
399*5225e6b1SAndroid Build Coastguard Worker         let a = poison * 2;
400*5225e6b1SAndroid Build Coastguard Worker         let b = poison * 4;
401*5225e6b1SAndroid Build Coastguard Worker 
402*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a, poison);
403*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(b, poison);
404*5225e6b1SAndroid Build Coastguard Worker     }
405*5225e6b1SAndroid Build Coastguard Worker 
406*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_remainder_poison()407*5225e6b1SAndroid Build Coastguard Worker     fn test_remainder_poison() {
408*5225e6b1SAndroid Build Coastguard Worker         let base: SafeNum = 2.into();
409*5225e6b1SAndroid Build Coastguard Worker         let poison = base % 0;
410*5225e6b1SAndroid Build Coastguard Worker         assert!(u64::try_from(poison).is_err());
411*5225e6b1SAndroid Build Coastguard Worker 
412*5225e6b1SAndroid Build Coastguard Worker         let a = poison * 2;
413*5225e6b1SAndroid Build Coastguard Worker         let b = poison * 4;
414*5225e6b1SAndroid Build Coastguard Worker 
415*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(a, poison);
416*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(b, poison);
417*5225e6b1SAndroid Build Coastguard Worker     }
418*5225e6b1SAndroid Build Coastguard Worker 
419*5225e6b1SAndroid Build Coastguard Worker     macro_rules! conversion_test {
420*5225e6b1SAndroid Build Coastguard Worker         ($name:ident) => {
421*5225e6b1SAndroid Build Coastguard Worker             mod $name {
422*5225e6b1SAndroid Build Coastguard Worker                 use super::*;
423*5225e6b1SAndroid Build Coastguard Worker                 use core::convert::TryInto;
424*5225e6b1SAndroid Build Coastguard Worker 
425*5225e6b1SAndroid Build Coastguard Worker                 #[test]
426*5225e6b1SAndroid Build Coastguard Worker                 fn test_between_safenum() {
427*5225e6b1SAndroid Build Coastguard Worker                     let var: $name = 16;
428*5225e6b1SAndroid Build Coastguard Worker                     let sn: SafeNum = var.into();
429*5225e6b1SAndroid Build Coastguard Worker                     let res: $name = sn.try_into().unwrap();
430*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!(var, res);
431*5225e6b1SAndroid Build Coastguard Worker                 }
432*5225e6b1SAndroid Build Coastguard Worker 
433*5225e6b1SAndroid Build Coastguard Worker                 #[test]
434*5225e6b1SAndroid Build Coastguard Worker                 fn test_arithmetic_safenum() {
435*5225e6b1SAndroid Build Coastguard Worker                     let primitive: $name = ((((0 + 11) * 11) / 3) % 32) - 3;
436*5225e6b1SAndroid Build Coastguard Worker                     let safe = ((((SafeNum::ZERO + $name::try_from(11u8).unwrap())
437*5225e6b1SAndroid Build Coastguard Worker                         * $name::try_from(11u8).unwrap())
438*5225e6b1SAndroid Build Coastguard Worker                         / $name::try_from(3u8).unwrap())
439*5225e6b1SAndroid Build Coastguard Worker                         % $name::try_from(32u8).unwrap())
440*5225e6b1SAndroid Build Coastguard Worker                         - $name::try_from(3u8).unwrap();
441*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!($name::try_from(safe).unwrap(), primitive);
442*5225e6b1SAndroid Build Coastguard Worker                 }
443*5225e6b1SAndroid Build Coastguard Worker             }
444*5225e6b1SAndroid Build Coastguard Worker         };
445*5225e6b1SAndroid Build Coastguard Worker     }
446*5225e6b1SAndroid Build Coastguard Worker 
447*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(u8);
448*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(u16);
449*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(u32);
450*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(u64);
451*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(u128);
452*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(usize);
453*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(i8);
454*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(i16);
455*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(i32);
456*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(i64);
457*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(i128);
458*5225e6b1SAndroid Build Coastguard Worker     conversion_test!(isize);
459*5225e6b1SAndroid Build Coastguard Worker 
460*5225e6b1SAndroid Build Coastguard Worker     macro_rules! correctness_tests {
461*5225e6b1SAndroid Build Coastguard Worker         ($name:ident, $operation:ident, $assign_operation:ident) => {
462*5225e6b1SAndroid Build Coastguard Worker             mod $operation {
463*5225e6b1SAndroid Build Coastguard Worker                 use super::*;
464*5225e6b1SAndroid Build Coastguard Worker                 use core::ops::$name;
465*5225e6b1SAndroid Build Coastguard Worker 
466*5225e6b1SAndroid Build Coastguard Worker                 #[test]
467*5225e6b1SAndroid Build Coastguard Worker                 fn test_correctness() {
468*5225e6b1SAndroid Build Coastguard Worker                     let normal = 300u64;
469*5225e6b1SAndroid Build Coastguard Worker                     let safe: SafeNum = normal.into();
470*5225e6b1SAndroid Build Coastguard Worker                     let rhs = 7u64;
471*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!(
472*5225e6b1SAndroid Build Coastguard Worker                         u64::try_from(safe.$operation(rhs)).unwrap(),
473*5225e6b1SAndroid Build Coastguard Worker                         normal.$operation(rhs)
474*5225e6b1SAndroid Build Coastguard Worker                     );
475*5225e6b1SAndroid Build Coastguard Worker                 }
476*5225e6b1SAndroid Build Coastguard Worker 
477*5225e6b1SAndroid Build Coastguard Worker                 #[test]
478*5225e6b1SAndroid Build Coastguard Worker                 fn test_assign() {
479*5225e6b1SAndroid Build Coastguard Worker                     let mut var: SafeNum = 2112.into();
480*5225e6b1SAndroid Build Coastguard Worker                     let rhs = 666u64;
481*5225e6b1SAndroid Build Coastguard Worker                     let expect = var.$operation(rhs);
482*5225e6b1SAndroid Build Coastguard Worker                     var.$assign_operation(rhs);
483*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!(var, expect);
484*5225e6b1SAndroid Build Coastguard Worker                 }
485*5225e6b1SAndroid Build Coastguard Worker 
486*5225e6b1SAndroid Build Coastguard Worker                 #[test]
487*5225e6b1SAndroid Build Coastguard Worker                 fn test_assign_poison() {
488*5225e6b1SAndroid Build Coastguard Worker                     let mut var = SafeNum::MIN - 1;
489*5225e6b1SAndroid Build Coastguard Worker                     let expected = var - 1;
490*5225e6b1SAndroid Build Coastguard Worker                     var.$assign_operation(2);
491*5225e6b1SAndroid Build Coastguard Worker                     // Poison saturates and doesn't perform additional changes
492*5225e6b1SAndroid Build Coastguard Worker                     assert_eq!(var, expected);
493*5225e6b1SAndroid Build Coastguard Worker                 }
494*5225e6b1SAndroid Build Coastguard Worker             }
495*5225e6b1SAndroid Build Coastguard Worker         };
496*5225e6b1SAndroid Build Coastguard Worker     }
497*5225e6b1SAndroid Build Coastguard Worker 
498*5225e6b1SAndroid Build Coastguard Worker     correctness_tests!(Add, add, add_assign);
499*5225e6b1SAndroid Build Coastguard Worker     correctness_tests!(Sub, sub, sub_assign);
500*5225e6b1SAndroid Build Coastguard Worker     correctness_tests!(Mul, mul, mul_assign);
501*5225e6b1SAndroid Build Coastguard Worker     correctness_tests!(Div, div, div_assign);
502*5225e6b1SAndroid Build Coastguard Worker     correctness_tests!(Rem, rem, rem_assign);
503*5225e6b1SAndroid Build Coastguard Worker 
504*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_round_down()505*5225e6b1SAndroid Build Coastguard Worker     fn test_round_down() {
506*5225e6b1SAndroid Build Coastguard Worker         let x: SafeNum = 255.into();
507*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(x.round_down(32), 224.into());
508*5225e6b1SAndroid Build Coastguard Worker         assert_eq!((x + 1).round_down(64), 256.into());
509*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(x.round_down(256), SafeNum::ZERO);
510*5225e6b1SAndroid Build Coastguard Worker         assert!(x.round_down(SafeNum::MIN).has_error());
511*5225e6b1SAndroid Build Coastguard Worker     }
512*5225e6b1SAndroid Build Coastguard Worker 
513*5225e6b1SAndroid Build Coastguard Worker     #[test]
test_round_up()514*5225e6b1SAndroid Build Coastguard Worker     fn test_round_up() {
515*5225e6b1SAndroid Build Coastguard Worker         let x: SafeNum = 255.into();
516*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(x.round_up(32), 256.into());
517*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(x.round_up(51), x);
518*5225e6b1SAndroid Build Coastguard Worker         assert_eq!(SafeNum::ZERO.round_up(x), SafeNum::ZERO);
519*5225e6b1SAndroid Build Coastguard Worker         assert!(SafeNum::MAX.round_up(32).has_error());
520*5225e6b1SAndroid Build Coastguard Worker     }
521*5225e6b1SAndroid Build Coastguard Worker }
522