1 | // Take a look at the license at the top of the repository in the LICENSE file. |
2 | |
3 | use 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 | /// ``` |
73 | pub 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 | |
110 | impl<T, V> CompatibleFormattedValue<V> for T |
111 | where |
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 | |
132 | impl<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 | |
158 | impl<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 | |