1 use std::{
2     collections::HashMap,
3     iter::FromIterator,
4     ops::{Deref, DerefMut},
5 };
6 
7 #[cfg(feature = "serde")]
8 use serde::{Deserialize, Serialize};
9 
10 use crate::{MediaTrackCapability, MediaTrackProperty};
11 
12 /// The capabilities of a [`MediaStreamTrack`][media_stream_track] object.
13 ///
14 /// # W3C Spec Compliance
15 ///
16 /// Corresponds to [`MediaTrackCapabilities`][media_track_capabilities]
17 /// from the W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec.
18 ///
19 /// The W3C spec defines `MediaTrackSettings` in terma of a dictionary,
20 /// which per the [WebIDL spec][webidl_spec] is an ordered map (e.g. `IndexMap<K, V>`).
21 /// Since the spec however does not make use of the order of items
22 /// in the map we use a simple `HashMap<K, V>`.
23 ///
24 /// [media_stream_track]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamtrack
25 /// [media_track_capabilities]: https://www.w3.org/TR/mediacapture-streams/#dom-mediatrackcapabilities
26 /// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams
27 /// [webidl_spec]: https://webidl.spec.whatwg.org/#idl-dictionaries
28 #[derive(Debug, Clone, Default, PartialEq)]
29 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
30 #[cfg_attr(feature = "serde", serde(transparent))]
31 pub struct MediaTrackCapabilities(HashMap<MediaTrackProperty, MediaTrackCapability>);
32 
33 impl MediaTrackCapabilities {
34     /// Creates a capabilities value from its inner hashmap.
new(capabilities: HashMap<MediaTrackProperty, MediaTrackCapability>) -> Self35     pub fn new(capabilities: HashMap<MediaTrackProperty, MediaTrackCapability>) -> Self {
36         Self(capabilities)
37     }
38 
39     /// Consumes the value, returning its inner hashmap.
into_inner(self) -> HashMap<MediaTrackProperty, MediaTrackCapability>40     pub fn into_inner(self) -> HashMap<MediaTrackProperty, MediaTrackCapability> {
41         self.0
42     }
43 }
44 
45 impl Deref for MediaTrackCapabilities {
46     type Target = HashMap<MediaTrackProperty, MediaTrackCapability>;
47 
deref(&self) -> &Self::Target48     fn deref(&self) -> &Self::Target {
49         &self.0
50     }
51 }
52 
53 impl DerefMut for MediaTrackCapabilities {
deref_mut(&mut self) -> &mut Self::Target54     fn deref_mut(&mut self) -> &mut Self::Target {
55         &mut self.0
56     }
57 }
58 
59 impl<T> FromIterator<(T, MediaTrackCapability)> for MediaTrackCapabilities
60 where
61     T: Into<MediaTrackProperty>,
62 {
from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = (T, MediaTrackCapability)>,63     fn from_iter<I>(iter: I) -> Self
64     where
65         I: IntoIterator<Item = (T, MediaTrackCapability)>,
66     {
67         Self::new(iter.into_iter().map(|(k, v)| (k.into(), v)).collect())
68     }
69 }
70 
71 impl IntoIterator for MediaTrackCapabilities {
72     type Item = (MediaTrackProperty, MediaTrackCapability);
73     type IntoIter = std::collections::hash_map::IntoIter<MediaTrackProperty, MediaTrackCapability>;
74 
into_iter(self) -> Self::IntoIter75     fn into_iter(self) -> Self::IntoIter {
76         self.0.into_iter()
77     }
78 }
79 
80 #[cfg(test)]
81 mod tests {
82     use crate::property::all::name::*;
83 
84     use super::*;
85 
86     type Subject = MediaTrackCapabilities;
87 
88     #[test]
into_inner()89     fn into_inner() {
90         let hash_map = HashMap::from_iter([
91             (DEVICE_ID.clone(), "device-id".into()),
92             (AUTO_GAIN_CONTROL.clone(), true.into()),
93             (CHANNEL_COUNT.clone(), (12..=34).into()),
94             (LATENCY.clone(), (1.2..=3.4).into()),
95         ]);
96 
97         let subject = Subject::new(hash_map.clone());
98 
99         let actual = subject.into_inner();
100 
101         let expected = hash_map;
102 
103         assert_eq!(actual, expected);
104     }
105 
106     #[test]
into_iter()107     fn into_iter() {
108         let hash_map = HashMap::from_iter([
109             (DEVICE_ID.clone(), "device-id".into()),
110             (AUTO_GAIN_CONTROL.clone(), true.into()),
111             (CHANNEL_COUNT.clone(), (12..=34).into()),
112             (LATENCY.clone(), (1.2..=3.4).into()),
113         ]);
114 
115         let subject = Subject::new(hash_map.clone());
116 
117         let actual: HashMap<_, _> = subject.into_iter().collect();
118 
119         let expected = hash_map;
120 
121         assert_eq!(actual, expected);
122     }
123 
124     #[test]
deref_and_deref_mut()125     fn deref_and_deref_mut() {
126         let mut subject = Subject::default();
127 
128         // Deref mut:
129         subject.insert(DEVICE_ID.clone(), "device-id".into());
130 
131         // Deref:
132         assert!(subject.contains_key(&DEVICE_ID));
133     }
134 }
135 
136 #[cfg(feature = "serde")]
137 #[cfg(test)]
138 mod serde_tests {
139     use crate::{macros::test_serde_symmetry, property::all::name::*};
140 
141     use super::*;
142 
143     type Subject = MediaTrackCapabilities;
144 
145     #[test]
default()146     fn default() {
147         let subject = Subject::default();
148         let json = serde_json::json!({});
149 
150         test_serde_symmetry!(subject: subject, json: json);
151     }
152 
153     #[test]
customized()154     fn customized() {
155         let subject = Subject::from_iter([
156             (&DEVICE_ID, "device-id".into()),
157             (&AUTO_GAIN_CONTROL, true.into()),
158             (&CHANNEL_COUNT, (12..=34).into()),
159             (&LATENCY, (1.2..=3.4).into()),
160         ]);
161         let json = serde_json::json!({
162             "deviceId": "device-id".to_owned(),
163             "autoGainControl": true,
164             "channelCount": { "min": 12, "max": 34 },
165             "latency": { "min": 1.2, "max": 3.4 },
166         });
167 
168         test_serde_symmetry!(subject: subject, json: json);
169     }
170 }
171