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