1 #[cfg(feature = "serde")] 2 use serde::{Deserialize, Serialize}; 3 4 use crate::MediaTrackConstraintResolutionStrategy; 5 6 /// A bare value or constraint specifying a sequence of accepted values. 7 /// 8 /// # W3C Spec Compliance 9 /// 10 /// There exists no direct corresponding type in the 11 /// W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec, 12 /// since the `BareOrValueConstraint<T>` type aims to be a generalization over 13 /// multiple types in the spec. 14 /// 15 /// | Rust | W3C | 16 /// | ---------------------------------------- | -------------------------------------------- | 17 /// | `BareOrValueSequenceConstraint<String>` | [`ConstrainDOMString`][constrain_dom_string] | 18 /// 19 /// [constrain_dom_string]: https://www.w3.org/TR/mediacapture-streams/#dom-constraindomstring 20 /// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/ 21 #[derive(Debug, Clone, PartialEq)] 22 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 23 #[cfg_attr(feature = "serde", serde(untagged))] 24 pub enum BareOrValueSequenceConstraint<T> { 25 Bare(Vec<T>), 26 Constraint(ValueSequenceConstraint<T>), 27 } 28 29 impl<T> Default for BareOrValueSequenceConstraint<T> { 30 fn default() -> Self { 31 Self::Constraint(Default::default()) 32 } 33 } 34 35 impl<T> From<T> for BareOrValueSequenceConstraint<T> { 36 fn from(bare: T) -> Self { 37 Self::Bare(vec![bare]) 38 } 39 } 40 41 impl<T> From<Vec<T>> for BareOrValueSequenceConstraint<T> { 42 fn from(bare: Vec<T>) -> Self { 43 Self::Bare(bare) 44 } 45 } 46 47 impl<T> From<ValueSequenceConstraint<T>> for BareOrValueSequenceConstraint<T> { 48 fn from(constraint: ValueSequenceConstraint<T>) -> Self { 49 Self::Constraint(constraint) 50 } 51 } 52 53 impl<T> BareOrValueSequenceConstraint<T> 54 where 55 T: Clone, 56 { 57 pub fn to_resolved( 58 &self, 59 strategy: MediaTrackConstraintResolutionStrategy, 60 ) -> ValueSequenceConstraint<T> { 61 self.clone().into_resolved(strategy) 62 } 63 64 pub fn into_resolved( 65 self, 66 strategy: MediaTrackConstraintResolutionStrategy, 67 ) -> ValueSequenceConstraint<T> { 68 match self { 69 Self::Bare(bare) => match strategy { 70 MediaTrackConstraintResolutionStrategy::BareToIdeal => { 71 ValueSequenceConstraint::ideal_only(bare) 72 } 73 MediaTrackConstraintResolutionStrategy::BareToExact => { 74 ValueSequenceConstraint::exact_only(bare) 75 } 76 }, 77 Self::Constraint(constraint) => constraint, 78 } 79 } 80 } 81 82 impl<T> BareOrValueSequenceConstraint<T> { 83 pub fn is_empty(&self) -> bool { 84 match self { 85 Self::Bare(bare) => bare.is_empty(), 86 Self::Constraint(constraint) => constraint.is_empty(), 87 } 88 } 89 } 90 91 /// A constraint specifying a sequence of accepted values. 92 /// 93 /// # W3C Spec Compliance 94 /// 95 /// There exists no direct corresponding type in the 96 /// W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec, 97 /// since the `BareOrValueSequenceConstraint<T>` type aims to be a 98 /// generalization over multiple types in the W3C spec: 99 /// 100 /// | Rust | W3C | 101 /// | --------------------------------- | ----------------------------------------------------------------- | 102 /// | `ValueSequenceConstraint<String>` | [`ConstrainDOMStringParameters`][constrain_dom_string_parameters] | 103 /// 104 /// [constrain_dom_string_parameters]: https://www.w3.org/TR/mediacapture-streams/#dom-constraindomstringparameters 105 /// [media_capture_and_streams_spec]: https://www.w3.org/TR/mediacapture-streams/ 106 #[derive(Debug, Clone, PartialEq)] 107 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 108 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] 109 pub struct ValueSequenceConstraint<T> { 110 // See https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints#constraindomstring 111 #[cfg_attr( 112 feature = "serde", 113 serde(skip_serializing_if = "core::option::Option::is_none") 114 )] 115 pub exact: Option<Vec<T>>, 116 #[cfg_attr( 117 feature = "serde", 118 serde(skip_serializing_if = "core::option::Option::is_none") 119 )] 120 pub ideal: Option<Vec<T>>, 121 } 122 123 impl<T> ValueSequenceConstraint<T> { 124 pub fn exact_only(exact: Vec<T>) -> Self { 125 Self { 126 exact: Some(exact), 127 ideal: None, 128 } 129 } 130 131 pub fn ideal_only(ideal: Vec<T>) -> Self { 132 Self { 133 exact: None, 134 ideal: Some(ideal), 135 } 136 } 137 138 pub fn is_required(&self) -> bool { 139 self.exact.is_some() 140 } 141 142 pub fn is_empty(&self) -> bool { 143 let exact_is_empty = self.exact.as_ref().map_or(true, Vec::is_empty); 144 let ideal_is_empty = self.ideal.as_ref().map_or(true, Vec::is_empty); 145 exact_is_empty && ideal_is_empty 146 } 147 } 148 149 impl<T> Default for ValueSequenceConstraint<T> { 150 fn default() -> Self { 151 Self { 152 exact: None, 153 ideal: None, 154 } 155 } 156 } 157 158 #[cfg(test)] 159 mod tests { 160 use super::*; 161 162 #[test] 163 fn resolve_to_advanced() { 164 let constraint = BareOrValueSequenceConstraint::Bare(vec![true]); 165 let strategy = MediaTrackConstraintResolutionStrategy::BareToExact; 166 let actual: ValueSequenceConstraint<bool> = constraint.into_resolved(strategy); 167 let expected = ValueSequenceConstraint::exact_only(vec![true]); 168 169 assert_eq!(actual, expected); 170 } 171 172 #[test] 173 fn resolve_to_basic() { 174 let constraint = BareOrValueSequenceConstraint::Bare(vec![true]); 175 let strategy = MediaTrackConstraintResolutionStrategy::BareToIdeal; 176 let actual: ValueSequenceConstraint<bool> = constraint.into_resolved(strategy); 177 let expected = ValueSequenceConstraint::ideal_only(vec![true]); 178 179 assert_eq!(actual, expected); 180 } 181 } 182 183 #[cfg(feature = "serde")] 184 #[cfg(test)] 185 mod serde_tests { 186 use crate::macros::test_serde_symmetry; 187 188 use super::*; 189 190 macro_rules! test_serde { 191 ($t:ty => { 192 values: [$($values:expr),*] 193 }) => { 194 type Subject = BareOrValueSequenceConstraint<$t>; 195 196 #[test] 197 fn default() { 198 let subject = Subject::default(); 199 let json = serde_json::json!({}); 200 201 test_serde_symmetry!(subject: subject, json: json); 202 } 203 204 #[test] 205 fn bare() { 206 let subject = Subject::Bare(vec![$($values.to_owned()),*].into()); 207 let json = serde_json::json!([$($values),*]); 208 209 test_serde_symmetry!(subject: subject, json: json); 210 } 211 212 #[test] 213 fn constraint() { 214 let subject = Subject::Constraint(ValueSequenceConstraint::<String> { 215 exact: Some(vec![$($values.to_owned()),*].into()), 216 ideal: None, 217 }); 218 let json = serde_json::json!({ 219 "exact": [$($values),*], 220 }); 221 222 test_serde_symmetry!(subject: subject, json: json); 223 } 224 }; 225 } 226 227 mod string { 228 use super::*; 229 230 test_serde!(String => { 231 values: ["VALUE_0", "VALUE_1"] 232 }); 233 } 234 } 235