1 #[cfg(feature = "serde")] 2 use serde::{Deserialize, Serialize}; 3 4 /// A bare value or constraint specifying a range of accepted values. 5 /// 6 /// # W3C Spec Compliance 7 /// 8 /// There exists no direct corresponding type in the 9 /// W3C ["Media Capture and Streams"][media_capture_and_streams_spec] spec, 10 /// since the `BareOrValueConstraint<T>` type aims to be a generalization over 11 /// multiple types in the spec. 12 /// 13 /// | Rust | W3C | 14 /// | ---------------------------------- | ------------------------------------- | 15 /// | `BareOrValueRangeConstraint<u64>` | [`ConstrainULong`][constrain_ulong] | 16 /// | `BareOrValueRangeConstraint<f64>` | [`ConstrainDouble`][constrain_double] | 17 /// 18 /// [constrain_double]: https://www.w3.org/TR/mediacapture-streams/#dom-constraindouble 19 /// [constrain_ulong]: https://www.w3.org/TR/mediacapture-streams/#dom-constrainulong 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 BareOrValueRangeConstraint<T> { 25 Bare(T), 26 Constraint(ValueRangeConstraint<T>), 27 } 28 29 impl<T> Default for BareOrValueRangeConstraint<T> { 30 fn default() -> Self { 31 Self::Constraint(Default::default()) 32 } 33 } 34 35 impl<T> From<T> for BareOrValueRangeConstraint<T> { 36 fn from(bare: T) -> Self { 37 Self::Bare(bare) 38 } 39 } 40 41 impl<T> From<ValueRangeConstraint<T>> for BareOrValueRangeConstraint<T> { 42 fn from(constraint: ValueRangeConstraint<T>) -> Self { 43 Self::Constraint(constraint) 44 } 45 } 46 47 /// A constraint specifying a range of accepted values. 48 /// 49 /// Corresponding W3C spec types as per ["Media Capture and Streams"][spec]: 50 /// - `ConstrainDouble` => `ValueRangeConstraint<f64>` 51 /// - `ConstrainULong` => `ValueRangeConstraint<u64>` 52 /// 53 /// [spec]: https://www.w3.org/TR/mediacapture-streams 54 #[derive(Debug, Clone, PartialEq)] 55 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] 56 #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] 57 pub struct ValueRangeConstraint<T> { 58 #[cfg_attr( 59 feature = "serde", 60 serde(skip_serializing_if = "core::option::Option::is_none") 61 )] 62 pub min: Option<T>, 63 #[cfg_attr( 64 feature = "serde", 65 serde(skip_serializing_if = "core::option::Option::is_none") 66 )] 67 pub max: Option<T>, 68 #[cfg_attr( 69 feature = "serde", 70 serde(skip_serializing_if = "core::option::Option::is_none") 71 )] 72 pub exact: Option<T>, 73 #[cfg_attr( 74 feature = "serde", 75 serde(skip_serializing_if = "core::option::Option::is_none") 76 )] 77 pub ideal: Option<T>, 78 } 79 80 impl<T> ValueRangeConstraint<T> { 81 pub fn exact_only(exact: T) -> Self { 82 Self { 83 min: None, 84 max: None, 85 exact: Some(exact), 86 ideal: None, 87 } 88 } 89 90 pub fn ideal_only(ideal: T) -> Self { 91 Self { 92 min: None, 93 max: None, 94 exact: None, 95 ideal: Some(ideal), 96 } 97 } 98 99 pub fn is_required(&self) -> bool { 100 self.min.is_some() || self.max.is_some() || self.exact.is_some() 101 } 102 } 103 104 impl<T> Default for ValueRangeConstraint<T> { 105 fn default() -> Self { 106 Self { 107 min: None, 108 max: None, 109 exact: None, 110 ideal: None, 111 } 112 } 113 } 114 115 #[cfg(feature = "serde")] 116 #[cfg(test)] 117 mod serde_tests { 118 use crate::macros::test_serde_symmetry; 119 120 use super::*; 121 122 macro_rules! test_serde { 123 ($t:ty => { 124 value: $value:expr 125 }) => { 126 type Subject = BareOrValueRangeConstraint<$t>; 127 128 #[test] 129 fn default() { 130 let subject = Subject::default(); 131 let json = serde_json::json!({}); 132 133 test_serde_symmetry!(subject: subject, json: json); 134 } 135 136 #[test] 137 fn bare() { 138 let subject = Subject::Bare($value.to_owned()); 139 let json = serde_json::json!($value); 140 141 test_serde_symmetry!(subject: subject, json: json); 142 } 143 144 #[test] 145 fn exact() { 146 let subject = Subject::Constraint(ValueRangeConstraint::exact_only($value.to_owned())); 147 let json = serde_json::json!({ 148 "exact": $value, 149 }); 150 151 test_serde_symmetry!(subject: subject, json: json); 152 } 153 154 #[test] 155 fn ideal() { 156 let subject = Subject::Constraint(ValueRangeConstraint::ideal_only($value.to_owned())); 157 let json = serde_json::json!({ 158 "ideal": $value, 159 }); 160 161 test_serde_symmetry!(subject: subject, json: json); 162 } 163 }; 164 } 165 166 mod f64 { 167 use super::*; 168 169 test_serde!(f64 => { 170 value: 42.0 171 }); 172 } 173 174 mod u64 { 175 use super::*; 176 177 test_serde!(u64 => { 178 value: 42 179 }); 180 } 181 } 182