gst/Segment: return immediately from some functions...

... if the input `is_none`.
This commit is contained in:
François Laignel 2022-09-21 15:47:03 +02:00 committed by François Laignel
parent 8595b67218
commit 86549dc06e
4 changed files with 313 additions and 104 deletions

View file

@ -439,6 +439,16 @@ pub trait FormattedValue: Copy + Clone + Sized + Into<GenericFormattedValue> + '
#[doc(alias = "get_format")] #[doc(alias = "get_format")]
fn format(&self) -> 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; unsafe fn into_raw_value(self) -> i64;
} }
@ -477,6 +487,87 @@ pub trait SpecificFormattedValueFullRange: FormattedValueFullRange {}
/// - `Bytes` is the intrinsic type for `Option<Bytes>`. /// - `Bytes` is the intrinsic type for `Option<Bytes>`.
pub trait SpecificFormattedValueIntrinsic: TryFromGlib<i64> + FormattedValueIntrinsic {} pub trait SpecificFormattedValueIntrinsic: TryFromGlib<i64> + 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::<FormattedValueIntrinsic>::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<FullRange>` 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<FullRange>`, 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<T> NoneSignedBuilder for T
where
T: UnsignedIntoSigned + FormattedValueNoneBuilder,
{
type Signed = <T as UnsignedIntoSigned>::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 // rustdoc-stripper-ignore-next
/// A trait implemented on types which can hold [`FormattedValue`]s compatible with parameter `F`. /// A trait implemented on types which can hold [`FormattedValue`]s compatible with parameter `F`.
/// ///
@ -686,6 +777,18 @@ impl FormattedValue for GenericFormattedValue {
self.format() 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 { unsafe fn into_raw_value(self) -> i64 {
self.value() 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 { impl GenericFormattedValue {
pub fn new(format: Format, value: i64) -> Self { pub fn new(format: Format, value: i64) -> Self {
skip_assert_initialized!(); 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 {} impl FormattedValueIntrinsic for GenericFormattedValue {}
@ -839,6 +942,10 @@ impl FormattedValue for Undefined {
Format::Undefined Format::Undefined
} }
fn is_some(&self) -> bool {
true
}
unsafe fn into_raw_value(self) -> i64 { unsafe fn into_raw_value(self) -> i64 {
self.0 self.0
} }
@ -939,6 +1046,10 @@ impl FormattedValue for Option<Percent> {
Format::Percent Format::Percent
} }
fn is_some(&self) -> bool {
Option::is_some(self)
}
unsafe fn into_raw_value(self) -> i64 { unsafe fn into_raw_value(self) -> i64 {
self.map_or(-1, |v| v.0 as i64) self.map_or(-1, |v| v.0 as i64)
} }
@ -976,6 +1087,10 @@ impl FormattedValue for Percent {
Format::Percent Format::Percent
} }
fn is_some(&self) -> bool {
true
}
unsafe fn into_raw_value(self) -> i64 { unsafe fn into_raw_value(self) -> i64 {
self.0 as i64 self.0 as i64
} }
@ -1033,6 +1148,11 @@ impl FormattedValueIntrinsic for Percent {}
impl SpecificFormattedValue for Option<Percent> {} impl SpecificFormattedValue for Option<Percent> {}
impl SpecificFormattedValueFullRange for Option<Percent> {} impl SpecificFormattedValueFullRange for Option<Percent> {}
impl SpecificFormattedValueIntrinsic for Percent {} impl SpecificFormattedValueIntrinsic for Percent {}
impl FormattedValueNoneBuilder for Option<Percent> {
fn none() -> Option<Percent> {
None
}
}
impl ops::Deref for Percent { impl ops::Deref for Percent {
type Target = u32; type Target = u32;
@ -1204,6 +1324,48 @@ mod tests {
.unwrap_err(); .unwrap_err();
} }
#[test]
fn none_builder() {
let ct_none: Option<ClockTime> = Option::<ClockTime>::none();
assert!(ct_none.is_none());
let ct_none: Option<ClockTime> = Option::<ClockTime>::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::<ClockTime>::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<Signed<ClockTime>> = Option::<ClockTime>::none_signed();
assert!(ct_none.is_none());
let ct_none: Option<Signed<ClockTime>> =
Option::<ClockTime>::none_signed_for_format(Format::Time);
assert!(ct_none.is_none());
let gen_ct_none: Signed<GenericFormattedValue> =
GenericFormattedValue::none_signed_for_format(Format::Time);
assert!(gen_ct_none.abs().is_none());
}
#[test] #[test]
fn signed_optional() { fn signed_optional() {
let ct_1 = Some(ClockTime::SECOND); let ct_1 = Some(ClockTime::SECOND);

View file

@ -227,8 +227,9 @@ mod typefind_factory;
pub mod format; pub mod format;
pub use crate::format::{ pub use crate::format::{
CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic,
GenericFormattedValue, Signed, SpecificFormattedValue, SpecificFormattedValueFullRange, FormattedValueNoneBuilder, GenericFormattedValue, NoneSignedBuilder, Signed,
SpecificFormattedValueIntrinsic, UnsignedIntoSigned, SpecificFormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic,
UnsignedIntoSigned,
}; };
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
mod format_serde; mod format_serde;
@ -353,8 +354,8 @@ pub mod prelude {
pub use crate::format::{ pub use crate::format::{
CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic,
SpecificFormattedValue, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, FormattedValueNoneBuilder, NoneSignedBuilder, SpecificFormattedValue,
UnsignedIntoSigned, SpecificFormattedValueFullRange, SpecificFormattedValueIntrinsic, UnsignedIntoSigned,
}; };
pub use crate::utils::Displayable; pub use crate::utils::Displayable;

View file

@ -1140,6 +1140,10 @@ macro_rules! impl_format_value_traits(
Format::$format Format::$format
} }
fn is_some(&self) -> bool {
Option::is_some(self)
}
unsafe fn into_raw_value(self) -> i64 { unsafe fn into_raw_value(self) -> i64 {
IntoGlib::into_glib(self) as 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<Option<$name>> for GenericFormattedValue { impl From<Option<$name>> for GenericFormattedValue {
fn from(v: Option<$name>) -> Self { fn from(v: Option<$name>) -> Self {
skip_assert_initialized!(); skip_assert_initialized!();
@ -1165,6 +1175,7 @@ macro_rules! impl_format_value_traits(
Self::$format_value(Some(v)) Self::$format_value(Some(v))
} }
} }
impl FormattedValue for $name { impl FormattedValue for $name {
type FullRange = Option<$name>; type FullRange = Option<$name>;
@ -1176,6 +1187,10 @@ macro_rules! impl_format_value_traits(
Format::$format Format::$format
} }
fn is_some(&self) -> bool {
true
}
unsafe fn into_raw_value(self) -> i64 { unsafe fn into_raw_value(self) -> i64 {
IntoGlib::into_glib(self) as i64 IntoGlib::into_glib(self) as i64
} }

View file

@ -6,7 +6,7 @@ use crate::SeekFlags;
use crate::SeekType; use crate::SeekType;
use crate::{ use crate::{
CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic, CompatibleFormattedValue, FormattedValue, FormattedValueFullRange, FormattedValueIntrinsic,
UnsignedIntoSigned, FormattedValueNoneBuilder, NoneSignedBuilder, UnsignedIntoSigned,
}; };
use glib::translate::*; use glib::translate::*;
use glib::StaticType; use glib::StaticType;
@ -175,48 +175,6 @@ impl<T: FormattedValueIntrinsic> FormattedSegment<T> {
} }
} }
#[doc(alias = "gst_segment_position_from_running_time")]
pub fn position_from_running_time(
&self,
running_time: impl CompatibleFormattedValue<T>,
) -> 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>,
) -> 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")] #[doc(alias = "gst_segment_set_running_time")]
pub fn set_running_time( pub fn set_running_time(
&mut self, &mut self,
@ -238,38 +196,6 @@ impl<T: FormattedValueIntrinsic> FormattedSegment<T> {
} }
} }
#[doc(alias = "gst_segment_to_running_time")]
pub fn to_running_time(&self, position: impl CompatibleFormattedValue<T>) -> 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>) -> 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")] #[doc(alias = "get_flags")]
pub fn flags(&self) -> crate::SegmentFlags { pub fn flags(&self) -> crate::SegmentFlags {
unsafe { from_glib(self.0.flags) } unsafe { from_glib(self.0.flags) }
@ -388,7 +314,100 @@ impl<T: FormattedValueIntrinsic> PartialEq for FormattedSegment<T> {
impl<T> FormattedSegment<T> impl<T> FormattedSegment<T>
where where
T: FormattedValueIntrinsic, T: FormattedValueIntrinsic,
<T as FormattedValue>::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>,
) -> 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>,
) -> 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>) -> 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>) -> 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<T> FormattedSegment<T>
where
T: FormattedValueIntrinsic,
T::FullRange: UnsignedIntoSigned,
T::FullRange: NoneSignedBuilder<Signed = <T::FullRange as UnsignedIntoSigned>::Signed>,
{ {
#[doc(alias = "gst_segment_position_from_running_time_full")] #[doc(alias = "gst_segment_position_from_running_time_full")]
pub fn position_from_running_time_full( pub fn position_from_running_time_full(
@ -398,6 +417,9 @@ where
let running_time = running_time let running_time = running_time
.try_into_checked_explicit(self.format()) .try_into_checked_explicit(self.format())
.unwrap(); .unwrap();
if running_time.is_none() {
return T::FullRange::none_signed_for_format(self.format());
}
unsafe { unsafe {
let mut position = mem::MaybeUninit::uninit(); let mut position = mem::MaybeUninit::uninit();
@ -420,6 +442,9 @@ where
let stream_time = stream_time let stream_time = stream_time
.try_into_checked_explicit(self.format()) .try_into_checked_explicit(self.format())
.unwrap(); .unwrap();
if stream_time.is_none() {
return T::FullRange::none_signed_for_format(self.format());
}
unsafe { unsafe {
let mut position = mem::MaybeUninit::uninit(); let mut position = mem::MaybeUninit::uninit();
@ -440,6 +465,9 @@ where
position: impl CompatibleFormattedValue<T>, position: impl CompatibleFormattedValue<T>,
) -> <T::FullRange as UnsignedIntoSigned>::Signed { ) -> <T::FullRange as UnsignedIntoSigned>::Signed {
let position = position.try_into_checked_explicit(self.format()).unwrap(); let position = position.try_into_checked_explicit(self.format()).unwrap();
if position.is_none() {
return T::FullRange::none_signed_for_format(self.format());
}
unsafe { unsafe {
let mut running_time = mem::MaybeUninit::uninit(); let mut running_time = mem::MaybeUninit::uninit();
@ -461,6 +489,9 @@ where
position: impl CompatibleFormattedValue<T>, position: impl CompatibleFormattedValue<T>,
) -> <T::FullRange as UnsignedIntoSigned>::Signed { ) -> <T::FullRange as UnsignedIntoSigned>::Signed {
let position = position.try_into_checked_explicit(self.format()).unwrap(); let position = position.try_into_checked_explicit(self.format()).unwrap();
if position.is_none() {
return T::FullRange::none_signed_for_format(self.format());
}
unsafe { unsafe {
let mut stream_time = mem::MaybeUninit::uninit(); let mut stream_time = mem::MaybeUninit::uninit();