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