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, 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::ideal_only(bare)
72                 }
73                 MediaTrackConstraintResolutionStrategy::BareToExact => {
74                     ValueSequenceConstraint::exact_only(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, 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     pub fn exact_only(exact: Vec<T>) -> Self {
125         Self {
126             exact: Some(exact),
127             ideal: None,
128         }
129     }
130 
131     pub fn ideal_only(ideal: Vec<T>) -> Self {
132         Self {
133             exact: None,
134             ideal: Some(ideal),
135         }
136     }
137 
138     pub fn is_required(&self) -> bool {
139         self.exact.is_some()
140     }
141 
142     pub fn is_empty(&self) -> bool {
143         let exact_is_empty = self.exact.as_ref().map_or(true, Vec::is_empty);
144         let ideal_is_empty = self.ideal.as_ref().map_or(true, Vec::is_empty);
145         exact_is_empty && ideal_is_empty
146     }
147 }
148 
149 impl<T> Default for ValueSequenceConstraint<T> {
150     fn default() -> Self {
151         Self {
152             exact: None,
153             ideal: None,
154         }
155     }
156 }
157 
158 #[cfg(test)]
159 mod tests {
160     use super::*;
161 
162     #[test]
163     fn resolve_to_advanced() {
164         let constraint = BareOrValueSequenceConstraint::Bare(vec![true]);
165         let strategy = MediaTrackConstraintResolutionStrategy::BareToExact;
166         let actual: ValueSequenceConstraint<bool> = constraint.into_resolved(strategy);
167         let expected = ValueSequenceConstraint::exact_only(vec![true]);
168 
169         assert_eq!(actual, expected);
170     }
171 
172     #[test]
173     fn resolve_to_basic() {
174         let constraint = BareOrValueSequenceConstraint::Bare(vec![true]);
175         let strategy = MediaTrackConstraintResolutionStrategy::BareToIdeal;
176         let actual: ValueSequenceConstraint<bool> = constraint.into_resolved(strategy);
177         let expected = ValueSequenceConstraint::ideal_only(vec![true]);
178 
179         assert_eq!(actual, expected);
180     }
181 }
182 
183 #[cfg(feature = "serde")]
184 #[cfg(test)]
185 mod serde_tests {
186     use crate::macros::test_serde_symmetry;
187 
188     use super::*;
189 
190     macro_rules! test_serde {
191         ($t:ty => {
192             values: [$($values:expr),*]
193         }) => {
194             type Subject = BareOrValueSequenceConstraint<$t>;
195 
196             #[test]
197             fn default() {
198                 let subject = Subject::default();
199                 let json = serde_json::json!({});
200 
201                 test_serde_symmetry!(subject: subject, json: json);
202             }
203 
204             #[test]
205             fn bare() {
206                 let subject = Subject::Bare(vec![$($values.to_owned()),*].into());
207                 let json = serde_json::json!([$($values),*]);
208 
209                 test_serde_symmetry!(subject: subject, json: json);
210             }
211 
212             #[test]
213             fn constraint() {
214                 let subject = Subject::Constraint(ValueSequenceConstraint::<String> {
215                     exact: Some(vec![$($values.to_owned()),*].into()),
216                     ideal: None,
217                 });
218                 let json = serde_json::json!({
219                     "exact": [$($values),*],
220                 });
221 
222                 test_serde_symmetry!(subject: subject, json: json);
223             }
224         };
225     }
226 
227     mod string {
228         use super::*;
229 
230         test_serde!(String => {
231             values: ["VALUE_0", "VALUE_1"]
232         });
233     }
234 }
235