diff --git a/README.md b/README.md index 4d8280c..c083d98 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,17 @@ The conversions supported cover the following cases. ### Version 0.4.6 news (unreleased) + * The following methods are now `const` functions: + [`saturating_neg`], [`saturating_add`], [`saturating_sub`], + [`saturating_mul_int`], [`saturating_abs`] * Support for casts using the [*az* crate] was added. +[`saturating_abs`]: https://docs.rs/fixed/0.4.5/fixed/struct.FixedI32.html#method.saturating_abs +[`saturating_add`]: https://docs.rs/fixed/0.4.5/fixed/struct.FixedI32.html#method.saturating_add +[`saturating_mul_int`]: https://docs.rs/fixed/0.4.5/fixed/struct.FixedI32.html#method.saturating_mul_int +[`saturating_mul_sub`]: https://docs.rs/fixed/0.4.5/fixed/struct.FixedI32.html#method.saturating_mul_sub +[`saturating_neg`]: https://docs.rs/fixed/0.4.5/fixed/struct.FixedI32.html#method.saturating_neg + ### Version 0.4.5 news (2019-08-30) * Bug fix: display of many decimal numbers was panicking in debug diff --git a/RELEASES.md b/RELEASES.md index fa0e186..55176e6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -8,6 +8,9 @@ as-is, without any warranty. --> Version 0.4.6 (unreleased) ========================== + * The following methods are now `const` functions: `saturating_neg`, + `saturating_add`, `saturating_sub`, `saturating_mul_int`, + `saturating_abs` * Support for casts using the *az* crate was added. Version 0.4.5 (2019-08-30) diff --git a/src/macros_no_frac.rs b/src/macros_no_frac.rs index 251e474..ee05955 100644 --- a/src/macros_no_frac.rs +++ b/src/macros_no_frac.rs @@ -633,10 +633,13 @@ assert_eq!(Fix::from_num(5).saturating_neg(), Fix::from_num(0));", ``` "; #[inline] - pub fn saturating_neg(self) -> $Fixed { + pub const fn saturating_neg(self) -> $Fixed { if_signed_unsigned! { $Signedness, - self.checked_neg().unwrap_or(Self::max_value()), + { + let (val, overflow) = self.overflowing_neg(); + val.if_cond_else(!overflow, Self::max_value()) + }, Self::from_bits(0), } } @@ -655,8 +658,16 @@ assert_eq!(Fix::max_value().saturating_add(Fix::from_num(1)), Fix::max_value()); ``` "; #[inline] - pub fn saturating_add(self, rhs: $Fixed) -> $Fixed { - Self::from_bits(self.to_bits().saturating_add(rhs.to_bits())) + pub const fn saturating_add(self, rhs: $Fixed) -> $Fixed { + let (val, overflow) = self.overflowing_add(rhs); + val.if_cond_else( + !overflow, + if_signed_unsigned! { + $Signedness, + Self::min_value().if_cond_else(self.to_bits() < 0, Self::max_value()), + Self::max_value(), + }, + ) } } @@ -680,8 +691,19 @@ assert_eq!(Fix::from_num(0).saturating_sub(Fix::from_num(1)), Fix::from_num(0)); ``` "; #[inline] - pub fn saturating_sub(self, rhs: $Fixed) -> $Fixed { - Self::from_bits(self.to_bits().saturating_sub(rhs.to_bits())) + pub const fn saturating_sub(self, rhs: $Fixed) -> $Fixed { + let (val, overflow) = self.overflowing_sub(rhs); + val.if_cond_else( + !overflow, + if_signed_unsigned! { + $Signedness, + Self::min_value().if_cond_else( + self.to_bits() < rhs.to_bits(), + Self::max_value(), + ), + Self::min_value(), + }, + ) } } @@ -698,8 +720,19 @@ assert_eq!(Fix::max_value().saturating_mul_int(2), Fix::max_value()); ``` "; #[inline] - pub fn saturating_mul_int(self, rhs: $Inner) -> $Fixed { - Self::from_bits(self.to_bits().saturating_mul(rhs)) + pub const fn saturating_mul_int(self, rhs: $Inner) -> $Fixed { + let (val, overflow) = self.overflowing_mul_int(rhs); + val.if_cond_else( + !overflow, + if_signed_unsigned! { + $Signedness, + Self::min_value().if_cond_else( + (self.to_bits() < 0) != (rhs < 0), + Self::max_value(), + ), + Self::max_value(), + }, + ) } } @@ -720,8 +753,9 @@ assert_eq!(Fix::min_value().saturating_abs(), Fix::max_value()); ``` "; #[inline] - pub fn saturating_abs(self) -> $Fixed { - self.checked_abs().unwrap_or(Self::max_value()) + pub const fn saturating_abs(self) -> $Fixed { + let (val, overflow) = self.overflowing_abs(); + val.if_cond_else(!overflow, Self::max_value()) } } } @@ -1268,6 +1302,12 @@ assert_eq!(Fix::min_value().overflowing_abs(), (Fix::min_value(), true)); } } } + + #[inline] + const fn if_cond_else(self, cond: bool, otherwise: Self) -> Self { + let not_mask = (cond as $Inner).wrapping_sub(1); + Self::from_bits((self.to_bits() & !not_mask) | (otherwise.to_bits() & not_mask)) + } } }; }