webrtc_constraints/
supported_constraints.rs1use std::{
2 collections::HashSet,
3 iter::FromIterator,
4 ops::{Deref, DerefMut},
5};
6
7#[cfg(feature = "serde")]
8use serde::{
9 de::{MapAccess, Visitor},
10 ser::SerializeMap,
11 Deserialize, Deserializer, Serialize, Serializer,
12};
13
14use crate::MediaTrackProperty;
15
16#[derive(Debug, Clone, Eq, PartialEq)]
36pub struct MediaTrackSupportedConstraints(HashSet<MediaTrackProperty>);
37
38impl MediaTrackSupportedConstraints {
39 pub fn new(properties: HashSet<MediaTrackProperty>) -> Self {
41 Self(properties)
42 }
43
44 pub fn into_inner(self) -> HashSet<MediaTrackProperty> {
46 self.0
47 }
48}
49
50impl Deref for MediaTrackSupportedConstraints {
51 type Target = HashSet<MediaTrackProperty>;
52
53 fn deref(&self) -> &Self::Target {
54 &self.0
55 }
56}
57
58impl DerefMut for MediaTrackSupportedConstraints {
59 fn deref_mut(&mut self) -> &mut Self::Target {
60 &mut self.0
61 }
62}
63
64impl Default for MediaTrackSupportedConstraints {
65 fn default() -> Self {
69 use crate::property::all::names as property_names;
70
71 Self::from_iter(property_names().into_iter().cloned())
72 }
73}
74
75impl<T> FromIterator<T> for MediaTrackSupportedConstraints
76where
77 T: Into<MediaTrackProperty>,
78{
79 fn from_iter<I>(iter: I) -> Self
80 where
81 I: IntoIterator<Item = T>,
82 {
83 Self(iter.into_iter().map(|property| property.into()).collect())
84 }
85}
86
87impl IntoIterator for MediaTrackSupportedConstraints {
88 type Item = MediaTrackProperty;
89 type IntoIter = std::collections::hash_set::IntoIter<MediaTrackProperty>;
90
91 fn into_iter(self) -> Self::IntoIter {
92 self.0.into_iter()
93 }
94}
95
96#[cfg(feature = "serde")]
97impl<'de> Deserialize<'de> for MediaTrackSupportedConstraints {
98 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
99 where
100 D: Deserializer<'de>,
101 {
102 deserializer.deserialize_map(SerdeVisitor)
103 }
104}
105
106#[cfg(feature = "serde")]
107impl Serialize for MediaTrackSupportedConstraints {
108 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
109 where
110 S: Serializer,
111 {
112 let mut map = serializer.serialize_map(Some(self.0.len()))?;
113 for property in &self.0 {
114 map.serialize_entry(property, &true)?;
115 }
116 map.end()
117 }
118}
119
120#[cfg(feature = "serde")]
121struct SerdeVisitor;
122
123#[cfg(feature = "serde")]
124impl<'de> Visitor<'de> for SerdeVisitor {
125 type Value = MediaTrackSupportedConstraints;
126
127 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 formatter.write_str("an object with strings as keys and `true` as values")
129 }
130
131 fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
132 where
133 M: MapAccess<'de>,
134 {
135 let mut set = HashSet::with_capacity(access.size_hint().unwrap_or(0));
136 while let Some((key, value)) = access.next_entry()? {
137 if value {
138 set.insert(key);
139 }
140 }
141 Ok(MediaTrackSupportedConstraints(set))
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use crate::property::all::name::*;
148
149 use super::*;
150
151 type Subject = MediaTrackSupportedConstraints;
152
153 #[test]
154 fn into_inner() {
155 let hash_set = HashSet::from_iter([
156 DEVICE_ID.clone(),
157 AUTO_GAIN_CONTROL.clone(),
158 CHANNEL_COUNT.clone(),
159 LATENCY.clone(),
160 ]);
161
162 let subject = Subject::new(hash_set.clone());
163
164 let actual = subject.into_inner();
165
166 let expected = hash_set;
167
168 assert_eq!(actual, expected);
169 }
170
171 #[test]
172 fn into_iter() {
173 let hash_set = HashSet::from_iter([
174 DEVICE_ID.clone(),
175 AUTO_GAIN_CONTROL.clone(),
176 CHANNEL_COUNT.clone(),
177 LATENCY.clone(),
178 ]);
179
180 let subject = Subject::new(hash_set.clone());
181
182 let actual: HashSet<_, _> = subject.into_iter().collect();
183
184 let expected = hash_set;
185
186 assert_eq!(actual, expected);
187 }
188
189 #[test]
190 fn deref_and_deref_mut() {
191 let mut subject = Subject::default();
192
193 subject.insert(DEVICE_ID.clone());
195
196 assert!(subject.contains(&DEVICE_ID));
198 }
199}
200
201#[cfg(feature = "serde")]
202#[cfg(test)]
203mod serde_tests {
204 use crate::{macros::test_serde_symmetry, property::all::name::*};
205
206 use super::*;
207
208 type Subject = MediaTrackSupportedConstraints;
209
210 #[test]
211 fn default() {
212 let subject = Subject::default();
213 let json = serde_json::json!({
214 "deviceId": true,
215 "groupId": true,
216 "autoGainControl": true,
217 "channelCount": true,
218 "echoCancellation": true,
219 "latency": true,
220 "noiseSuppression": true,
221 "sampleRate": true,
222 "sampleSize": true,
223 "aspectRatio": true,
224 "facingMode": true,
225 "frameRate": true,
226 "height": true,
227 "width": true,
228 "resizeMode": true,
229 });
230
231 test_serde_symmetry!(subject: subject, json: json);
232 }
233
234 #[test]
235 fn customized() {
236 let subject = Subject::from_iter([
237 &DEVICE_ID,
238 &GROUP_ID,
239 &AUTO_GAIN_CONTROL,
240 &CHANNEL_COUNT,
241 &ASPECT_RATIO,
242 &FACING_MODE,
243 ]);
244 let json = serde_json::json!({
245 "deviceId": true,
246 "groupId": true,
247 "autoGainControl": true,
248 "channelCount": true,
249 "aspectRatio": true,
250 "facingMode": true
251 });
252
253 test_serde_symmetry!(subject: subject, json: json);
254 }
255}