diff --git a/gstreamer/src/format/clock_time.rs b/gstreamer/src/format/clock_time.rs index a89c0d044..86b4a59eb 100644 --- a/gstreamer/src/format/clock_time.rs +++ b/gstreamer/src/format/clock_time.rs @@ -368,6 +368,7 @@ impl From for Duration { impl_common_ops_for_newtype_uint!(ClockTime, u64); impl_signed_div_mul!(ClockTime, u64); +impl_signed_int_into_signed!(ClockTime, u64); // rustdoc-stripper-ignore-next /// Tell [`pad_clocktime`] what kind of time we're formatting @@ -1342,4 +1343,37 @@ mod tests { fn attempt_to_build_from_u64max() { let _ = ClockTime::from_nseconds(u64::MAX); } + + #[test] + fn try_into_signed() { + let time = crate::Signed::Positive(ClockTime::from_nseconds(0)); + assert_eq!(i64::try_from(time), Ok(0)); + + let time = crate::Signed::Positive(ClockTime::from_nseconds(123)); + assert_eq!(i64::try_from(time), Ok(123)); + + let time = crate::Signed::Positive(ClockTime::from_nseconds(u64::MAX - 1)); + assert!(i64::try_from(time).is_err()); + + let time = crate::Signed::Positive(ClockTime::from_nseconds(u64::MAX >> 1)); + assert_eq!(i64::MAX as i128, (u64::MAX >> 1) as i128); + assert_eq!(i64::try_from(time), Ok(i64::MAX)); + + let time = crate::Signed::Negative(ClockTime::from_nseconds(0)); + assert_eq!(i64::try_from(time), Ok(0)); + + let time = crate::Signed::Negative(ClockTime::from_nseconds(123)); + assert_eq!(i64::try_from(time), Ok(-123)); + + let time = crate::Signed::Negative(ClockTime::from_nseconds(u64::MAX - 1)); + assert!(i64::try_from(time).is_err()); + + let time = crate::Signed::Negative(ClockTime::from_nseconds(u64::MAX >> 1)); + assert_eq!(i64::MIN as i128 + 1, -((u64::MAX >> 1) as i128)); + assert_eq!(i64::try_from(time), Ok(i64::MIN + 1)); + + let time = crate::Signed::Negative(ClockTime::from_nseconds((u64::MAX >> 1) + 1)); + assert_eq!(i64::MIN as i128, -(((u64::MAX >> 1) + 1) as i128)); + assert_eq!(i64::try_from(time), Ok(i64::MIN)); + } } diff --git a/gstreamer/src/format/generic.rs b/gstreamer/src/format/generic.rs index 897619844..b592130a6 100644 --- a/gstreamer/src/format/generic.rs +++ b/gstreamer/src/format/generic.rs @@ -52,6 +52,7 @@ impl Other { impl_common_ops_for_newtype_uint!(Other, u64); impl_signed_div_mul!(Other, u64); +impl_signed_int_into_signed!(Other, u64); option_glib_newtype_from_to!(Other, u64::MAX); glib_newtype_display!(Other, DisplayableOptionOther); diff --git a/gstreamer/src/format/macros.rs b/gstreamer/src/format/macros.rs index ecb88a429..11a642ae7 100644 --- a/gstreamer/src/format/macros.rs +++ b/gstreamer/src/format/macros.rs @@ -517,6 +517,10 @@ macro_rules! impl_signed_ops( impl_signed_ops!(u32, u32, 0); }; + (usize) => { + impl_signed_ops!(usize, usize, 0); + }; + ($typ:ty, $inner:ty, $zero:expr) => { impl crate::Signed<$typ> { // rustdoc-stripper-ignore-next @@ -879,6 +883,26 @@ macro_rules! impl_signed_div_mul( ($typ:ty, $inner:ty, $signed_rhs:ty, $into_inner:expr) => { impl crate::Signed<$typ> { + #[allow(dead_code)] + fn signed_from_inner(val: $inner, 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) -> Option { + skip_assert_initialized!(); + <$typ>::try_from(val).ok().map(crate::Signed::Positive) + } + + fn negative_from_inner(val: $inner) -> Option { + skip_assert_initialized!(); + <$typ>::try_from(val).ok().map(crate::Signed::Negative) + } + #[must_use = "this returns the result of the operation, without modifying the original"] pub fn checked_div(self, rhs:$signed_rhs) -> Option { use crate::Signed::*; @@ -1274,27 +1298,6 @@ macro_rules! impl_signed_extra_div_mul( macro_rules! impl_signed_div_mul_trait( ($typ:ty, $inner:ty, $signed_rhs:ty, $into_inner:expr) => { - impl crate::Signed<$typ> { - fn signed_from_inner(val: $inner, 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) -> Option { - skip_assert_initialized!(); - <$typ>::try_from(val).ok().map(crate::Signed::Positive) - } - - fn negative_from_inner(val: $inner) -> Option { - skip_assert_initialized!(); - <$typ>::try_from(val).ok().map(crate::Signed::Negative) - } - } - impl muldiv::MulDiv<$signed_rhs> for crate::Signed<$typ> { type Output = Self; @@ -1628,3 +1631,59 @@ macro_rules! glib_newtype_display { } }; } + +macro_rules! impl_signed_int_into_signed( + (u64) => { + impl_signed_int_into_signed!(u64, u64, i64, |val: u64| val); + }; + + (usize) => { + impl_signed_int_into_signed!(usize, usize, isize, |val: usize| val); + }; + + (u32) => { + impl_signed_int_into_signed!(u32, u32, i32, |val: u32| val); + }; + + ($newtyp:ty, u64) => { + impl_signed_int_into_signed!($newtyp, u64, i64, |val: $newtyp| *val); + }; + + ($newtyp:ty, u32) => { + impl_signed_int_into_signed!($newtyp, u32, i32, |val: $newtyp| *val); + }; + + ($typ:ty, $inner:ty, $signed:ty, $into_inner:expr) => { + impl TryFrom> for $signed { + type Error = std::num::TryFromIntError; + + fn try_from(value: crate::Signed<$typ>) -> Result<$signed, Self::Error> { + assert_eq!(::std::mem::size_of::<$inner>(), ::std::mem::size_of::<$signed>()); + + match value { + crate::Signed::Positive(value) => <$signed>::try_from($into_inner(value)), + crate::Signed::Negative(value) => { + let inner = $into_inner(value); + // `$signed::MIN.abs()` can't be represented as an `$signed` + if inner == (<$inner>::MAX >> 1) + 1 { + Ok(<$signed>::MIN) + } else { + Ok(-<$signed>::try_from(inner)?) + } + }, + } + } + } + + impl From<$signed> for crate::Signed<$typ> { + fn from(value: $signed) -> crate::Signed<$typ> { + let abs = value.unsigned_abs(); + if value.signum() >= 0 { + Self::positive_from_inner(abs).unwrap() + } else { + Self::negative_from_inner(abs).unwrap() + } + } + } + }; +); diff --git a/gstreamer/src/format/signed.rs b/gstreamer/src/format/signed.rs index d67e35155..ff6fcb7ec 100644 --- a/gstreamer/src/format/signed.rs +++ b/gstreamer/src/format/signed.rs @@ -220,50 +220,17 @@ pub trait UnsignedIntoSigned: Copy + Sized { impl_unsigned_int_into_signed!(u64); impl_signed_ops!(u64); impl_signed_div_mul!(u64); +impl_signed_int_into_signed!(u64); impl_unsigned_int_into_signed!(u32); impl_signed_ops!(u32); impl_signed_div_mul!(u32); +impl_signed_int_into_signed!(u32); -impl From for Signed { - fn from(val: i64) -> Signed { - skip_assert_initialized!(); - match val { - positive if positive.is_positive() => Signed::Positive(positive as u64), - i64::MIN => { - // `i64::MIN.abs()` can't be represented as an `i64` - Signed::Negative((-(i64::MIN as i128)) as u64) - } - negative => Signed::Negative((-negative) as u64), - } - } -} - -impl From for Signed { - fn from(val: isize) -> Signed { - skip_assert_initialized!(); - match val { - positive if positive.is_positive() => Signed::Positive(positive as usize), - isize::MIN => { - // `isize::MIN.abs()` can't be represented as an `isize` - Signed::Negative((-(isize::MIN as i128)) as usize) - } - negative => Signed::Negative((-negative) as usize), - } - } -} - -// `i32::MIN.abs()` can't be represented as an `i32` -impl From for Signed { - fn from(val: i32) -> Signed { - skip_assert_initialized!(); - if val.is_positive() { - Signed::Positive(val as u32) - } else { - Signed::Negative((-(val as i64)) as u32) - } - } -} +impl_unsigned_int_into_signed!(usize); +impl_signed_ops!(usize); +impl_signed_div_mul!(usize); +impl_signed_int_into_signed!(usize); pub trait NoneSignedBuilder: FormattedValueNoneBuilder { type Signed; diff --git a/gstreamer/src/format/specific.rs b/gstreamer/src/format/specific.rs index fc5a64d4b..6327a8a24 100644 --- a/gstreamer/src/format/specific.rs +++ b/gstreamer/src/format/specific.rs @@ -60,6 +60,7 @@ impl Buffers { impl_common_ops_for_newtype_uint!(Buffers, u64); impl_signed_div_mul!(Buffers, u64); +impl_signed_int_into_signed!(Buffers, u64); impl_format_value_traits!(Buffers, Buffers, Buffers, u64); option_glib_newtype_from_to!(Buffers, Buffers::OFFSET_NONE); glib_newtype_display!(Buffers, DisplayableOptionBuffers, Format::Buffers); @@ -132,6 +133,7 @@ impl Bytes { impl_common_ops_for_newtype_uint!(Bytes, u64); impl_signed_div_mul!(Bytes, u64); +impl_signed_int_into_signed!(Bytes, u64); impl_format_value_traits!(Bytes, Bytes, Bytes, u64); option_glib_newtype_from_to!(Bytes, u64::MAX); glib_newtype_display!(Bytes, DisplayableOptionBytes, Format::Bytes); @@ -222,6 +224,7 @@ impl Default { impl_common_ops_for_newtype_uint!(Default, u64); impl_signed_div_mul!(Default, u64); +impl_signed_int_into_signed!(Default, u64); impl_format_value_traits!(Default, Default, Default, u64); option_glib_newtype_from_to!(Default, u64::MAX); glib_newtype_display!(Default, DisplayableOptionDefault, Format::Default); @@ -297,6 +300,7 @@ impl Percent { impl_common_ops_for_newtype_uint!(Percent, u32, one: ffi::GST_FORMAT_PERCENT_SCALE as u32); impl_signed_div_mul!(Percent, u32); +impl_signed_int_into_signed!(Percent, u32); impl FormattedValue for Option { type FullRange = Option;