From 274a5bd020b7db2f035c736859a292b39067453f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Laignel?= Date: Sat, 8 Oct 2022 23:27:45 +0200 Subject: [PATCH] gst/format: implement `GenericSignedFormattedValue` The `Signed` version for `GenericFormattedValue` was implemented as `Signed`, which failed to represent properly the `None` variants when applicable and could represent inconsistent `Signed` variant combined with `GenericFormattedValue` formats which are internaly represented as signed integers. --- gstreamer/src/format/generic.rs | 179 ++++++++++++++++++++++++++++++-- gstreamer/src/format/mod.rs | 46 ++++++-- 2 files changed, 208 insertions(+), 17 deletions(-) diff --git a/gstreamer/src/format/generic.rs b/gstreamer/src/format/generic.rs index d9d03b63e..f05095be8 100644 --- a/gstreamer/src/format/generic.rs +++ b/gstreamer/src/format/generic.rs @@ -72,7 +72,7 @@ impl fmt::Display for GenericFormattedValue { } impl Displayable for GenericFormattedValue { - type DisplayImpl = GenericFormattedValue; + type DisplayImpl = Self; fn display(self) -> Self { self } @@ -186,25 +186,37 @@ impl FormattedValueNoneBuilder for GenericFormattedValue { } impl UnsignedIntoSigned for GenericFormattedValue { - type Signed = Signed; + type Signed = GenericSignedFormattedValue; #[track_caller] fn into_positive(self) -> Self::Signed { + use Signed::Positive; match self { - GenericFormattedValue::Undefined(_) => { + Self::Undefined(_) => { unimplemented!("`GenericFormattedValue::Undefined` is already signed") } - unsigned_inner => Signed::Positive(unsigned_inner), + Self::Default(val) => Self::Signed::Default(val.map(Positive)), + Self::Bytes(val) => Self::Signed::Bytes(val.map(Positive)), + Self::Time(val) => Self::Signed::Time(val.map(Positive)), + Self::Buffers(val) => Self::Signed::Buffers(val.map(Positive)), + Self::Percent(val) => Self::Signed::Percent(val.map(Positive)), + Self::Other(format, val) => Self::Signed::Other(format, val.map(Positive)), } } #[track_caller] fn into_negative(self) -> Self::Signed { + use Signed::Negative; match self { - GenericFormattedValue::Undefined(_) => { + Self::Undefined(_) => { unimplemented!("`GenericFormattedValue::Undefined` is already signed") } - unsigned_inner => Signed::Negative(unsigned_inner), + Self::Default(val) => Self::Signed::Default(val.map(Negative)), + Self::Bytes(val) => Self::Signed::Bytes(val.map(Negative)), + Self::Time(val) => Self::Signed::Time(val.map(Negative)), + Self::Buffers(val) => Self::Signed::Buffers(val.map(Negative)), + Self::Percent(val) => Self::Signed::Percent(val.map(Negative)), + Self::Other(format, val) => Self::Signed::Other(format, val.map(Negative)), } } } @@ -233,6 +245,136 @@ impl CompatibleFormattedValue for GenericFormattedValue { } } +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum GenericSignedFormattedValue { + Default(Option>), + Bytes(Option>), + Time(Option>), + Buffers(Option>), + Percent(Option>), + Other(Format, Option>), +} + +impl GenericSignedFormattedValue { + #[doc(alias = "get_format")] + pub fn format(&self) -> Format { + match *self { + Self::Default(_) => Format::Default, + Self::Bytes(_) => Format::Bytes, + Self::Time(_) => Format::Time, + Self::Buffers(_) => Format::Buffers, + Self::Percent(_) => Format::Percent, + Self::Other(format, _) => format, + } + } + + pub fn abs(self) -> GenericFormattedValue { + use GenericFormattedValue as Unsigned; + match self { + Self::Default(opt_signed) => Unsigned::Default(opt_signed.map(Signed::abs)), + Self::Bytes(opt_signed) => Unsigned::Bytes(opt_signed.map(Signed::abs)), + Self::Time(opt_signed) => Unsigned::Time(opt_signed.map(Signed::abs)), + Self::Buffers(opt_signed) => Unsigned::Buffers(opt_signed.map(Signed::abs)), + Self::Percent(opt_signed) => Unsigned::Percent(opt_signed.map(Signed::abs)), + Self::Other(format, opt_signed) => Unsigned::Other(format, opt_signed.map(Signed::abs)), + } + } + + pub fn is_some(&self) -> bool { + match self { + 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(_, v) => v.is_some(), + } + } + + pub fn is_none(&self) -> bool { + !self.is_some() + } + + #[track_caller] + pub fn none_for_format(format: Format) -> Self { + skip_assert_initialized!(); + match format { + 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::Undefined => { + panic!("`Undefined` is already signed, use `GenericFormattedValue`") + } + other => Self::Other(other, None), + } + } +} + +macro_rules! impl_gsfv_fn_opt_ret( + ($fn:ident(self) -> Option<$ret_ty:ty>) => { + pub fn $fn(self) -> Option<$ret_ty> { + match self { + Self::Default(opt_signed) => opt_signed.map(|signed| signed.$fn()), + Self::Bytes(opt_signed) => opt_signed.map(|signed| signed.$fn()), + Self::Time(opt_signed) => opt_signed.map(|signed| signed.$fn()), + Self::Buffers(opt_signed) => opt_signed.map(|signed| signed.$fn()), + Self::Percent(opt_signed) => opt_signed.map(|signed| signed.$fn()), + Self::Other(_, opt_signed) => opt_signed.map(|signed| signed.$fn()), + } + } + }; +); + +impl GenericSignedFormattedValue { + impl_gsfv_fn_opt_ret!(is_positive(self) -> Option); + impl_gsfv_fn_opt_ret!(is_negative(self) -> Option); + impl_gsfv_fn_opt_ret!(signum(self) -> Option); +} + +impl std::ops::Neg for GenericSignedFormattedValue { + type Output = Self; + + fn neg(self) -> Self { + use std::ops::Neg; + match self { + Self::Default(opt_signed) => Self::Default(opt_signed.map(Neg::neg)), + Self::Bytes(opt_signed) => Self::Bytes(opt_signed.map(Neg::neg)), + Self::Time(opt_signed) => Self::Time(opt_signed.map(Neg::neg)), + Self::Buffers(opt_signed) => Self::Buffers(opt_signed.map(Neg::neg)), + Self::Percent(opt_signed) => Self::Percent(opt_signed.map(Neg::neg)), + Self::Other(format, opt_signed) => Self::Other(format, opt_signed.map(Neg::neg)), + } + } +} + +impl fmt::Display for GenericSignedFormattedValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Default(opt_signed) => opt_signed.display().fmt(f), + Self::Bytes(opt_signed) => opt_signed.display().fmt(f), + Self::Time(opt_signed) => opt_signed.display().fmt(f), + Self::Buffers(opt_signed) => opt_signed.display().fmt(f), + Self::Percent(opt_signed) => opt_signed.display().fmt(f), + Self::Other(format, opt_signed) => { + opt_signed.display().fmt(f)?; + fmt::Write::write_char(f, ' ')?; + fmt::Display::fmt(&format, f) + } + } + } +} + +impl Displayable for GenericSignedFormattedValue { + type DisplayImpl = Self; + + fn display(self) -> Self::DisplayImpl { + self + } +} + #[cfg(test)] mod tests { use super::*; @@ -284,4 +426,29 @@ mod tests { GenericFormattedValue::Other(Format::__Unknown(128), None) ); } + + #[test] + #[allow(clippy::eq_op, clippy::op_ref)] + fn generic_signed_other() { + let gen_other_42: GenericFormattedValue = + GenericFormattedValue::new(Format::__Unknown(128), 42); + + let p_gen_other_42 = gen_other_42.into_positive(); + assert_eq!( + p_gen_other_42, + GenericSignedFormattedValue::Other( + Format::__Unknown(128), + Some(Signed::Positive(Other(42))), + ), + ); + + let n_gen_other_42 = gen_other_42.into_negative(); + assert_eq!( + n_gen_other_42, + GenericSignedFormattedValue::Other( + Format::__Unknown(128), + Some(Signed::Negative(Other(42))), + ), + ); + } } diff --git a/gstreamer/src/format/mod.rs b/gstreamer/src/format/mod.rs index b2b382dc3..def950989 100644 --- a/gstreamer/src/format/mod.rs +++ b/gstreamer/src/format/mod.rs @@ -684,7 +684,7 @@ mod tests { Option::::none_signed_for_format(Format::Time); assert!(ct_none.is_none()); - let gen_ct_none: Signed = + let gen_ct_none: GenericSignedFormattedValue = GenericFormattedValue::none_signed_for_format(Format::Time); assert!(gen_ct_none.abs().is_none()); } @@ -775,25 +775,49 @@ mod tests { assert!(ct_1.is_some()); let signed = ct_1.into_positive(); - assert_eq!(signed, Signed::Positive(ct_1)); - assert!(signed.is_positive()); - assert_eq!(signed.positive(), Some(ct_1)); + assert_eq!( + signed, + GenericSignedFormattedValue::Time(Some(Signed::Positive(ClockTime::SECOND))), + ); + assert_eq!(signed.is_positive(), Some(true)); + assert_eq!(signed.is_negative(), Some(false)); + assert_eq!(signed.signum(), Some(1)); let signed = ct_1.into_negative(); - assert_eq!(signed, Signed::Negative(ct_1)); - assert!(signed.is_negative()); - assert_eq!(signed.negative(), Some(ct_1)); + assert_eq!( + signed, + GenericSignedFormattedValue::Time(Some(Signed::Negative(ClockTime::SECOND))), + ); + assert_eq!(signed.is_negative(), Some(true)); + assert_eq!(signed.is_positive(), Some(false)); + assert_eq!(signed.signum(), Some(-1)); let ct_none = GenericFormattedValue::Time(ClockTime::NONE); assert!(ct_none.is_none()); let signed = ct_none.into_positive(); - assert_eq!(signed, Signed::Positive(ct_none)); - assert!(signed.is_positive()); + assert_eq!(signed, GenericSignedFormattedValue::Time(None),); + assert!(signed.is_positive().is_none()); + assert!(signed.is_negative().is_none()); + assert!(signed.signum().is_none()); let signed = ct_none.into_negative(); - assert_eq!(signed, Signed::Negative(ct_none)); - assert!(signed.is_negative()); + assert_eq!(signed, GenericSignedFormattedValue::Time(None),); + assert!(signed.is_negative().is_none()); + assert!(signed.is_positive().is_none()); + assert!(signed.signum().is_none()); + + let ct_zero = GenericFormattedValue::Time(Some(ClockTime::ZERO)); + assert!(ct_zero.is_some()); + + let signed = ct_zero.into_positive(); + assert_eq!( + signed, + GenericSignedFormattedValue::Time(Some(Signed::Positive(ClockTime::ZERO))), + ); + assert_eq!(signed.is_positive(), Some(true)); + assert_eq!(signed.is_negative(), Some(false)); + assert_eq!(signed.signum(), Some(0)); } #[test]