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