webrtc_constraints/constraint/
value_sequence.rs1#[cfg(feature = "serde")]
2use serde::{Deserialize, Serialize};
3
4use crate::MediaTrackConstraintResolutionStrategy;
5
6#[derive(Debug, Clone, Eq, PartialEq)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23#[cfg_attr(feature = "serde", serde(untagged))]
24pub enum ValueSequenceConstraint<T> {
25 Bare(Vec<T>),
27 Constraint(ResolvedValueSequenceConstraint<T>),
29}
30
31impl<T> Default for ValueSequenceConstraint<T> {
32 fn default() -> Self {
33 Self::Constraint(Default::default())
34 }
35}
36
37impl<T> From<T> for ValueSequenceConstraint<T> {
38 fn from(bare: T) -> Self {
39 Self::Bare(vec![bare])
40 }
41}
42
43impl<T> From<Vec<T>> for ValueSequenceConstraint<T> {
44 fn from(bare: Vec<T>) -> Self {
45 Self::Bare(bare)
46 }
47}
48
49impl<T> From<ResolvedValueSequenceConstraint<T>> for ValueSequenceConstraint<T> {
50 fn from(constraint: ResolvedValueSequenceConstraint<T>) -> Self {
51 Self::Constraint(constraint)
52 }
53}
54
55impl<T> ValueSequenceConstraint<T>
56where
57 T: Clone,
58{
59 pub fn to_resolved(
62 &self,
63 strategy: MediaTrackConstraintResolutionStrategy,
64 ) -> ResolvedValueSequenceConstraint<T> {
65 self.clone().into_resolved(strategy)
66 }
67
68 pub fn into_resolved(
71 self,
72 strategy: MediaTrackConstraintResolutionStrategy,
73 ) -> ResolvedValueSequenceConstraint<T> {
74 match self {
75 Self::Bare(bare) => match strategy {
76 MediaTrackConstraintResolutionStrategy::BareToIdeal => {
77 ResolvedValueSequenceConstraint::default().ideal(bare)
78 }
79 MediaTrackConstraintResolutionStrategy::BareToExact => {
80 ResolvedValueSequenceConstraint::default().exact(bare)
81 }
82 },
83 Self::Constraint(constraint) => constraint,
84 }
85 }
86}
87
88impl<T> ValueSequenceConstraint<T> {
89 pub fn is_empty(&self) -> bool {
91 match self {
92 Self::Bare(bare) => bare.is_empty(),
93 Self::Constraint(constraint) => constraint.is_empty(),
94 }
95 }
96}
97
98#[derive(Debug, Clone, Eq, PartialEq)]
114#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
115#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
116pub struct ResolvedValueSequenceConstraint<T> {
117 #[cfg_attr(
121 feature = "serde",
122 serde(skip_serializing_if = "core::option::Option::is_none")
123 )]
124 pub exact: Option<Vec<T>>,
125 #[cfg_attr(
129 feature = "serde",
130 serde(skip_serializing_if = "core::option::Option::is_none")
131 )]
132 pub ideal: Option<Vec<T>>,
133}
134
135impl<T> ResolvedValueSequenceConstraint<T> {
136 #[inline]
139 pub fn exact<U>(mut self, exact: U) -> Self
140 where
141 Option<Vec<T>>: From<U>,
142 {
143 self.exact = exact.into();
144 self
145 }
146
147 #[inline]
150 pub fn ideal<U>(mut self, ideal: U) -> Self
151 where
152 Option<Vec<T>>: From<U>,
153 {
154 self.ideal = ideal.into();
155 self
156 }
157
158 pub fn is_required(&self) -> bool {
161 self.exact.is_some()
162 }
163
164 pub fn is_empty(&self) -> bool {
167 let exact_is_empty = self.exact.as_ref().map_or(true, Vec::is_empty);
168 let ideal_is_empty = self.ideal.as_ref().map_or(true, Vec::is_empty);
169 exact_is_empty && ideal_is_empty
170 }
171
172 pub fn to_required_only(&self) -> Self
174 where
175 T: Clone,
176 {
177 self.clone().into_required_only()
178 }
179
180 pub fn into_required_only(self) -> Self {
183 Self {
184 exact: self.exact,
185 ideal: None,
186 }
187 }
188}
189
190impl<T> Default for ResolvedValueSequenceConstraint<T> {
191 fn default() -> Self {
192 Self {
193 exact: None,
194 ideal: None,
195 }
196 }
197}
198
199impl<T> std::fmt::Display for ResolvedValueSequenceConstraint<T>
200where
201 T: std::fmt::Debug,
202{
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 let mut is_first = true;
205 f.write_str("(")?;
206 if let Some(ref exact) = &self.exact {
207 f.write_fmt(format_args!("x == {:?}", exact))?;
208 is_first = false;
209 }
210 if let Some(ref ideal) = &self.ideal {
211 if !is_first {
212 f.write_str(" && ")?;
213 }
214 f.write_fmt(format_args!("x ~= {:?}", ideal))?;
215 is_first = false;
216 }
217 if is_first {
218 f.write_str("<empty>")?;
219 }
220 f.write_str(")")?;
221 Ok(())
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn to_string() {
231 let scenarios = [
232 (ResolvedValueSequenceConstraint::default(), "(<empty>)"),
233 (
234 ResolvedValueSequenceConstraint::default().exact(vec![1, 2]),
235 "(x == [1, 2])",
236 ),
237 (
238 ResolvedValueSequenceConstraint::default().ideal(vec![2, 3]),
239 "(x ~= [2, 3])",
240 ),
241 (
242 ResolvedValueSequenceConstraint::default()
243 .exact(vec![1, 2])
244 .ideal(vec![2, 3]),
245 "(x == [1, 2] && x ~= [2, 3])",
246 ),
247 ];
248
249 for (constraint, expected) in scenarios {
250 let actual = constraint.to_string();
251
252 assert_eq!(actual, expected);
253 }
254 }
255
256 #[test]
257 fn is_required() {
258 let scenarios = [
259 (ResolvedValueSequenceConstraint::default(), false),
260 (
261 ResolvedValueSequenceConstraint::default().exact(vec![true]),
262 true,
263 ),
264 (
265 ResolvedValueSequenceConstraint::default().ideal(vec![true]),
266 false,
267 ),
268 (
269 ResolvedValueSequenceConstraint::default()
270 .exact(vec![true])
271 .ideal(vec![true]),
272 true,
273 ),
274 ];
275
276 for (constraint, expected) in scenarios {
277 let actual = constraint.is_required();
278
279 assert_eq!(actual, expected);
280 }
281 }
282
283 mod is_empty {
284 use super::*;
285
286 #[test]
287 fn bare() {
288 let constraint = ValueSequenceConstraint::Bare(vec![true]);
289
290 assert!(!constraint.is_empty());
291 }
292
293 #[test]
294 fn constraint() {
295 let scenarios = [
296 (ResolvedValueSequenceConstraint::default(), true),
297 (
298 ResolvedValueSequenceConstraint::default().exact(vec![true]),
299 false,
300 ),
301 (
302 ResolvedValueSequenceConstraint::default().ideal(vec![true]),
303 false,
304 ),
305 (
306 ResolvedValueSequenceConstraint::default()
307 .exact(vec![true])
308 .ideal(vec![true]),
309 false,
310 ),
311 ];
312
313 for (constraint, expected) in scenarios {
314 let constraint = ValueSequenceConstraint::<bool>::Constraint(constraint);
315
316 let actual = constraint.is_empty();
317
318 assert_eq!(actual, expected);
319 }
320 }
321 }
322
323 #[test]
324 fn resolve_to_advanced() {
325 let constraints = [
326 ValueSequenceConstraint::Bare(vec![true]),
327 ValueSequenceConstraint::Constraint(
328 ResolvedValueSequenceConstraint::default().exact(vec![true]),
329 ),
330 ];
331 let strategy = MediaTrackConstraintResolutionStrategy::BareToExact;
332
333 for constraint in constraints {
334 let actuals = [
335 constraint.to_resolved(strategy),
336 constraint.into_resolved(strategy),
337 ];
338
339 let expected = ResolvedValueSequenceConstraint::default().exact(vec![true]);
340
341 for actual in actuals {
342 assert_eq!(actual, expected);
343 }
344 }
345 }
346
347 #[test]
348 fn resolve_to_basic() {
349 let constraints = [
350 ValueSequenceConstraint::Bare(vec![true]),
351 ValueSequenceConstraint::Constraint(
352 ResolvedValueSequenceConstraint::default().ideal(vec![true]),
353 ),
354 ];
355 let strategy = MediaTrackConstraintResolutionStrategy::BareToIdeal;
356
357 for constraint in constraints {
358 let actuals = [
359 constraint.to_resolved(strategy),
360 constraint.into_resolved(strategy),
361 ];
362
363 let expected = ResolvedValueSequenceConstraint::default().ideal(vec![true]);
364
365 for actual in actuals {
366 assert_eq!(actual, expected);
367 }
368 }
369 }
370}
371
372#[cfg(feature = "serde")]
373#[cfg(test)]
374mod serde_tests {
375 use crate::macros::test_serde_symmetry;
376
377 use super::*;
378
379 macro_rules! test_serde {
380 ($t:ty => {
381 values: [$($values:expr),*]
382 }) => {
383 type Subject = ValueSequenceConstraint<$t>;
384
385 #[test]
386 fn default() {
387 let subject = Subject::default();
388 let json = serde_json::json!({});
389
390 test_serde_symmetry!(subject: subject, json: json);
391 }
392
393 #[test]
394 fn bare() {
395 let subject = Subject::Bare(vec![$($values.to_owned()),*].into());
396 let json = serde_json::json!([$($values),*]);
397
398 test_serde_symmetry!(subject: subject, json: json);
399 }
400
401 #[test]
402 fn exact_constraint() {
403 let subject = Subject::Constraint(ResolvedValueSequenceConstraint::default().exact(vec![$($values.to_owned()),*]));
404 let json = serde_json::json!({
405 "exact": [$($values),*],
406 });
407
408 test_serde_symmetry!(subject: subject, json: json);
409 }
410
411 #[test]
412 fn ideal_constraint() {
413 let subject = Subject::Constraint(ResolvedValueSequenceConstraint::default().ideal(vec![$($values.to_owned()),*]));
414 let json = serde_json::json!({
415 "ideal": [$($values),*],
416 });
417
418 test_serde_symmetry!(subject: subject, json: json);
419 }
420
421 #[test]
422 fn full_constraint() {
423 let subject = Subject::Constraint(ResolvedValueSequenceConstraint::default().exact(vec![$($values.to_owned()),*]).ideal(vec![$($values.to_owned()),*]));
424 let json = serde_json::json!({
425 "exact": [$($values),*],
426 "ideal": [$($values),*],
427 });
428
429 test_serde_symmetry!(subject: subject, json: json);
430 }
431 };
432 }
433
434 mod string {
435 use super::*;
436
437 test_serde!(String => {
438 values: ["VALUE_0", "VALUE_1"]
439 });
440 }
441}