From 183a399d1da3a12cedfb93df7f62cfc861f48f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= Date: Mon, 19 Sep 2022 18:38:19 +0200 Subject: [PATCH] gst/Signed: impl `MulDiv` --- gstreamer/src/clock_time.rs | 42 ++++++++++ gstreamer/src/format.rs | 13 +++ gstreamer/src/macros.rs | 156 +++++++++++++++++++++++++++++++++--- 3 files changed, 199 insertions(+), 12 deletions(-) diff --git a/gstreamer/src/clock_time.rs b/gstreamer/src/clock_time.rs index 3b271991e..f4d48587d 100644 --- a/gstreamer/src/clock_time.rs +++ b/gstreamer/src/clock_time.rs @@ -711,6 +711,48 @@ mod tests { ); } + #[test] + fn mul_div_ops() { + assert_eq!(CT_1.mul_div_floor(7, 3), Some(CT_2)); + + assert_eq!(P_CT_1.mul_div_floor(7u64, 3), Some(P_CT_2)); + assert_eq!(P_CT_1.mul_div_floor(-7i64, 3), Some(N_CT_2)); + assert_eq!(P_CT_1.mul_div_floor(7i64, -3), Some(N_CT_2)); + assert_eq!(P_CT_1.mul_div_floor(-7i64, -3), Some(P_CT_2)); + + assert_eq!(N_CT_1.mul_div_floor(7u64, 3), Some(N_CT_2)); + assert_eq!(N_CT_1.mul_div_floor(-7i64, 3), Some(P_CT_2)); + assert_eq!(N_CT_1.mul_div_floor(7i64, -3), Some(P_CT_2)); + assert_eq!(N_CT_1.mul_div_floor(-7i64, -3), Some(N_CT_2)); + + assert_eq!(CT_1.mul_div_round(10, 3), Some(CT_3)); + assert_eq!(CT_1.mul_div_round(8, 3), Some(CT_3)); + + assert_eq!(P_CT_1.mul_div_round(10u64, 3), Some(P_CT_3)); + assert_eq!(P_CT_1.mul_div_round(8u64, 3), Some(P_CT_3)); + assert_eq!(P_CT_1.mul_div_round(-10i64, 3), Some(N_CT_3)); + assert_eq!(P_CT_1.mul_div_round(-8i64, 3), Some(N_CT_3)); + assert_eq!(P_CT_1.mul_div_round(10i64, -3), Some(N_CT_3)); + assert_eq!(P_CT_1.mul_div_round(-10i64, -3), Some(P_CT_3)); + + assert_eq!(N_CT_1.mul_div_round(10u64, 3), Some(N_CT_3)); + assert_eq!(N_CT_1.mul_div_round(-10i64, 3), Some(P_CT_3)); + assert_eq!(N_CT_1.mul_div_round(10i64, -3), Some(P_CT_3)); + assert_eq!(N_CT_1.mul_div_round(-10i64, -3), Some(N_CT_3)); + + assert_eq!(CT_1.mul_div_ceil(7, 3), Some(CT_3)); + + assert_eq!(P_CT_1.mul_div_ceil(7u64, 3), Some(P_CT_3)); + assert_eq!(P_CT_1.mul_div_ceil(-7i64, 3), Some(N_CT_3)); + assert_eq!(P_CT_1.mul_div_ceil(7i64, -3), Some(N_CT_3)); + assert_eq!(P_CT_1.mul_div_ceil(-7i64, -3), Some(P_CT_3)); + + assert_eq!(N_CT_1.mul_div_ceil(7u64, 3), Some(N_CT_3)); + assert_eq!(N_CT_1.mul_div_ceil(-7i64, 3), Some(P_CT_3)); + assert_eq!(N_CT_1.mul_div_ceil(7i64, -3), Some(P_CT_3)); + assert_eq!(N_CT_1.mul_div_ceil(-7i64, -3), Some(N_CT_3)); + } + #[test] #[allow(clippy::nonminimal_bool)] fn comp() { diff --git a/gstreamer/src/format.rs b/gstreamer/src/format.rs index 5015a08f2..3f9fc1696 100644 --- a/gstreamer/src/format.rs +++ b/gstreamer/src/format.rs @@ -1003,6 +1003,19 @@ impl TryFromGlib for Percent { } } +impl TryFrom for Percent { + type Error = FormattedValueError; + + fn try_from(value: u32) -> Result { + skip_assert_initialized!(); + if value > ffi::GST_FORMAT_PERCENT_MAX as u32 { + Err(FormattedValueError(Format::Percent)) + } else { + Ok(Percent(value)) + } + } +} + impl TryFrom for Option { type Error = FormattedValueError; diff --git a/gstreamer/src/macros.rs b/gstreamer/src/macros.rs index 6fe31dab5..63cdf8939 100644 --- a/gstreamer/src/macros.rs +++ b/gstreamer/src/macros.rs @@ -635,30 +635,31 @@ macro_rules! impl_signed_ops( macro_rules! impl_signed_div_mul( (u64) => { - impl_signed_div_mul!(u64, u64, i64); + impl_signed_div_mul!(u64, u64, i64, |val: u64| val); + impl_signed_div_mul_trait!(u64, u64, i64, |val: u64| val); }; (usize) => { - impl_signed_div_mul!(usize, usize, isize); + impl_signed_div_mul!(usize, usize, isize, |val: usize| val); + // `MulDiv` not available for usize }; (u32) => { - impl_signed_div_mul!(u32, u32, i32); + impl_signed_div_mul!(u32, u32, i32, |val: u32| val); + impl_signed_div_mul_trait!(u32, u32, i32, |val: u32| val); }; - ($type:ty, u64) => { - impl_signed_div_mul!($type, u64, i64); + ($new_type:ty, u64) => { + impl_signed_div_mul!($new_type, u64, i64, |val: $new_type| *val); + impl_signed_div_mul_trait!($new_type, u64, i64, |val: $new_type| *val); }; - ($type:ty, usize) => { - impl_signed_div_mul!($type, usize, isize); + ($new_type:ty, u32) => { + impl_signed_div_mul!($new_type, u32, i32, |val: $new_type| *val); + impl_signed_div_mul_trait!($new_type, u32, i32, |val: $new_type| *val); }; - ($type:ty, u32) => { - impl_signed_div_mul!($type, u32, i32); - }; - - ($type:ty, $inner_type:ty, $signed_rhs:ty) => { + ($type:ty, $inner_type:ty, $signed_rhs:ty, $into_inner:expr) => { impl crate::Signed<$type> { #[must_use = "this returns the result of the operation, without modifying the original"] pub fn checked_div(self, rhs:$signed_rhs) -> Option { @@ -875,6 +876,137 @@ macro_rules! impl_signed_div_mul( }; ); +macro_rules! impl_signed_div_mul_trait( + ($type:ty, $inner_type:ty, $signed_rhs:ty, $into_inner:expr) => { + impl crate::Signed<$type> { + fn signed_from_inner(val: $inner_type, sign: $signed_rhs) -> Option> { + skip_assert_initialized!(); + if sign.is_positive() { + Self::positive_from_inner(val) + } else { + Self::negative_from_inner(val) + } + } + + fn positive_from_inner(val: $inner_type) -> Option> { + skip_assert_initialized!(); + use crate::UnsignedIntoSigned; + <$type>::try_from(val).ok().map(<$type>::into_positive) + } + + fn negative_from_inner(val: $inner_type) -> Option> { + skip_assert_initialized!(); + use crate::UnsignedIntoSigned; + <$type>::try_from(val).ok().map(<$type>::into_negative) + } + } + + impl MulDiv<$signed_rhs> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn mul_div_floor(self, num: $signed_rhs, denom: $signed_rhs) -> Option { + use crate::Signed::*; + match self { + Positive(lhs) => { + $into_inner(lhs) + .mul_div_floor(num.abs() as $inner_type, denom.abs() as $inner_type) + .and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum())) + } + Negative(lhs) => { + $into_inner(lhs) + .mul_div_floor(num.abs() as $inner_type, denom.abs() as $inner_type) + .and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum())) + } + } + } + + fn mul_div_round(self, num: $signed_rhs, denom: $signed_rhs) -> Option { + use crate::Signed::*; + match self { + Positive(lhs) => { + $into_inner(lhs) + .mul_div_round(num.abs() as $inner_type, denom.abs() as $inner_type) + .and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum())) + } + Negative(lhs) => { + $into_inner(lhs) + .mul_div_round(num.abs() as $inner_type, denom.abs() as $inner_type) + .and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum())) + } + } + } + + fn mul_div_ceil(self, num: $signed_rhs, denom: $signed_rhs) -> Option { + use crate::Signed::*; + match self { + Positive(lhs) => { + $into_inner(lhs) + .mul_div_ceil(num.abs() as $inner_type, denom.abs() as $inner_type) + .and_then(|val| Self::signed_from_inner(val, num.signum() * denom.signum())) + } + Negative(lhs) => { + $into_inner(lhs) + .mul_div_ceil(num.abs() as $inner_type, denom.abs() as $inner_type) + .and_then(|val| Self::signed_from_inner(val, -num.signum() * denom.signum())) + } + } + } + } + + impl MulDiv<$inner_type> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn mul_div_floor(self, num: $inner_type, denom: $inner_type) -> Option { + use crate::Signed::*; + match self { + Positive(lhs) => { + $into_inner(lhs) + .mul_div_floor(num, denom) + .and_then(Self::positive_from_inner) + } + Negative(lhs) => { + $into_inner(lhs) + .mul_div_floor(num, denom) + .and_then(Self::negative_from_inner) + } + } + } + + fn mul_div_round(self, num: $inner_type, denom: $inner_type) -> Option { + use crate::Signed::*; + match self { + Positive(lhs) => { + $into_inner(lhs) + .mul_div_round(num, denom) + .and_then(Self::positive_from_inner) + } + Negative(lhs) => { + $into_inner(lhs) + .mul_div_round(num, denom) + .and_then(Self::negative_from_inner) + } + } + } + + fn mul_div_ceil(self, num: $inner_type, denom: $inner_type) -> Option { + use crate::Signed::*; + match self { + Positive(lhs) => { + $into_inner(lhs) + .mul_div_ceil(num, denom) + .and_then(Self::positive_from_inner) + } + Negative(lhs) => { + $into_inner(lhs) + .mul_div_ceil(num, denom) + .and_then(Self::negative_from_inner) + } + } + } + } + }; +); + macro_rules! impl_format_value_traits( ($name:ident, $format:ident, $format_value:ident, $inner_type:ty) => { impl FormattedValue for Option<$name> {