gstreamer/format/
compatible.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use super::{
4    Format, FormattedValue, FormattedValueError, GenericFormattedValue, SpecificFormattedValue,
5};
6
7// rustdoc-stripper-ignore-next
8/// A trait implemented on types which can hold [`FormattedValue`]s compatible with parameter `F`.
9///
10/// This trait is auto-implemented based on [`FormattedValue`]s additional traits
11/// such as [`SpecificFormattedValue`].
12///
13/// # Example
14///
15/// Consider the following function:
16///
17/// ```rust
18/// # use gstreamer::format::{ClockTime, CompatibleFormattedValue, FormattedValue, GenericFormattedValue};
19/// fn with_compatible_formats<V: FormattedValue>(
20///     arg1: V,
21///     arg2: impl CompatibleFormattedValue<V>,
22/// ) {
23///     // This is required to access arg2 as a FormattedValue:
24///     let _arg2 = arg2.try_into_checked(arg1).unwrap();
25/// }
26///
27/// // This is Ok because arg1 is a ClockTime and arg2 is
28/// // an Option<ClockTime> which are compatible format-wise.
29/// with_compatible_formats(ClockTime::ZERO, ClockTime::NONE);
30///
31/// // This is Ok because arg1 is a ClockTime and arg2 is
32/// // a GenericFormattedValue which are compatible format-wise.
33/// with_compatible_formats(
34///     ClockTime::ZERO,
35///     GenericFormattedValue::Time(None),
36/// );
37/// ```
38///
39/// Users are able to call the function with arguments:
40///
41/// 1. of the same type (e.g. `ClockTime`),
42/// 2. of different types, but able to hold a value of the same [`Format`]
43///    (e.g. `ClockTime` and `Option<ClockTime>`).
44/// 3. One of a Formatted Value (specific or generic), the other being
45///    a `GenericFormattedValue`.
46///
47/// Format compatibility for cases 1 and 2 is enforced by
48/// the type system, while case 3 will be checked at runtime time.
49///
50/// ```compile_fail
51/// # use gstreamer::{ClockTime, CompatibleFormattedValue, FormattedValue, format::Bytes};
52/// # fn with_compatible_formats<V: FormattedValue>(
53/// #     arg1: V,
54/// #     arg2: impl CompatibleFormattedValue<V>,
55/// # ) {}
56/// // This doesn't compile because the arguments are not compatible:
57/// let _ = with_compatible_formats(ClockTime::ZERO, Bytes(Some(42)));
58/// ```
59///
60/// Note: users will not be able use `arg2` directly unless format
61/// check succeeds:
62///
63/// ```compile_fail
64/// # use gstreamer::{CompatibleFormattedValue, FormattedValue};
65/// fn with_compatible_formats<V: FormattedValue>(
66///     arg1: V,
67///     arg2: impl CompatibleFormattedValue<V>,
68/// ) {
69///     // This doesn't compile because arg2 hasn't been checked:
70///     let _format = arg2.format();
71/// }
72/// ```
73pub trait CompatibleFormattedValue<V: FormattedValue> {
74    type Original: FormattedValue;
75
76    // rustdoc-stripper-ignore-next
77    /// Returns `Ok(self)` with its type restored if it is compatible with the format of `other`.
78    ///
79    /// When used with compatible [`SpecificFormattedValue`]s, checks
80    /// are enforced by the type system, no runtime checks are performed.
81    ///
82    /// When used with [`FormattedValue`] / [`GenericFormattedValue`] and
83    /// vice versa, a runtime format check is performed. If the check fails,
84    /// `Err(FormattedValueError)` is returned.
85    fn try_into_checked(self, other: V) -> Result<Self::Original, FormattedValueError>;
86
87    // rustdoc-stripper-ignore-next
88    /// Returns `Ok(self)` with its type restored if it is compatible with the format of `V`.
89    ///
90    /// When possible, prefer using [`Self::try_into_checked`] which
91    /// reduces the risk of misuse.
92    ///
93    /// When used with compatible [`SpecificFormattedValue`]s, checks
94    /// are enforced by the type system, no runtime checks are performed.
95    ///
96    /// When used with [`SpecificFormattedValue`] as a parameter and
97    /// a [`GenericFormattedValue`] as `Self`, a runtime check is performed
98    /// against the default format of the parameter. If the check fails,
99    /// `Err(FormattedValueError)` is returned.
100    ///
101    /// When used with [`GenericFormattedValue`] as a parameter and
102    /// a [`SpecificFormattedValue`] as `Self`, the `format` argument
103    /// used. If the check fails, `Err(FormattedValueError)` is returned.
104    fn try_into_checked_explicit(
105        self,
106        format: Format,
107    ) -> Result<Self::Original, FormattedValueError>;
108}
109
110impl<T, V> CompatibleFormattedValue<V> for T
111where
112    V: SpecificFormattedValue,
113    T: SpecificFormattedValue<FullRange = V::FullRange>,
114{
115    type Original = Self;
116    #[inline]
117    fn try_into_checked(self, _other: V) -> Result<Self, FormattedValueError> {
118        skip_assert_initialized!();
119        Ok(self)
120    }
121
122    #[inline]
123    fn try_into_checked_explicit(
124        self,
125        _format: Format,
126    ) -> Result<Self::Original, FormattedValueError> {
127        skip_assert_initialized!();
128        Ok(self)
129    }
130}
131
132impl<T: SpecificFormattedValue> CompatibleFormattedValue<GenericFormattedValue> for T {
133    type Original = Self;
134    #[inline]
135    fn try_into_checked(self, other: GenericFormattedValue) -> Result<Self, FormattedValueError> {
136        skip_assert_initialized!();
137        if self.format() == other.format() {
138            Ok(self)
139        } else {
140            Err(FormattedValueError(self.format()))
141        }
142    }
143
144    #[inline]
145    fn try_into_checked_explicit(
146        self,
147        format: Format,
148    ) -> Result<Self::Original, FormattedValueError> {
149        skip_assert_initialized!();
150        if self.format() == format {
151            Ok(self)
152        } else {
153            Err(FormattedValueError(self.format()))
154        }
155    }
156}
157
158impl<V: SpecificFormattedValue> CompatibleFormattedValue<V> for GenericFormattedValue {
159    type Original = Self;
160    #[inline]
161    fn try_into_checked(self, _other: V) -> Result<Self, FormattedValueError> {
162        skip_assert_initialized!();
163        if self.format() == V::default_format() {
164            Ok(self)
165        } else {
166            Err(FormattedValueError(self.format()))
167        }
168    }
169
170    #[inline]
171    fn try_into_checked_explicit(
172        self,
173        _format: Format,
174    ) -> Result<Self::Original, FormattedValueError> {
175        skip_assert_initialized!();
176        if self.format() == V::default_format() {
177            Ok(self)
178        } else {
179            Err(FormattedValueError(self.format()))
180        }
181    }
182}