gstreamer/format/
generic.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::fmt;
4
5use glib::translate::{FromGlib, GlibNoneError, IntoGlib, OptionIntoGlib, TryFromGlib};
6
7use super::{
8    Buffers, Bytes, ClockTime, CompatibleFormattedValue, Default, Format, FormattedValue,
9    FormattedValueError, FormattedValueFullRange, FormattedValueIntrinsic,
10    FormattedValueNoneBuilder, Percent, Signed, SignedIntrinsic, Undefined, UnsignedIntoSigned,
11};
12use crate::utils::Displayable;
13
14#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)]
15pub struct Other(u64);
16impl Other {
17    pub const MAX: Self = Self(u64::MAX - 1);
18}
19
20impl Other {
21    // rustdoc-stripper-ignore-next
22    /// Builds a new `Other` value with the provided quantity.
23    ///
24    /// # Panics
25    ///
26    /// Panics if the provided quantity equals `u64::MAX`,
27    /// which is reserved for `None` in C.
28    #[track_caller]
29    #[inline]
30    pub const fn from_u64(quantity: u64) -> Self {
31        if quantity == u64::MAX {
32            panic!("`Other` value out of range");
33        }
34
35        Other(quantity)
36    }
37
38    // rustdoc-stripper-ignore-next
39    /// Builds a new `Other` value with the provided quantity.
40    ///
41    /// # Panics
42    ///
43    /// Panics if the provided quantity equals `u64::MAX`,
44    /// which is reserved for `None` in C.
45    #[track_caller]
46    #[inline]
47    pub fn from_usize(quantity: usize) -> Self {
48        // FIXME can't use `try_into` in `const` (rustc 1.64.0)
49        Other::from_u64(quantity.try_into().unwrap())
50    }
51}
52
53impl_common_ops_for_newtype_uint!(Other, u64);
54impl_signed_div_mul!(Other, u64);
55impl_signed_int_into_signed!(Other, u64);
56option_glib_newtype_from_to!(Other, u64::MAX);
57glib_newtype_display!(Other, DisplayableOptionOther);
58
59impl TryFrom<u64> for Other {
60    type Error = GlibNoneError;
61    #[inline]
62    fn try_from(val: u64) -> Result<Self, GlibNoneError> {
63        skip_assert_initialized!();
64        unsafe { Self::try_from_glib(val) }
65    }
66}
67
68impl TryFromGlib<i64> for Other {
69    type Error = GlibNoneError;
70    #[inline]
71    unsafe fn try_from_glib(val: i64) -> Result<Self, GlibNoneError> {
72        skip_assert_initialized!();
73        Self::try_from_glib(val as u64)
74    }
75}
76
77impl TryFrom<Other> for usize {
78    type Error = std::num::TryFromIntError;
79
80    fn try_from(value: Other) -> Result<Self, Self::Error> {
81        value.0.try_into()
82    }
83}
84
85// FIXME `functions in traits cannot be const` (rustc 1.64.0)
86// rustdoc-stripper-ignore-next
87/// `Other` formatted value constructor trait.
88pub trait OtherFormatConstructor {
89    // rustdoc-stripper-ignore-next
90    /// Builds an `Other` formatted value from `self`.
91    fn other_format(self) -> Other;
92}
93
94impl OtherFormatConstructor for u64 {
95    #[track_caller]
96    #[inline]
97    fn other_format(self) -> Other {
98        Other::from_u64(self)
99    }
100}
101
102#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
103#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
104pub enum GenericFormattedValue {
105    Undefined(Undefined),
106    Default(Option<Default>),
107    Bytes(Option<Bytes>),
108    Time(Option<ClockTime>),
109    Buffers(Option<Buffers>),
110    Percent(Option<Percent>),
111    Other(Format, Option<Other>),
112}
113
114impl fmt::Display for GenericFormattedValue {
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        match self {
117            Self::Undefined(val) => val.fmt(f),
118            Self::Default(val) => val.display().fmt(f),
119            Self::Bytes(val) => val.display().fmt(f),
120            Self::Time(val) => val.display().fmt(f),
121            Self::Buffers(val) => val.display().fmt(f),
122            Self::Percent(val) => val.display().fmt(f),
123            Self::Other(format, val) => {
124                val.display().fmt(f)?;
125                fmt::Write::write_char(f, ' ')?;
126                fmt::Display::fmt(&format, f)
127            }
128        }
129    }
130}
131
132impl Displayable for GenericFormattedValue {
133    type DisplayImpl = Self;
134    fn display(self) -> Self {
135        self
136    }
137}
138
139impl GenericFormattedValue {
140    #[inline]
141    pub fn new(format: Format, value: i64) -> Self {
142        skip_assert_initialized!();
143        match format {
144            Format::Undefined => Self::Undefined(value.into()),
145            Format::Default => Self::Default(unsafe { FromGlib::from_glib(value) }),
146            Format::Bytes => Self::Bytes(unsafe { FromGlib::from_glib(value) }),
147            Format::Time => Self::Time(unsafe { FromGlib::from_glib(value) }),
148            Format::Buffers => Self::Buffers(unsafe { FromGlib::from_glib(value) }),
149            Format::Percent => Self::Percent(unsafe { FromGlib::from_glib(value) }),
150            Format::__Unknown(_) => Self::Other(format, unsafe { FromGlib::from_glib(value) }),
151        }
152    }
153
154    #[doc(alias = "get_format")]
155    #[inline]
156    pub fn format(&self) -> Format {
157        match *self {
158            Self::Undefined(_) => Format::Undefined,
159            Self::Default(_) => Format::Default,
160            Self::Bytes(_) => Format::Bytes,
161            Self::Time(_) => Format::Time,
162            Self::Buffers(_) => Format::Buffers,
163            Self::Percent(_) => Format::Percent,
164            Self::Other(f, _) => f,
165        }
166    }
167
168    #[doc(alias = "get_value")]
169    #[inline]
170    pub fn value(&self) -> i64 {
171        unsafe {
172            match *self {
173                Self::Undefined(v) => *v,
174                Self::Default(v) => v.into_raw_value(),
175                Self::Bytes(v) => v.into_raw_value(),
176                Self::Time(v) => v.into_raw_value(),
177                Self::Buffers(v) => v.into_raw_value(),
178                Self::Percent(v) => v.into_raw_value(),
179                Self::Other(_, v) => v.into_glib() as i64,
180            }
181        }
182    }
183}
184
185impl FormattedValue for GenericFormattedValue {
186    // The intrinsic value for `GenericFormattedValue` is also
187    // `GenericFormattedValue`. We can't dissociate the `Option`
188    // from the variants' inner type since they are not all `Option`s.
189    type FullRange = GenericFormattedValue;
190
191    #[inline]
192    fn default_format() -> Format {
193        Format::Undefined
194    }
195
196    #[inline]
197    fn format(&self) -> Format {
198        self.format()
199    }
200
201    #[inline]
202    fn is_some(&self) -> bool {
203        match self {
204            Self::Undefined(_) => true,
205            Self::Default(v) => v.is_some(),
206            Self::Bytes(v) => v.is_some(),
207            Self::Time(v) => v.is_some(),
208            Self::Buffers(v) => v.is_some(),
209            Self::Percent(v) => v.is_some(),
210            Self::Other(_, v) => v.is_some(),
211        }
212    }
213
214    #[inline]
215    unsafe fn into_raw_value(self) -> i64 {
216        self.value()
217    }
218}
219
220impl FormattedValueFullRange for GenericFormattedValue {
221    #[inline]
222    unsafe fn from_raw(format: Format, value: i64) -> Self {
223        GenericFormattedValue::new(format, value)
224    }
225}
226
227impl FormattedValueIntrinsic for GenericFormattedValue {}
228impl SignedIntrinsic for GenericFormattedValue {}
229
230impl FormattedValueNoneBuilder for GenericFormattedValue {
231    #[track_caller]
232    fn none() -> Self {
233        panic!(concat!(
234            "`GenericFormattedValue` can't build `None` without knowing",
235            "the target format. Use `GenericFormattedValue::none_for_format`",
236        ));
237    }
238
239    #[track_caller]
240    #[inline]
241    fn none_for_format(format: Format) -> Self {
242        skip_assert_initialized!();
243        match format {
244            Format::Undefined => panic!("`None` can't be represented by `Undefined`"),
245            Format::Default => Self::Default(None),
246            Format::Bytes => Self::Bytes(None),
247            Format::Time => Self::Time(None),
248            Format::Buffers => Self::Buffers(None),
249            Format::Percent => Self::Percent(None),
250            unknown => Self::Other(unknown, Other::NONE),
251        }
252    }
253}
254
255impl UnsignedIntoSigned for GenericFormattedValue {
256    type Signed = GenericSignedFormattedValue;
257
258    #[track_caller]
259    #[inline]
260    fn into_positive(self) -> Self::Signed {
261        use Signed::Positive;
262        match self {
263            Self::Undefined(_) => {
264                unimplemented!("`GenericFormattedValue::Undefined` is already signed")
265            }
266            Self::Default(val) => Self::Signed::Default(val.map(Positive)),
267            Self::Bytes(val) => Self::Signed::Bytes(val.map(Positive)),
268            Self::Time(val) => Self::Signed::Time(val.map(Positive)),
269            Self::Buffers(val) => Self::Signed::Buffers(val.map(Positive)),
270            Self::Percent(val) => Self::Signed::Percent(val.map(Positive)),
271            Self::Other(format, val) => Self::Signed::Other(format, val.map(Positive)),
272        }
273    }
274
275    #[track_caller]
276    #[inline]
277    fn into_negative(self) -> Self::Signed {
278        use Signed::Negative;
279        match self {
280            Self::Undefined(_) => {
281                unimplemented!("`GenericFormattedValue::Undefined` is already signed")
282            }
283            Self::Default(val) => Self::Signed::Default(val.map(Negative)),
284            Self::Bytes(val) => Self::Signed::Bytes(val.map(Negative)),
285            Self::Time(val) => Self::Signed::Time(val.map(Negative)),
286            Self::Buffers(val) => Self::Signed::Buffers(val.map(Negative)),
287            Self::Percent(val) => Self::Signed::Percent(val.map(Negative)),
288            Self::Other(format, val) => Self::Signed::Other(format, val.map(Negative)),
289        }
290    }
291}
292
293impl CompatibleFormattedValue<GenericFormattedValue> for GenericFormattedValue {
294    type Original = Self;
295    #[inline]
296    fn try_into_checked(self, other: GenericFormattedValue) -> Result<Self, FormattedValueError> {
297        skip_assert_initialized!();
298        if self.format() == other.format() {
299            Ok(self)
300        } else {
301            Err(FormattedValueError(self.format()))
302        }
303    }
304
305    #[inline]
306    fn try_into_checked_explicit(
307        self,
308        format: Format,
309    ) -> Result<Self::Original, FormattedValueError> {
310        skip_assert_initialized!();
311        if self.format() == format {
312            Ok(self)
313        } else {
314            Err(FormattedValueError(self.format()))
315        }
316    }
317}
318
319#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
320#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
321pub enum GenericSignedFormattedValue {
322    Default(Option<Signed<Default>>),
323    Bytes(Option<Signed<Bytes>>),
324    Time(Option<Signed<ClockTime>>),
325    Buffers(Option<Signed<Buffers>>),
326    Percent(Option<Signed<Percent>>),
327    Other(Format, Option<Signed<Other>>),
328}
329
330impl GenericSignedFormattedValue {
331    #[doc(alias = "get_format")]
332    #[inline]
333    pub fn format(&self) -> Format {
334        match *self {
335            Self::Default(_) => Format::Default,
336            Self::Bytes(_) => Format::Bytes,
337            Self::Time(_) => Format::Time,
338            Self::Buffers(_) => Format::Buffers,
339            Self::Percent(_) => Format::Percent,
340            Self::Other(format, _) => format,
341        }
342    }
343
344    #[inline]
345    pub fn abs(self) -> GenericFormattedValue {
346        use GenericFormattedValue as Unsigned;
347        match self {
348            Self::Default(opt_signed) => Unsigned::Default(opt_signed.map(Signed::abs)),
349            Self::Bytes(opt_signed) => Unsigned::Bytes(opt_signed.map(Signed::abs)),
350            Self::Time(opt_signed) => Unsigned::Time(opt_signed.map(Signed::abs)),
351            Self::Buffers(opt_signed) => Unsigned::Buffers(opt_signed.map(Signed::abs)),
352            Self::Percent(opt_signed) => Unsigned::Percent(opt_signed.map(Signed::abs)),
353            Self::Other(format, opt_signed) => Unsigned::Other(format, opt_signed.map(Signed::abs)),
354        }
355    }
356
357    #[inline]
358    pub fn is_some(&self) -> bool {
359        match self {
360            Self::Default(v) => v.is_some(),
361            Self::Bytes(v) => v.is_some(),
362            Self::Time(v) => v.is_some(),
363            Self::Buffers(v) => v.is_some(),
364            Self::Percent(v) => v.is_some(),
365            Self::Other(_, v) => v.is_some(),
366        }
367    }
368
369    #[inline]
370    pub fn is_none(&self) -> bool {
371        !self.is_some()
372    }
373
374    #[track_caller]
375    #[inline]
376    pub fn none_for_format(format: Format) -> Self {
377        skip_assert_initialized!();
378        match format {
379            Format::Default => Self::Default(None),
380            Format::Bytes => Self::Bytes(None),
381            Format::Time => Self::Time(None),
382            Format::Buffers => Self::Buffers(None),
383            Format::Percent => Self::Percent(None),
384            Format::Undefined => {
385                panic!("`Undefined` is already signed, use `GenericFormattedValue`")
386            }
387            other => Self::Other(other, None),
388        }
389    }
390}
391
392macro_rules! impl_gsfv_fn_opt_ret(
393    ($fn:ident(self) -> Option<$ret_ty:ty>) => {
394        #[inline]
395        pub fn $fn(self) -> Option<$ret_ty> {
396            match self {
397                Self::Default(opt_signed) => opt_signed.map(|signed| signed.$fn()),
398                Self::Bytes(opt_signed) => opt_signed.map(|signed| signed.$fn()),
399                Self::Time(opt_signed) => opt_signed.map(|signed| signed.$fn()),
400                Self::Buffers(opt_signed) => opt_signed.map(|signed| signed.$fn()),
401                Self::Percent(opt_signed) => opt_signed.map(|signed| signed.$fn()),
402                Self::Other(_, opt_signed) => opt_signed.map(|signed| signed.$fn()),
403            }
404        }
405    };
406);
407
408impl GenericSignedFormattedValue {
409    impl_gsfv_fn_opt_ret!(is_positive(self) -> Option<bool>);
410    impl_gsfv_fn_opt_ret!(is_negative(self) -> Option<bool>);
411    impl_gsfv_fn_opt_ret!(signum(self) -> Option<i32>);
412}
413
414impl std::ops::Neg for GenericSignedFormattedValue {
415    type Output = Self;
416
417    #[inline]
418    fn neg(self) -> Self {
419        use std::ops::Neg;
420        match self {
421            Self::Default(opt_signed) => Self::Default(opt_signed.map(Neg::neg)),
422            Self::Bytes(opt_signed) => Self::Bytes(opt_signed.map(Neg::neg)),
423            Self::Time(opt_signed) => Self::Time(opt_signed.map(Neg::neg)),
424            Self::Buffers(opt_signed) => Self::Buffers(opt_signed.map(Neg::neg)),
425            Self::Percent(opt_signed) => Self::Percent(opt_signed.map(Neg::neg)),
426            Self::Other(format, opt_signed) => Self::Other(format, opt_signed.map(Neg::neg)),
427        }
428    }
429}
430
431impl fmt::Display for GenericSignedFormattedValue {
432    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
433        match self {
434            Self::Default(opt_signed) => opt_signed.display().fmt(f),
435            Self::Bytes(opt_signed) => opt_signed.display().fmt(f),
436            Self::Time(opt_signed) => opt_signed.display().fmt(f),
437            Self::Buffers(opt_signed) => opt_signed.display().fmt(f),
438            Self::Percent(opt_signed) => opt_signed.display().fmt(f),
439            Self::Other(format, opt_signed) => {
440                opt_signed.display().fmt(f)?;
441                fmt::Write::write_char(f, ' ')?;
442                fmt::Display::fmt(&format, f)
443            }
444        }
445    }
446}
447
448impl Displayable for GenericSignedFormattedValue {
449    type DisplayImpl = Self;
450
451    fn display(self) -> Self::DisplayImpl {
452        self
453    }
454}
455
456#[cfg(test)]
457mod tests {
458    use super::*;
459
460    #[test]
461    #[allow(clippy::eq_op, clippy::op_ref)]
462    fn other() {
463        // Check a few ops on `Other`, better coverage for
464        // the macro ops impl ensured as part of the `clock_time` module.
465
466        use opt_ops::prelude::*;
467
468        let other_none: Option<Other> = Other::try_from(u64::MAX).ok();
469        assert!(other_none.is_none());
470
471        let other_10 = Other::from_u64(10);
472        let other_20 = Other::from_usize(20);
473        let other_30 = 30.other_format();
474
475        assert_eq!(other_10 + other_20, other_30);
476        assert_eq!(other_30 - other_20, other_10);
477
478        assert!(other_10 < Other::MAX);
479
480        assert_eq!(Some(other_10).opt_add(other_20), Some(other_30));
481    }
482
483    #[test]
484    #[allow(clippy::eq_op, clippy::op_ref)]
485    fn generic_other() {
486        let gen_other_42: GenericFormattedValue =
487            GenericFormattedValue::new(Format::__Unknown(128), 42);
488        assert_eq!(
489            gen_other_42,
490            GenericFormattedValue::Other(Format::__Unknown(128), Other::try_from(42).ok())
491        );
492        assert_eq!(gen_other_42.format(), Format::__Unknown(128));
493        assert_eq!(gen_other_42.value(), 42);
494        assert!(gen_other_42.is_some());
495
496        let other_none: Option<Other> = Other::NONE;
497        assert!(other_none.is_none());
498
499        let gen_other_none: GenericFormattedValue =
500            GenericFormattedValue::none_for_format(Format::__Unknown(128));
501        assert!(gen_other_none.is_none());
502        assert_eq!(
503            gen_other_none,
504            GenericFormattedValue::Other(Format::__Unknown(128), None)
505        );
506    }
507
508    #[test]
509    #[allow(clippy::eq_op, clippy::op_ref)]
510    fn generic_signed_other() {
511        let gen_other_42: GenericFormattedValue =
512            GenericFormattedValue::new(Format::__Unknown(128), 42);
513
514        let p_gen_other_42 = gen_other_42.into_positive();
515        assert_eq!(
516            p_gen_other_42,
517            GenericSignedFormattedValue::Other(
518                Format::__Unknown(128),
519                Some(Signed::Positive(42.other_format())),
520            ),
521        );
522
523        let n_gen_other_42 = gen_other_42.into_negative();
524        assert_eq!(
525            n_gen_other_42,
526            GenericSignedFormattedValue::Other(
527                Format::__Unknown(128),
528                Some(Signed::Negative(42.other_format())),
529            ),
530        );
531    }
532}