1 use std::{
2     collections::HashMap,
3     ops::{Deref, DerefMut},
4 };
5 
6 #[cfg(feature = "serde")]
7 use serde::{Deserialize, Serialize};
8 
9 use crate::MediaTrackCapability;
10 
11 /// The capabilities of a [`MediaStreamTrack`][media_stream_track] object.
12 ///
13 /// # W3C Spec Compliance
14 ///
15 /// Corresponds to [`MediaTrackCapabilities`][media_track_capabilities]
16 /// from the W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec.
17 ///
18 /// The W3C spec defines `MediaTrackSettings` in terma of a dictionary,
19 /// which per the [WebIDL spec][webidl_spec] is an ordered map (e.g. `IndexMap<K, V>`).
20 /// Since the spec however does not make use of the order of items
21 /// in the map we use a simple `HashMap<K, V>`.
22 ///
23 /// [media_stream_track]: https://www.w3.org/TR/mediacapture-streams/#dom-mediastreamtrack
24 /// [media_track_capabilities]: https://www.w3.org/TR/mediacapture-streams/#dom-mediatrackcapabilities
25 /// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams
26 /// [webidl_spec]: https://webidl.spec.whatwg.org/#idl-dictionaries
27 #[derive(Debug, Clone, Default, PartialEq)]
28 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
29 #[cfg_attr(feature = "serde", serde(transparent))]
30 pub struct MediaTrackCapabilities(HashMap<String, MediaTrackCapability>);
31 
32 impl MediaTrackCapabilities {
33     pub fn new(capabilities: HashMap<String, MediaTrackCapability>) -> Self {
34         Self(capabilities)
35     }
36 
37     pub fn into_inner(self) -> HashMap<String, MediaTrackCapability> {
38         self.0
39     }
40 }
41 
42 impl Deref for MediaTrackCapabilities {
43     type Target = HashMap<String, MediaTrackCapability>;
44 
45     fn deref(&self) -> &Self::Target {
46         &self.0
47     }
48 }
49 
50 impl DerefMut for MediaTrackCapabilities {
51     fn deref_mut(&mut self) -> &mut Self::Target {
52         &mut self.0
53     }
54 }
55 
56 impl<T> FromIterator<(T, MediaTrackCapability)> for MediaTrackCapabilities
57 where
58     T: Into<String>,
59 {
60     fn from_iter<I>(iter: I) -> Self
61     where
62         I: IntoIterator<Item = (T, MediaTrackCapability)>,
63     {
64         Self::new(iter.into_iter().map(|(k, v)| (k.into(), v)).collect())
65     }
66 }
67 
68 impl IntoIterator for MediaTrackCapabilities {
69     type Item = (String, MediaTrackCapability);
70     type IntoIter = std::collections::hash_map::IntoIter<String, MediaTrackCapability>;
71 
72     fn into_iter(self) -> Self::IntoIter {
73         self.0.into_iter()
74     }
75 }
76 
77 #[cfg(feature = "serde")]
78 #[cfg(test)]
79 mod serde_tests {
80     use crate::{macros::test_serde_symmetry, property::name::*};
81 
82     use super::*;
83 
84     type Subject = MediaTrackCapabilities;
85 
86     #[test]
87     fn default() {
88         let subject = Subject::default();
89         let json = serde_json::json!({});
90 
91         test_serde_symmetry!(subject: subject, json: json);
92     }
93 
94     #[test]
95     fn customized() {
96         let subject = Subject::from_iter([
97             (DEVICE_ID, "device-id".into()),
98             (AUTO_GAIN_CONTROL, true.into()),
99             (CHANNEL_COUNT, (12..=34).into()),
100             (LATENCY, (1.2..=3.4).into()),
101         ]);
102         let json = serde_json::json!({
103             "deviceId": "device-id".to_owned(),
104             "autoGainControl": true,
105             "channelCount": { "min": 12, "max": 34 },
106             "latency": { "min": 1.2, "max": 3.4 },
107         });
108 
109         test_serde_symmetry!(subject: subject, json: json);
110     }
111 }
112