diff --git a/gstreamer/src/clock_time.rs b/gstreamer/src/clock_time.rs index 26cefbfe4..3b271991e 100644 --- a/gstreamer/src/clock_time.rs +++ b/gstreamer/src/clock_time.rs @@ -225,6 +225,7 @@ impl From for Duration { } impl_common_ops_for_newtype_uint!(ClockTime, u64); +impl_signed_div_mul!(ClockTime, u64); // rustdoc-stripper-ignore-next /// Tell [`pad_clocktime`] what kind of time we're formatting @@ -492,7 +493,30 @@ mod tests { assert_eq!(P_CT_2 - N_CT_1, P_CT_3); assert_eq!(N_CT_2 - P_CT_1, N_CT_3); assert_eq!(N_CT_3 - N_CT_1, N_CT_2); - assert_eq!(N_CT_2 - N_CT_3, P_CT_1); + + assert_eq!(P_CT_1 * 2i64, P_CT_2); + assert_eq!(P_CT_1 * -2i64, N_CT_2); + assert_eq!(N_CT_1 * 2i64, N_CT_2); + assert_eq!(N_CT_1 * -2i64, P_CT_2); + + assert_eq!(P_CT_1 * 2u64, P_CT_2); + assert_eq!(N_CT_1 * 2u64, N_CT_2); + + assert_eq!(P_CT_2 / 2i64, P_CT_1); + assert_eq!(P_CT_2 / -2i64, N_CT_1); + assert_eq!(N_CT_2 / 2i64, N_CT_1); + assert_eq!(N_CT_2 / -2i64, P_CT_1); + + assert_eq!(P_CT_2 / 2u64, P_CT_1); + assert_eq!(N_CT_2 / 2u64, N_CT_1); + + assert_eq!(P_CT_3 % 2i64, P_CT_1); + assert_eq!(P_CT_3 % -2i64, P_CT_1); + assert_eq!(N_CT_3 % 2i64, N_CT_1); + assert_eq!(N_CT_3 % -2i64, N_CT_1); + + assert_eq!(P_CT_3 % 2u64, P_CT_1); + assert_eq!(N_CT_3 % 2u64, N_CT_1); } #[test] @@ -537,6 +561,24 @@ mod tests { Some(CT_1).opt_checked_sub(CT_2), Err(opt_ops::Error::Overflow) ); + + assert_eq!(CT_1.checked_mul(2), Some(CT_2)); + assert_eq!(P_CT_1.checked_mul(2), Some(P_CT_2)); + assert_eq!(P_CT_1.checked_mul(-2), Some(N_CT_2)); + assert_eq!(N_CT_1.checked_mul(2), Some(N_CT_2)); + assert_eq!(N_CT_1.checked_mul(-2), Some(P_CT_2)); + + assert_eq!(P_CT_1.checked_mul_unsigned(2u64), Some(P_CT_2)); + assert_eq!(N_CT_1.checked_mul_unsigned(2u64), Some(N_CT_2)); + + assert_eq!(CT_3.checked_div(3), Some(CT_1)); + assert_eq!(P_CT_3.checked_div(3), Some(P_CT_1)); + assert_eq!(P_CT_3.checked_div(-3), Some(N_CT_1)); + assert_eq!(N_CT_3.checked_div(3), Some(N_CT_1)); + assert_eq!(N_CT_3.checked_div(-3), Some(P_CT_1)); + + assert_eq!(P_CT_3.checked_div_unsigned(3u64), Some(P_CT_1)); + assert_eq!(N_CT_3.checked_div_unsigned(3u64), Some(N_CT_1)); } #[test] @@ -584,6 +626,7 @@ mod tests { #[test] fn saturating_ops() { let p_ct_max: Signed = ClockTime::MAX.into_positive(); + let n_ct_max: Signed = ClockTime::MAX.into_negative(); assert_eq!(CT_1.saturating_add(CT_2), CT_3); assert_eq!(P_CT_1.saturating_add(P_CT_2), P_CT_3); @@ -625,6 +668,20 @@ mod tests { assert_eq!(CT_1.saturating_mul(2), CT_2); assert_eq!(ClockTime::MAX.saturating_mul(2), ClockTime::MAX); + + assert_eq!(P_CT_1.saturating_mul(2), P_CT_2); + assert_eq!(P_CT_1.saturating_mul(-2), N_CT_2); + assert_eq!(N_CT_1.saturating_mul(2), N_CT_2); + assert_eq!(N_CT_1.saturating_mul(-2), P_CT_2); + + assert_eq!(P_CT_1.saturating_mul_unsigned(2u64), P_CT_2); + assert_eq!(N_CT_1.saturating_mul_unsigned(2u64), N_CT_2); + + assert_eq!(p_ct_max.saturating_mul(2), p_ct_max); + assert_eq!(n_ct_max.saturating_mul(2), n_ct_max); + + assert_eq!(p_ct_max.saturating_mul_unsigned(2u64), p_ct_max); + assert_eq!(n_ct_max.saturating_mul_unsigned(2u64), n_ct_max); } #[test] diff --git a/gstreamer/src/format.rs b/gstreamer/src/format.rs index 0727e987b..5015a08f2 100644 --- a/gstreamer/src/format.rs +++ b/gstreamer/src/format.rs @@ -235,13 +235,16 @@ pub trait UnsignedIntoSigned: Copy + Sized { } impl_unsigned_int_into_signed!(u64); -impl_signed_ops!(u64, 0); +impl_signed_ops!(u64); +impl_signed_div_mul!(u64); impl_unsigned_int_into_signed!(usize); -impl_signed_ops!(usize, 0); +impl_signed_ops!(usize); +impl_signed_div_mul!(usize); impl_unsigned_int_into_signed!(u32); -impl_signed_ops!(u32, 0); +impl_signed_ops!(u32); +impl_signed_div_mul!(u32); impl From for Signed { fn from(val: i64) -> Signed { @@ -796,6 +799,7 @@ impl UnsignedIntoSigned for GenericFormattedValue { } impl_common_ops_for_newtype_uint!(Default, u64); +impl_signed_div_mul!(Default, u64); impl_format_value_traits!(Default, Default, Default, u64); option_glib_newtype_from_to!(Default, u64::MAX); glib_newtype_display!( @@ -806,6 +810,7 @@ glib_newtype_display!( ); impl_common_ops_for_newtype_uint!(Bytes, u64); +impl_signed_div_mul!(Bytes, u64); impl_format_value_traits!(Bytes, Bytes, Bytes, u64); option_glib_newtype_from_to!(Bytes, u64::MAX); glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes"); @@ -813,6 +818,7 @@ glib_newtype_display!(Bytes, DisplayableBytes, DisplayableOptionBytes, "bytes"); impl_format_value_traits!(ClockTime, Time, Time, u64); impl_common_ops_for_newtype_uint!(Buffers, u64); +impl_signed_div_mul!(Buffers, u64); impl_format_value_traits!(Buffers, Buffers, Buffers, u64); option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE); glib_newtype_display!( @@ -919,6 +925,7 @@ impl From for Signed { glib_newtype_display!(Undefined, DisplayableUndefined, "(Undefined)"); impl_common_ops_for_newtype_uint!(Percent, u32); +impl_signed_div_mul!(Percent, u32); glib_newtype_display!(Percent, DisplayablePercent, DisplayableOptionPercent, "%"); impl FormattedValue for Option { diff --git a/gstreamer/src/macros.rs b/gstreamer/src/macros.rs index 89ffa5e90..6fe31dab5 100644 --- a/gstreamer/src/macros.rs +++ b/gstreamer/src/macros.rs @@ -158,6 +158,12 @@ macro_rules! impl_non_trait_op_inner_type( } } + #[must_use = "this returns the result of the operation, without modifying the original"] + #[inline] + pub const fn saturating_div(self, rhs: $inner_type) -> Self { + Self(self.0.saturating_div(rhs)) + } + #[must_use = "this returns the result of the operation, without modifying the original"] #[inline] pub const fn checked_mul(self, rhs: $inner_type) -> Option { @@ -266,7 +272,7 @@ macro_rules! impl_common_ops_for_newtype_uint( impl_non_trait_op_inner_type!($name, $inner_type); impl_unsigned_int_into_signed!($name); - impl_signed_ops!($name, $name::ZERO); + impl_signed_ops!($name, $inner_type, $name::ZERO); impl> MulDiv for $name { type Output = $name; @@ -423,7 +429,19 @@ macro_rules! impl_common_ops_for_newtype_uint( ); macro_rules! impl_signed_ops( - ($type:ty, $zero:expr) => { + (u64) => { + impl_signed_ops!(u64, u64, 0); + }; + + (usize) => { + impl_signed_ops!(usize, usize, 0); + }; + + (u32) => { + impl_signed_ops!(u32, u32, 0); + }; + + ($type:ty, $inner_type:ty, $zero:expr) => { impl crate::Signed<$type> { // rustdoc-stripper-ignore-next /// Returns the signum for this `Signed`. @@ -615,6 +633,248 @@ macro_rules! impl_signed_ops( }; ); +macro_rules! impl_signed_div_mul( + (u64) => { + impl_signed_div_mul!(u64, u64, i64); + }; + + (usize) => { + impl_signed_div_mul!(usize, usize, isize); + }; + + (u32) => { + impl_signed_div_mul!(u32, u32, i32); + }; + + ($type:ty, u64) => { + impl_signed_div_mul!($type, u64, i64); + }; + + ($type:ty, usize) => { + impl_signed_div_mul!($type, usize, isize); + }; + + ($type:ty, u32) => { + impl_signed_div_mul!($type, u32, i32); + }; + + ($type:ty, $inner_type:ty, $signed_rhs:ty) => { + 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 { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => { + if rhs.is_positive() { + lhs.checked_div(rhs as $inner_type).map(<$type>::into_positive) + } else { + lhs.checked_div(-rhs as $inner_type).map(<$type>::into_negative) + } + } + Negative(lhs) => { + if rhs.is_positive() { + lhs.checked_div(rhs as $inner_type).map(<$type>::into_negative) + } else { + lhs.checked_div(-rhs as $inner_type).map(<$type>::into_positive) + } + } + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn checked_div_unsigned(self, rhs:$inner_type) -> Option { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => lhs.checked_div(rhs).map(<$type>::into_positive), + Negative(lhs) => lhs.checked_div(rhs).map(<$type>::into_negative), + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn checked_rem(self, rhs:$signed_rhs) -> Option { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => { + if rhs.is_positive() { + lhs.checked_rem(rhs as $inner_type).map(<$type>::into_positive) + } else { + lhs.checked_rem(-rhs as $inner_type).map(<$type>::into_positive) + } + } + Negative(lhs) => { + if rhs.is_positive() { + lhs.checked_rem(rhs as $inner_type).map(<$type>::into_negative) + } else { + lhs.checked_rem(-rhs as $inner_type).map(<$type>::into_negative) + } + } + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn checked_rem_unsigned(self, rhs:$inner_type) -> Option { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => lhs.checked_rem(rhs).map(<$type>::into_positive), + Negative(lhs) => lhs.checked_rem(rhs).map(<$type>::into_negative), + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn checked_mul(self, rhs:$signed_rhs) -> Option { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => { + if rhs.is_positive() { + lhs.checked_mul(rhs as $inner_type).map(<$type>::into_positive) + } else { + lhs.checked_mul(-rhs as $inner_type).map(<$type>::into_negative) + } + } + Negative(lhs) => { + if rhs.is_positive() { + lhs.checked_mul(rhs as $inner_type).map(<$type>::into_negative) + } else { + lhs.checked_mul(-rhs as $inner_type).map(<$type>::into_positive) + } + } + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn checked_mul_unsigned(self, rhs:$inner_type) -> Option { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => lhs.checked_mul(rhs).map(<$type>::into_positive), + Negative(lhs) => lhs.checked_mul(rhs).map(<$type>::into_negative), + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn saturating_mul(self, rhs:$signed_rhs) -> Self { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => { + if rhs.is_positive() { + lhs.saturating_mul(rhs as $inner_type).into_positive() + } else { + lhs.saturating_mul(-rhs as $inner_type).into_negative() + } + } + Negative(lhs) => { + if rhs.is_positive() { + lhs.saturating_mul(rhs as $inner_type).into_negative() + } else { + lhs.saturating_mul(-rhs as $inner_type).into_positive() + } + } + } + } + + #[must_use = "this returns the result of the operation, without modifying the original"] + pub fn saturating_mul_unsigned(self, rhs:$inner_type) -> Self { + use crate::UnsignedIntoSigned; + use crate::Signed::*; + match self { + Positive(lhs) => lhs.saturating_mul(rhs).into_positive(), + Negative(lhs) => lhs.saturating_mul(rhs).into_negative(), + } + } + } + + impl std::ops::Div<$signed_rhs> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn div(self, rhs: $signed_rhs) -> crate::Signed<$type> { + self.checked_div(rhs).expect("division overflowed") + } + } + + impl std::ops::DivAssign<$signed_rhs> for crate::Signed<$type> { + fn div_assign(&mut self, rhs: $signed_rhs) { + *self = std::ops::Div::div(*self, rhs); + } + } + + impl std::ops::Div<$inner_type> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn div(self, rhs: $inner_type) -> crate::Signed<$type> { + self.checked_div_unsigned(rhs).expect("division overflowed") + } + } + + impl std::ops::DivAssign<$inner_type> for crate::Signed<$type> { + fn div_assign(&mut self, rhs: $inner_type) { + *self = std::ops::Div::div(*self, rhs); + } + } + + impl std::ops::Rem<$signed_rhs> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn rem(self, rhs: $signed_rhs) -> crate::Signed<$type> { + self.checked_rem(rhs).expect("division overflowed") + } + } + + impl std::ops::RemAssign<$signed_rhs> for crate::Signed<$type> { + fn rem_assign(&mut self, rhs: $signed_rhs) { + *self = std::ops::Rem::rem(*self, rhs); + } + } + + impl std::ops::Rem<$inner_type> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn rem(self, rhs: $inner_type) -> crate::Signed<$type> { + self.checked_rem_unsigned(rhs).expect("division overflowed") + } + } + + impl std::ops::RemAssign<$inner_type> for crate::Signed<$type> { + fn rem_assign(&mut self, rhs: $inner_type) { + *self = std::ops::Rem::rem(*self, rhs); + } + } + + impl std::ops::Mul<$signed_rhs> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn mul(self, rhs: $signed_rhs) -> crate::Signed<$type> { + self.checked_mul(rhs).expect("multiplication overflowed") + } + } + + impl std::ops::MulAssign<$signed_rhs> for crate::Signed<$type> { + fn mul_assign(&mut self, rhs: $signed_rhs) { + *self = std::ops::Mul::mul(*self, rhs); + } + } + + impl std::ops::Mul<$inner_type> for crate::Signed<$type> { + type Output = crate::Signed<$type>; + + fn mul(self, rhs: $inner_type) -> crate::Signed<$type> { + self.checked_mul_unsigned(rhs).expect("multiplication overflowed") + } + } + + impl std::ops::MulAssign<$inner_type> for crate::Signed<$type> { + fn mul_assign(&mut self, rhs: $inner_type) { + *self = std::ops::Mul::mul(*self, rhs); + } + } + }; +); + macro_rules! impl_format_value_traits( ($name:ident, $format:ident, $format_value:ident, $inner_type:ty) => { impl FormattedValue for Option<$name> {