inset_embedder/
restoration.rs1use std::hash::{Hash, Hasher};
9
10use indexmap::IndexMap;
11
12pub type RestorationMap = IndexMap<RestorationData, RestorationData>;
14
15#[derive(Clone, Debug, Default, PartialEq)]
20pub enum RestorationData {
21 #[default]
23 Null,
24 Bool(bool),
26 Int(i64),
28 Double(f64),
30 String(String),
32 Uint8List(Vec<u8>),
34 Int32List(Vec<i32>),
36 Int64List(Vec<i64>),
38 Float64List(Vec<f64>),
40 List(Vec<RestorationData>),
42 Map(RestorationMap),
44}
45
46impl RestorationData {
47 pub fn is_null(&self) -> bool {
49 matches!(self, RestorationData::Null)
50 }
51
52 pub fn as_bool(&self) -> Option<bool> {
54 match self {
55 RestorationData::Bool(value) => Some(*value),
56 _ => None,
57 }
58 }
59
60 pub fn as_int(&self) -> Option<i64> {
62 match self {
63 RestorationData::Int(value) => Some(*value),
64 _ => None,
65 }
66 }
67
68 pub fn as_double(&self) -> Option<f64> {
70 match self {
71 RestorationData::Double(value) => Some(*value),
72 _ => None,
73 }
74 }
75
76 pub fn as_str(&self) -> Option<&str> {
78 match self {
79 RestorationData::String(value) => Some(value),
80 _ => None,
81 }
82 }
83
84 pub fn as_uint8_list(&self) -> Option<&[u8]> {
86 match self {
87 RestorationData::Uint8List(values) => Some(values),
88 _ => None,
89 }
90 }
91
92 pub fn as_int32_list(&self) -> Option<&[i32]> {
94 match self {
95 RestorationData::Int32List(values) => Some(values),
96 _ => None,
97 }
98 }
99
100 pub fn as_int64_list(&self) -> Option<&[i64]> {
102 match self {
103 RestorationData::Int64List(values) => Some(values),
104 _ => None,
105 }
106 }
107
108 pub fn as_float64_list(&self) -> Option<&[f64]> {
110 match self {
111 RestorationData::Float64List(values) => Some(values),
112 _ => None,
113 }
114 }
115
116 pub fn as_list(&self) -> Option<&[RestorationData]> {
118 match self {
119 RestorationData::List(values) => Some(values),
120 _ => None,
121 }
122 }
123
124 pub fn as_map(&self) -> Option<&RestorationMap> {
126 match self {
127 RestorationData::Map(map) => Some(map),
128 _ => None,
129 }
130 }
131
132 pub fn as_map_mut(&mut self) -> Option<&mut RestorationMap> {
134 match self {
135 RestorationData::Map(map) => Some(map),
136 _ => None,
137 }
138 }
139
140 pub fn into_map(self) -> Option<RestorationMap> {
142 match self {
143 RestorationData::Map(map) => Some(map),
144 _ => None,
145 }
146 }
147}
148
149fn hash_double<H: Hasher>(value: f64, state: &mut H) {
151 let normalized = if value == 0.0 { 0.0 } else { value };
152 normalized.to_bits().hash(state);
153}
154
155impl Eq for RestorationData {}
156
157impl Hash for RestorationData {
158 fn hash<H: Hasher>(&self, state: &mut H) {
159 std::mem::discriminant(self).hash(state);
160 match self {
161 RestorationData::Null => {}
162 RestorationData::Bool(value) => value.hash(state),
163 RestorationData::Int(value) => value.hash(state),
164 RestorationData::Double(value) => hash_double(*value, state),
165 RestorationData::String(value) => value.hash(state),
166 RestorationData::Uint8List(values) => values.hash(state),
167 RestorationData::Int32List(values) => values.hash(state),
168 RestorationData::Int64List(values) => values.hash(state),
169 RestorationData::Float64List(values) => {
170 for value in values {
171 hash_double(*value, state);
172 }
173 }
174 RestorationData::List(values) => values.hash(state),
175 RestorationData::Map(map) => map.len().hash(state),
178 }
179 }
180}
181
182impl From<bool> for RestorationData {
183 fn from(value: bool) -> RestorationData {
184 RestorationData::Bool(value)
185 }
186}
187
188impl From<i64> for RestorationData {
189 fn from(value: i64) -> RestorationData {
190 RestorationData::Int(value)
191 }
192}
193
194impl From<f64> for RestorationData {
195 fn from(value: f64) -> RestorationData {
196 RestorationData::Double(value)
197 }
198}
199
200impl From<&str> for RestorationData {
201 fn from(value: &str) -> RestorationData {
202 RestorationData::String(value.to_string())
203 }
204}
205
206impl From<String> for RestorationData {
207 fn from(value: String) -> RestorationData {
208 RestorationData::String(value)
209 }
210}
211
212impl From<Vec<u8>> for RestorationData {
213 fn from(values: Vec<u8>) -> RestorationData {
214 RestorationData::Uint8List(values)
215 }
216}
217
218impl From<Vec<i32>> for RestorationData {
219 fn from(values: Vec<i32>) -> RestorationData {
220 RestorationData::Int32List(values)
221 }
222}
223
224impl From<Vec<i64>> for RestorationData {
225 fn from(values: Vec<i64>) -> RestorationData {
226 RestorationData::Int64List(values)
227 }
228}
229
230impl From<Vec<f64>> for RestorationData {
231 fn from(values: Vec<f64>) -> RestorationData {
232 RestorationData::Float64List(values)
233 }
234}
235
236impl From<Vec<RestorationData>> for RestorationData {
237 fn from(values: Vec<RestorationData>) -> RestorationData {
238 RestorationData::List(values)
239 }
240}
241
242impl From<RestorationMap> for RestorationData {
243 fn from(map: RestorationMap) -> RestorationData {
244 RestorationData::Map(map)
245 }
246}
247
248impl<T: Into<RestorationData>> From<Option<T>> for RestorationData {
249 fn from(value: Option<T>) -> RestorationData {
250 match value {
251 Some(value) => value.into(),
252 None => RestorationData::Null,
253 }
254 }
255}
256
257#[derive(Clone, Debug, Default, PartialEq)]
262pub struct RestorationUpdate {
263 pub enabled: bool,
266
267 pub data: Option<RestorationMap>,
270}
271
272#[cfg(test)]
273mod tests {
274 use std::collections::hash_map::DefaultHasher;
275 use std::hash::{Hash, Hasher};
276
277 use super::{RestorationData, RestorationMap};
278
279 fn hash_of(value: &RestorationData) -> u64 {
280 let mut hasher = DefaultHasher::new();
281 value.hash(&mut hasher);
282 hasher.finish()
283 }
284
285 #[test]
286 fn zero_and_negative_zero_are_one_key() {
287 let zero = RestorationData::from(0.0);
288 let negative_zero = RestorationData::from(-0.0);
289 assert_eq!(zero, negative_zero);
290 assert_eq!(hash_of(&zero), hash_of(&negative_zero));
291 }
292
293 #[test]
294 fn a_map_keyed_by_value_finds_what_it_stored() {
295 let mut map = RestorationMap::new();
296 map.insert("value1".into(), 10i64.into());
297 map.insert(12i64.into(), vec![1.5f64, 2.5].into());
298
299 assert_eq!(
300 map.get(&RestorationData::from("value1")).unwrap().as_int(),
301 Some(10)
302 );
303 assert_eq!(
304 map.get(&RestorationData::from(12i64))
305 .unwrap()
306 .as_float64_list(),
307 Some([1.5, 2.5].as_slice())
308 );
309 assert!(map.get(&RestorationData::from("missing")).is_none());
310 }
311
312 #[test]
313 fn an_optional_value_becomes_null() {
314 assert!(RestorationData::from(None::<i64>).is_null());
315 assert_eq!(RestorationData::from(Some(3i64)).as_int(), Some(3));
316 }
317}