1 #[cfg(feature = "serde")]
2 use serde::{Deserialize, Serialize};
3 
4 use crate::MediaTrackConstraintResolutionStrategy;
5 
6 /// A bare value or constraint specifying a sequence of accepted values.
7 ///
8 /// # W3C Spec Compliance
9 ///
10 /// There exists no direct corresponding type in the
11 /// W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec,
12 /// since the `BareOrValueConstraint<T>` type aims to be a generalization over
13 /// multiple types in the spec.
14 ///
15 /// | Rust                                     | W3C                                          |
16 /// | ---------------------------------------- | -------------------------------------------- |
17 /// | `BareOrValueSequenceConstraint<String>` | [`ConstrainDOMString`][constrain_dom_string] |
18 ///
19 /// [constrain_dom_string]: https://www.w3.org/TR/mediacapture-streams/#dom-constraindomstring
20 /// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/
21 #[derive(Debug, Clone, Eq, PartialEq)]
22 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23 #[cfg_attr(feature = "serde", serde(untagged))]
24 pub enum BareOrValueSequenceConstraint<T> {
25     Bare(Vec<T>),
26     Constraint(ValueSequenceConstraint<T>),
27 }
28 
29 impl<T> Default for BareOrValueSequenceConstraint<T> {
30     fn default() -> Self {
31         Self::Constraint(Default::default())
32     }
33 }
34 
35 impl<T> From<T> for BareOrValueSequenceConstraint<T> {
36     fn from(bare: T) -> Self {
37         Self::Bare(vec![bare])
38     }
39 }
40 
41 impl<T> From<Vec<T>> for BareOrValueSequenceConstraint<T> {
42     fn from(bare: Vec<T>) -> Self {
43         Self::Bare(bare)
44     }
45 }
46 
47 impl<T> From<ValueSequenceConstraint<T>> for BareOrValueSequenceConstraint<T> {
48     fn from(constraint: ValueSequenceConstraint<T>) -> Self {
49         Self::Constraint(constraint)
50     }
51 }
52 
53 impl<T> BareOrValueSequenceConstraint<T>
54 where
55     T: Clone,
56 {
57     pub fn to_resolved(
58         &self,
59         strategy: MediaTrackConstraintResolutionStrategy,
60     ) -> ValueSequenceConstraint<T> {
61         self.clone().into_resolved(strategy)
62     }
63 
64     pub fn into_resolved(
65         self,
66         strategy: MediaTrackConstraintResolutionStrategy,
67     ) -> ValueSequenceConstraint<T> {
68         match self {
69             Self::Bare(bare) => match strategy {
70                 MediaTrackConstraintResolutionStrategy::BareToIdeal => {
71                     ValueSequenceConstraint::default().ideal(bare)
72                 }
73                 MediaTrackConstraintResolutionStrategy::BareToExact => {
74                     ValueSequenceConstraint::default().exact(bare)
75                 }
76             },
77             Self::Constraint(constraint) => constraint,
78         }
79     }
80 }
81 
82 impl<T> BareOrValueSequenceConstraint<T> {
83     pub fn is_empty(&self) -> bool {
84         match self {
85             Self::Bare(bare) => bare.is_empty(),
86             Self::Constraint(constraint) => constraint.is_empty(),
87         }
88     }
89 }
90 
91 /// A constraint specifying a sequence of accepted values.
92 ///
93 /// # W3C Spec Compliance
94 ///
95 /// There exists no direct corresponding type in the
96 /// W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec,
97 /// since the `BareOrValueSequenceConstraint<T>` type aims to be a
98 /// generalization over multiple types in the W3C spec:
99 ///
100 /// | Rust                              | W3C                                                               |
101 /// | --------------------------------- | ----------------------------------------------------------------- |
102 /// | `ValueSequenceConstraint<String>` | [`ConstrainDOMStringParameters`][constrain_dom_string_parameters] |
103 ///
104 /// [constrain_dom_string_parameters]: https://www.w3.org/TR/mediacapture-streams/#dom-constraindomstringparameters
105 /// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/
106 #[derive(Debug, Clone, Eq, PartialEq)]
107 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
108 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
109 pub struct ValueSequenceConstraint<T> {
110     // See https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#constraindomstring
111     #[cfg_attr(
112         feature = "serde",
113         serde(skip_serializing_if = "core::option::Option::is_none")
114     )]
115     pub exact: Option<Vec<T>>,
116     #[cfg_attr(
117         feature = "serde",
118         serde(skip_serializing_if = "core::option::Option::is_none")
119     )]
120     pub ideal: Option<Vec<T>>,
121 }
122 
123 impl<T> ValueSequenceConstraint<T> {
124     #[inline]
125     pub fn exact<U>(mut self, exact: U) -> Self
126     where
127         Option<Vec<T>>: From<U>,
128     {
129         self.exact = exact.into();
130         self
131     }
132 
133     #[inline]
134     pub fn ideal<U>(mut self, ideal: U) -> Self
135     where
136         Option<Vec<T>>: From<U>,
137     {
138         self.ideal = ideal.into();
139         self
140     }
141 
142     pub fn is_required(&self) -> bool {
143         self.exact.is_some()
144     }
145 
146     pub fn is_empty(&self) -> bool {
147         let exact_is_empty = self.exact.as_ref().map_or(true, Vec::is_empty);
148         let ideal_is_empty = self.ideal.as_ref().map_or(true, Vec::is_empty);
149         exact_is_empty && ideal_is_empty
150     }
151 
152     pub fn to_required_only(&self) -> Self
153     where
154         T: Clone,
155     {
156         self.clone().into_required_only()
157     }
158 
159     pub fn into_required_only(self) -> Self {
160         Self {
161             exact: self.exact,
162             ideal: None,
163         }
164     }
165 }
166 
167 impl<T> Default for ValueSequenceConstraint<T> {
168     fn default() -> Self {
169         Self {
170             exact: None,
171             ideal: None,
172         }
173     }
174 }
175 
176 impl<T> std::fmt::Display for ValueSequenceConstraint<T>
177 where
178     T: std::fmt::Debug,
179 {
180     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
181         let mut is_first = true;
182         f.write_str("(")?;
183         if let Some(ref exact) = &self.exact {
184             f.write_fmt(format_args!("x == {:?}", exact))?;
185             is_first = false;
186         }
187         if let Some(ref ideal) = &self.ideal {
188             if !is_first {
189                 f.write_str(" && ")?;
190             }
191             f.write_fmt(format_args!("x ~= {:?}", ideal))?;
192             is_first = false;
193         }
194         if is_first {
195             f.write_str("<empty>")?;
196         }
197         f.write_str(")")?;
198         Ok(())
199     }
200 }
201 
202 #[cfg(test)]
203 mod tests {
204     use super::*;
205 
206     #[test]
207     fn resolve_to_advanced() {
208         let constraint = BareOrValueSequenceConstraint::Bare(vec![true]);
209         let strategy = MediaTrackConstraintResolutionStrategy::BareToExact;
210         let actual: ValueSequenceConstraint<bool> = constraint.into_resolved(strategy);
211         let expected = ValueSequenceConstraint::default().exact(vec![true]);
212 
213         assert_eq!(actual, expected);
214     }
215 
216     #[test]
217     fn resolve_to_basic() {
218         let constraint = BareOrValueSequenceConstraint::Bare(vec![true]);
219         let strategy = MediaTrackConstraintResolutionStrategy::BareToIdeal;
220         let actual: ValueSequenceConstraint<bool> = constraint.into_resolved(strategy);
221         let expected = ValueSequenceConstraint::default().ideal(vec![true]);
222 
223         assert_eq!(actual, expected);
224     }
225 }
226 
227 #[cfg(feature = "serde")]
228 #[cfg(test)]
229 mod serde_tests {
230     use crate::macros::test_serde_symmetry;
231 
232     use super::*;
233 
234     macro_rules! test_serde {
235         ($t:ty => {
236             values: [$($values:expr),*]
237         }) => {
238             type Subject = BareOrValueSequenceConstraint<$t>;
239 
240             #[test]
241             fn default() {
242                 let subject = Subject::default();
243                 let json = serde_json::json!({});
244 
245                 test_serde_symmetry!(subject: subject, json: json);
246             }
247 
248             #[test]
249             fn bare() {
250                 let subject = Subject::Bare(vec![$($values.to_owned()),*].into());
251                 let json = serde_json::json!([$($values),*]);
252 
253                 test_serde_symmetry!(subject: subject, json: json);
254             }
255 
256             #[test]
257             fn exact_constraint() {
258                 let subject = Subject::Constraint(ValueSequenceConstraint::default().exact(vec![$($values.to_owned()),*]));
259                 let json = serde_json::json!({
260                     "exact": [$($values),*],
261                 });
262 
263                 test_serde_symmetry!(subject: subject, json: json);
264             }
265 
266             #[test]
267             fn ideal_constraint() {
268                 let subject = Subject::Constraint(ValueSequenceConstraint::default().ideal(vec![$($values.to_owned()),*]));
269                 let json = serde_json::json!({
270                     "ideal": [$($values),*],
271                 });
272 
273                 test_serde_symmetry!(subject: subject, json: json);
274             }
275 
276             #[test]
277             fn full_constraint() {
278                 let subject = Subject::Constraint(ValueSequenceConstraint::default().exact(vec![$($values.to_owned()),*]).ideal(vec![$($values.to_owned()),*]));
279                 let json = serde_json::json!({
280                     "exact": [$($values),*],
281                     "ideal": [$($values),*],
282                 });
283 
284                 test_serde_symmetry!(subject: subject, json: json);
285             }
286         };
287     }
288 
289     mod string {
290         use super::*;
291 
292         test_serde!(String => {
293             values: ["VALUE_0", "VALUE_1"]
294         });
295     }
296 }
297