Skip to main content

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