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}
183