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