From 86549dc06e2092664768d2326cbe46b5e483a589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= Date: Wed, 21 Sep 2022 15:47:03 +0200 Subject: [PATCH] gst/Segment: return immediately from some functions... ... if the input `is_none`. --- gstreamer/src/format.rs | 210 ++++++++++++++++++++++++++++++++++----- gstreamer/src/lib.rs | 9 +- gstreamer/src/macros.rs | 15 +++ gstreamer/src/segment.rs | 183 ++++++++++++++++++++-------------- 4 files changed, 313 insertions(+), 104 deletions(-) diff --git a/gstreamer/src/format.rs b/gstreamer/src/format.rs index 3f9fc1696..cd0d0ad6c 100644 --- a/gstreamer/src/format.rs +++ b/gstreamer/src/format.rs @@ -439,6 +439,16 @@ pub trait FormattedValue: Copy + Clone + Sized + Into + ' #[doc(alias = "get_format")] fn format(&self) -> Format; + // rustdoc-stripper-ignore-next + /// Returns `true` if this `FormattedValue` represents a defined value. + fn is_some(&self) -> bool; + + // rustdoc-stripper-ignore-next + /// Returns `true` if this `FormattedValue` represents an undefined value. + fn is_none(&self) -> bool { + !self.is_some() + } + unsafe fn into_raw_value(self) -> i64; } @@ -477,6 +487,87 @@ pub trait SpecificFormattedValueFullRange: FormattedValueFullRange {} /// - `Bytes` is the intrinsic type for `Option`. pub trait SpecificFormattedValueIntrinsic: TryFromGlib + FormattedValueIntrinsic {} +pub trait FormattedValueNoneBuilder: FormattedValueFullRange { + // rustdoc-stripper-ignore-next + /// Returns the `None` value for `Self` as a `FullRange` if such a value can be represented. + /// + /// - For `SpecificFormattedValue`s, this results in `Option::::None`. + /// - For `GenericFormattedValue`, this can only be obtained using [`Self::none_for_format`] + /// because the `None` is an inner value of some of the variants. + /// + /// # Panics + /// + /// Panics if `Self` is `GenericFormattedValue` in which case, the `Format` must be known. + fn none() -> Self; + + // rustdoc-stripper-ignore-next + /// Returns the `None` value for `Self` if such a value can be represented. + /// + /// - For `SpecificFormattedValue`s, this is the same as `Self::none()` + /// if the `format` matches the `SpecificFormattedValue`'s format. + /// - For `GenericFormattedValue` this is the variant for the specified `format`, + /// initialized with `None` as a value, if the `format` can represent that value. + /// + /// # Panics + /// + /// Panics if `None` can't be represented by `Self` for `format` or by the requested + /// `GenericFormattedValue` variant. + #[track_caller] + fn none_for_format(format: Format) -> Self { + skip_assert_initialized!(); + // This is the default impl. `GenericFormattedValue` must override. + if Self::default_format() != format { + panic!( + "Expected: {:?}, requested {format:?}", + Self::default_format() + ); + } + + Self::none() + } +} + +pub trait NoneSignedBuilder: FormattedValueNoneBuilder { + type Signed; + + // rustdoc-stripper-ignore-next + /// Returns the `None` value for `Self` as a `Signed` if such a value can be represented. + /// + /// See details in [`FormattedValueNoneBuilder::none`]. + /// + /// # Panics + /// + /// Panics if `Self` is `GenericFormattedValue` in which case, the `Format` must be known. + fn none_signed() -> Self::Signed; + + // rustdoc-stripper-ignore-next + /// Returns the `None` value for `Self` as a `Signed`, if such a value can be represented. + /// + /// See details in [`FormattedValueNoneBuilder::none_for_format`]. + /// + /// # Panics + /// + /// Panics if `None` can't be represented by `Self` for `format` or by the requested + /// `GenericFormattedValue` variant. + fn none_signed_for_format(format: Format) -> Self::Signed; +} + +impl NoneSignedBuilder for T +where + T: UnsignedIntoSigned + FormattedValueNoneBuilder, +{ + type Signed = ::Signed; + + fn none_signed() -> Self::Signed { + Self::none().into_positive() + } + + fn none_signed_for_format(format: Format) -> Self::Signed { + skip_assert_initialized!(); + Self::none_for_format(format).into_positive() + } +} + // rustdoc-stripper-ignore-next /// A trait implemented on types which can hold [`FormattedValue`]s compatible with parameter `F`. /// @@ -686,6 +777,18 @@ impl FormattedValue for GenericFormattedValue { self.format() } + fn is_some(&self) -> bool { + match self { + Self::Undefined(_) => true, + Self::Default(v) => v.is_some(), + Self::Bytes(v) => v.is_some(), + Self::Time(v) => v.is_some(), + Self::Buffers(v) => v.is_some(), + Self::Percent(v) => v.is_some(), + Self::Other(..) => true, + } + } + unsafe fn into_raw_value(self) -> i64 { self.value() } @@ -697,6 +800,30 @@ impl FormattedValueFullRange for GenericFormattedValue { } } +impl FormattedValueNoneBuilder for GenericFormattedValue { + #[track_caller] + fn none() -> Self { + panic!(concat!( + "`GenericFormattedValue` can't build `None` without knowing", + "the target format. Use `GenericFormattedValue::none_for_format`", + )); + } + + #[track_caller] + fn none_for_format(format: Format) -> Self { + skip_assert_initialized!(); + match format { + Format::Undefined => panic!("`None` can't be represented by `Undefined`"), + Format::Default => Self::Default(None), + Format::Bytes => Self::Bytes(None), + Format::Time => Self::Time(None), + Format::Buffers => Self::Buffers(None), + Format::Percent => Self::Percent(None), + Format::__Unknown(_) => panic!("`None` can't be represented by `__Unknown`"), + } + } +} + impl GenericFormattedValue { pub fn new(format: Format, value: i64) -> Self { skip_assert_initialized!(); @@ -740,30 +867,6 @@ impl GenericFormattedValue { } } } - - pub fn is_some(&self) -> bool { - match *self { - Self::Undefined(_) => true, - Self::Default(v) => v.is_some(), - Self::Bytes(v) => v.is_some(), - Self::Time(v) => v.is_some(), - Self::Buffers(v) => v.is_some(), - Self::Percent(v) => v.is_some(), - Self::Other(..) => true, - } - } - - pub fn is_none(&self) -> bool { - match *self { - Self::Undefined(_) => false, - Self::Default(v) => v.is_none(), - Self::Bytes(v) => v.is_none(), - Self::Time(v) => v.is_none(), - Self::Buffers(v) => v.is_none(), - Self::Percent(v) => v.is_none(), - Self::Other(..) => false, - } - } } impl FormattedValueIntrinsic for GenericFormattedValue {} @@ -839,6 +942,10 @@ impl FormattedValue for Undefined { Format::Undefined } + fn is_some(&self) -> bool { + true + } + unsafe fn into_raw_value(self) -> i64 { self.0 } @@ -939,6 +1046,10 @@ impl FormattedValue for Option { Format::Percent } + fn is_some(&self) -> bool { + Option::is_some(self) + } + unsafe fn into_raw_value(self) -> i64 { self.map_or(-1, |v| v.0 as i64) } @@ -976,6 +1087,10 @@ impl FormattedValue for Percent { Format::Percent } + fn is_some(&self) -> bool { + true + } + unsafe fn into_raw_value(self) -> i64 { self.0 as i64 } @@ -1033,6 +1148,11 @@ impl FormattedValueIntrinsic for Percent {} impl SpecificFormattedValue for Option {} impl SpecificFormattedValueFullRange for Option {} impl SpecificFormattedValueIntrinsic for Percent {} +impl FormattedValueNoneBuilder for Option { + fn none() -> Option { + None + } +} impl ops::Deref for Percent { type Target = u32; @@ -1204,6 +1324,48 @@ mod tests { .unwrap_err(); } + #[test] + fn none_builder() { + let ct_none: Option = Option::::none(); + assert!(ct_none.is_none()); + + let ct_none: Option = Option::::none_for_format(Format::Time); + assert!(ct_none.is_none()); + + let gen_ct_none: GenericFormattedValue = + GenericFormattedValue::none_for_format(Format::Time); + assert!(gen_ct_none.is_none()); + + assert!(ClockTime::ZERO.is_some()); + assert!(!ClockTime::ZERO.is_none()); + } + + #[test] + #[should_panic] + fn none_for_inconsistent_format() { + let _ = Option::::none_for_format(Format::Percent); + } + + #[test] + #[should_panic] + fn none_for_unsupported_format() { + let _ = GenericFormattedValue::none_for_format(Format::Undefined); + } + + #[test] + fn none_signed_builder() { + let ct_none: Option> = Option::::none_signed(); + assert!(ct_none.is_none()); + + let ct_none: Option> = + Option::::none_signed_for_format(Format::Time); + assert!(ct_none.is_none()); + + let gen_ct_none: Signed = + GenericFormattedValue::none_signed_for_format(Format::Time); + assert!(gen_ct_none.abs().is_none()); + } + #[test] fn signed_optional() { let ct_1 = Some(ClockTime::SECOND); diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 8725a762b..b6e80ea0b 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -227,8 +227,9 @@ mod typefind_factory; pub mod format; pub use crate::format::{ CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, - GenericFormattedValue, Signed, SpecificFormattedValue, SpecificFormattedValueFullRange, - SpecificFormattedValueIntrinsic, UnsignedIntoSigned, + FormattedValueNoneBuilder, GenericFormattedValue, NoneSignedBuilder, Signed, + SpecificFormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, + UnsignedIntoSigned, }; #[cfg(feature = "serde")] mod format_serde; @@ -353,8 +354,8 @@ pub mod prelude { pub use crate::format::{ CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, - SpecificFormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, - UnsignedIntoSigned, + FormattedValueNoneBuilder, NoneSignedBuilder, SpecificFormattedValue, + SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, UnsignedIntoSigned, }; pub use crate::utils::Displayable; diff --git a/gstreamer/src/macros.rs b/gstreamer/src/macros.rs index cd9ca06c2..01c899c0a 100644 --- a/gstreamer/src/macros.rs +++ b/gstreamer/src/macros.rs @@ -1140,6 +1140,10 @@ macro_rules! impl_format_value_traits( Format::$format } + fn is_some(&self) -> bool { + Option::is_some(self) + } + unsafe fn into_raw_value(self) -> i64 { IntoGlib::into_glib(self) as i64 } @@ -1152,6 +1156,12 @@ macro_rules! impl_format_value_traits( } } + impl FormattedValueNoneBuilder for Option<$name> { + fn none() -> Option<$name> { + None + } + } + impl From> for GenericFormattedValue { fn from(v: Option<$name>) -> Self { skip_assert_initialized!(); @@ -1165,6 +1175,7 @@ macro_rules! impl_format_value_traits( Self::$format_value(Some(v)) } } + impl FormattedValue for $name { type FullRange = Option<$name>; @@ -1176,6 +1187,10 @@ macro_rules! impl_format_value_traits( Format::$format } + fn is_some(&self) -> bool { + true + } + unsafe fn into_raw_value(self) -> i64 { IntoGlib::into_glib(self) as i64 } diff --git a/gstreamer/src/segment.rs b/gstreamer/src/segment.rs index 571125f54..eb27df0c7 100644 --- a/gstreamer/src/segment.rs +++ b/gstreamer/src/segment.rs @@ -6,7 +6,7 @@ use crate::SeekFlags; use crate::SeekType; use crate::{ CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, - UnsignedIntoSigned, + FormattedValueNoneBuilder, NoneSignedBuilder, UnsignedIntoSigned, }; use glib::translate::*; use glib::StaticType; @@ -175,48 +175,6 @@ impl FormattedSegment { } } - #[doc(alias = "gst_segment_position_from_running_time")] - pub fn position_from_running_time( - &self, - running_time: impl CompatibleFormattedValue, - ) -> T::FullRange { - let running_time = running_time - .try_into_checked_explicit(self.format()) - .unwrap(); - - unsafe { - T::FullRange::from_raw( - self.format(), - ffi::gst_segment_position_from_running_time( - &self.0, - self.format().into_glib(), - running_time.into_raw_value() as u64, - ) as i64, - ) - } - } - - #[doc(alias = "gst_segment_position_from_stream_time")] - pub fn position_from_stream_time( - &self, - stream_time: impl CompatibleFormattedValue, - ) -> T::FullRange { - let stream_time = stream_time - .try_into_checked_explicit(self.format()) - .unwrap(); - - unsafe { - T::FullRange::from_raw( - self.format(), - ffi::gst_segment_position_from_stream_time( - &self.0, - self.format().into_glib(), - stream_time.into_raw_value() as u64, - ) as i64, - ) - } - } - #[doc(alias = "gst_segment_set_running_time")] pub fn set_running_time( &mut self, @@ -238,38 +196,6 @@ impl FormattedSegment { } } - #[doc(alias = "gst_segment_to_running_time")] - pub fn to_running_time(&self, position: impl CompatibleFormattedValue) -> T::FullRange { - let position = position.try_into_checked_explicit(self.format()).unwrap(); - - unsafe { - T::FullRange::from_raw( - self.format(), - ffi::gst_segment_to_running_time( - &self.0, - self.format().into_glib(), - position.into_raw_value() as u64, - ) as i64, - ) - } - } - - #[doc(alias = "gst_segment_to_stream_time")] - pub fn to_stream_time(&self, position: impl CompatibleFormattedValue) -> T::FullRange { - let position = position.try_into_checked_explicit(self.format()).unwrap(); - - unsafe { - T::FullRange::from_raw( - self.format(), - ffi::gst_segment_to_stream_time( - &self.0, - self.format().into_glib(), - position.into_raw_value() as u64, - ) as i64, - ) - } - } - #[doc(alias = "get_flags")] pub fn flags(&self) -> crate::SegmentFlags { unsafe { from_glib(self.0.flags) } @@ -388,7 +314,100 @@ impl PartialEq for FormattedSegment { impl FormattedSegment where T: FormattedValueIntrinsic, - ::FullRange: UnsignedIntoSigned, + T::FullRange: FormattedValueNoneBuilder, +{ + #[doc(alias = "gst_segment_position_from_running_time")] + pub fn position_from_running_time( + &self, + running_time: impl CompatibleFormattedValue, + ) -> T::FullRange { + let running_time = running_time + .try_into_checked_explicit(self.format()) + .unwrap(); + if running_time.is_none() { + return T::FullRange::none_for_format(self.format()); + } + + unsafe { + T::FullRange::from_raw( + self.format(), + ffi::gst_segment_position_from_running_time( + &self.0, + self.format().into_glib(), + running_time.into_raw_value() as u64, + ) as i64, + ) + } + } + + #[doc(alias = "gst_segment_position_from_stream_time")] + pub fn position_from_stream_time( + &self, + stream_time: impl CompatibleFormattedValue, + ) -> T::FullRange { + let stream_time = stream_time + .try_into_checked_explicit(self.format()) + .unwrap(); + if stream_time.is_none() { + return T::FullRange::none_for_format(self.format()); + } + + unsafe { + T::FullRange::from_raw( + self.format(), + ffi::gst_segment_position_from_stream_time( + &self.0, + self.format().into_glib(), + stream_time.into_raw_value() as u64, + ) as i64, + ) + } + } + + #[doc(alias = "gst_segment_to_running_time")] + pub fn to_running_time(&self, position: impl CompatibleFormattedValue) -> T::FullRange { + let position = position.try_into_checked_explicit(self.format()).unwrap(); + if position.is_none() { + return T::FullRange::none_for_format(self.format()); + } + + unsafe { + T::FullRange::from_raw( + self.format(), + ffi::gst_segment_to_running_time( + &self.0, + self.format().into_glib(), + position.into_raw_value() as u64, + ) as i64, + ) + } + } + + #[doc(alias = "gst_segment_to_stream_time")] + pub fn to_stream_time(&self, position: impl CompatibleFormattedValue) -> T::FullRange { + let position = position.try_into_checked_explicit(self.format()).unwrap(); + if position.is_none() { + return T::FullRange::none_for_format(self.format()); + } + + unsafe { + T::FullRange::from_raw( + self.format(), + ffi::gst_segment_to_stream_time( + &self.0, + self.format().into_glib(), + position.into_raw_value() as u64, + ) as i64, + ) + } + } +} + +impl FormattedSegment +where + T: FormattedValueIntrinsic, + T::FullRange: UnsignedIntoSigned, + T::FullRange: NoneSignedBuilder::Signed>, { #[doc(alias = "gst_segment_position_from_running_time_full")] pub fn position_from_running_time_full( @@ -398,6 +417,9 @@ where let running_time = running_time .try_into_checked_explicit(self.format()) .unwrap(); + if running_time.is_none() { + return T::FullRange::none_signed_for_format(self.format()); + } unsafe { let mut position = mem::MaybeUninit::uninit(); @@ -420,6 +442,9 @@ where let stream_time = stream_time .try_into_checked_explicit(self.format()) .unwrap(); + if stream_time.is_none() { + return T::FullRange::none_signed_for_format(self.format()); + } unsafe { let mut position = mem::MaybeUninit::uninit(); @@ -440,6 +465,9 @@ where position: impl CompatibleFormattedValue, ) -> ::Signed { let position = position.try_into_checked_explicit(self.format()).unwrap(); + if position.is_none() { + return T::FullRange::none_signed_for_format(self.format()); + } unsafe { let mut running_time = mem::MaybeUninit::uninit(); @@ -461,6 +489,9 @@ where position: impl CompatibleFormattedValue, ) -> ::Signed { let position = position.try_into_checked_explicit(self.format()).unwrap(); + if position.is_none() { + return T::FullRange::none_signed_for_format(self.format()); + } unsafe { let mut stream_time = mem::MaybeUninit::uninit();