1 use std::ops::{RangeFrom, RangeInclusive, RangeToInclusive};
2 
3 #[cfg(feature = "serde")]
4 use serde::{Deserialize, Serialize};
5 
6 /// A capability specifying a range of supported 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 `MediaTrackValueRangeCapability<T>` type aims to be a
13 /// generalization over multiple types in the W3C spec:
14 ///
15 /// | Rust                                  | W3C                           |
16 /// | ------------------------------------- | ----------------------------- |
17 /// | `MediaTrackValueRangeCapability<u64>` | [`ULongRange`][ulong_range]   |
18 /// | `MediaTrackValueRangeCapability<f64>` | [`DoubleRange`][double_range] |
19 ///
20 /// [double_range]: https://www.w3.org/TR/mediacapture-streams/#dom-doublerange
21 /// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/
22 /// [ulong_range]: https://www.w3.org/TR/mediacapture-streams/#dom-ulongrange
23 #[derive(Debug, Clone, Eq, PartialEq)]
24 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
26 pub struct MediaTrackValueRangeCapability<T> {
27     #[cfg_attr(
28         feature = "serde",
29         serde(skip_serializing_if = "core::option::Option::is_none")
30     )]
31     pub min: Option<T>,
32     #[cfg_attr(
33         feature = "serde",
34         serde(skip_serializing_if = "core::option::Option::is_none")
35     )]
36     pub max: Option<T>,
37 }
38 
39 impl<T> Default for MediaTrackValueRangeCapability<T> {
40     fn default() -> Self {
41         Self {
42             min: Default::default(),
43             max: Default::default(),
44         }
45     }
46 }
47 
48 impl<T> From<RangeInclusive<T>> for MediaTrackValueRangeCapability<T> {
49     fn from(range: RangeInclusive<T>) -> Self {
50         let (min, max) = range.into_inner();
51         Self {
52             min: Some(min),
53             max: Some(max),
54         }
55     }
56 }
57 
58 impl<T> From<RangeFrom<T>> for MediaTrackValueRangeCapability<T> {
59     fn from(range: RangeFrom<T>) -> Self {
60         Self {
61             min: Some(range.start),
62             max: None,
63         }
64     }
65 }
66 
67 impl<T> From<RangeToInclusive<T>> for MediaTrackValueRangeCapability<T> {
68     fn from(range: RangeToInclusive<T>) -> Self {
69         Self {
70             min: None,
71             max: Some(range.end),
72         }
73     }
74 }
75 
76 impl<T> MediaTrackValueRangeCapability<T> {
77     pub fn contains(&self, value: &T) -> bool
78     where
79         T: PartialOrd,
80     {
81         // FIXME(regexident): replace with if-let-chain, once stabilized:
82         // Tracking issue: https://github.com/rust-lang/rust/issues/53667
83         if let Some(ref min) = self.min {
84             if min > value {
85                 return false;
86             }
87         }
88         // FIXME(regexident): replace with if-let-chain, once stabilized:
89         // Tracking issue: https://github.com/rust-lang/rust/issues/53667
90         if let Some(ref max) = self.max {
91             if max < value {
92                 return false;
93             }
94         }
95         true
96     }
97 }
98 
99 #[cfg(feature = "serde")]
100 #[cfg(test)]
101 mod serde_tests {
102     use crate::macros::test_serde_symmetry;
103 
104     use super::*;
105 
106     type Subject = MediaTrackValueRangeCapability<i64>;
107 
108     #[test]
109     fn customized() {
110         let subject = Subject {
111             min: Some(12),
112             max: Some(34),
113         };
114         let json = serde_json::json!({
115             "min": 12,
116             "max": 34,
117         });
118 
119         test_serde_symmetry!(subject: subject, json: json);
120     }
121 }
122