1use std::convert::TryInto;
2
3use anyhow::anyhow;
4use ciborium::value::Value as CborValue;
5use serde_json::{Map, Value as JsonValue};
6
7use crate::ProtocolError;
8mod convert;
9pub use convert::FieldType;
10
11mod value;
12pub use value::*;
13
14mod canonical;
15pub use canonical::*;
16
17mod map;
18pub use map::*;
19
20pub trait ValuesCollection {
21 type Key;
22 type Value;
23
24 fn get_mut(&mut self, key: &Self::Key) -> Option<&mut Self::Value>;
25 fn get(&self, key: &Self::Key) -> Option<&Self::Value>;
26 fn remove(&mut self, key_to_remove: impl Into<Self::Key>) -> Option<Self::Value>;
27}
28
29pub trait ReplacePaths: ValuesCollection {
30 type Value;
31
32 fn replace_paths<I, C>(&mut self, paths: I, from: FieldType, to: FieldType)
33 where
34 I: IntoIterator<Item = C>,
35 C: AsRef<str>;
36
37 fn replace_path(&mut self, path: &str, from: FieldType, to: FieldType) -> Option<()>;
38 fn get_path_mut(&mut self, path: &str) -> Option<&mut <Self as ReplacePaths>::Value>;
39}
40
41pub fn get_key_from_cbor_map<'a>(
42 cbor_map: &'a [(CborValue, CborValue)],
43 key: &'a str,
44) -> Option<&'a CborValue> {
45 for (cbor_key, cbor_value) in cbor_map.iter() {
46 if !cbor_key.is_text() {
47 continue;
48 }
49
50 if cbor_key.as_text().expect("confirmed as text") == key {
51 return Some(cbor_value);
52 }
53 }
54 None
55}
56
57impl CborMapExtension for &Vec<(CborValue, CborValue)> {
58 fn as_u16(&self, key: &str, error_message: &str) -> Result<u16, ProtocolError> {
59 let key_value = get_key_from_cbor_map(self, key)
60 .ok_or_else(|| ProtocolError::DecodingError(String::from(error_message)))?;
61 if let CborValue::Integer(integer_value) = key_value {
62 return Ok(i128::from(*integer_value) as u16);
63 }
64 Err(ProtocolError::DecodingError(String::from(error_message)))
65 }
66
67 fn as_u8(&self, key: &str, error_message: &str) -> Result<u8, ProtocolError> {
68 let key_value = get_key_from_cbor_map(self, key)
69 .ok_or_else(|| ProtocolError::DecodingError(String::from(error_message)))?;
70 if let CborValue::Integer(integer_value) = key_value {
71 return Ok(i128::from(*integer_value) as u8);
72 }
73 Err(ProtocolError::DecodingError(String::from(error_message)))
74 }
75
76 fn as_bool(&self, key: &str, error_message: &str) -> Result<bool, ProtocolError> {
77 let key_value = get_key_from_cbor_map(self, key)
78 .ok_or_else(|| ProtocolError::DecodingError(String::from(error_message)))?;
79 if let CborValue::Bool(bool_value) = key_value {
80 return Ok(*bool_value);
81 }
82 Err(ProtocolError::DecodingError(String::from(error_message)))
83 }
84
85 fn as_bytes(&self, key: &str, error_message: &str) -> Result<Vec<u8>, ProtocolError> {
86 let key_value = get_key_from_cbor_map(self, key)
87 .ok_or_else(|| ProtocolError::DecodingError(String::from(error_message)))?;
88 match key_value {
89 CborValue::Bytes(bytes) => Ok(bytes.clone()),
90 CborValue::Array(array) => array
91 .iter()
92 .map(|byte| match byte {
93 CborValue::Integer(int) => {
94 let value_as_u8: u8 = (*int).try_into().map_err(|_| {
95 ProtocolError::DecodingError(String::from("expected u8 value"))
96 })?;
97 Ok(value_as_u8)
98 }
99 _ => Err(ProtocolError::DecodingError(String::from(
100 "not an array of integers",
101 ))),
102 })
103 .collect::<Result<Vec<u8>, ProtocolError>>(),
104 _ => Err(ProtocolError::DecodingError(String::from(error_message))),
105 }
106 }
107
108 fn as_string(&self, key: &str, error_message: &str) -> Result<String, ProtocolError> {
109 let key_value = get_key_from_cbor_map(self, key)
110 .ok_or_else(|| ProtocolError::DecodingError(String::from(error_message)))?;
111 if let CborValue::Text(string_value) = key_value {
112 return Ok(string_value.clone());
113 }
114 Err(ProtocolError::DecodingError(String::from(error_message)))
115 }
116
117 fn as_u64(&self, key: &str, error_message: &str) -> Result<u64, ProtocolError> {
118 let key_value = get_key_from_cbor_map(self, key)
119 .ok_or_else(|| ProtocolError::DecodingError(String::from(error_message)))?;
120 if let CborValue::Integer(integer_value) = key_value {
121 return Ok(i128::from(*integer_value) as u64);
122 }
123 Err(ProtocolError::DecodingError(String::from(error_message)))
124 }
125}
126
127pub fn cbor_value_to_json_value(cbor: &CborValue) -> Result<serde_json::Value, anyhow::Error> {
129 match cbor {
130 CborValue::Integer(num) => Ok(JsonValue::from(i128::from(*num) as i64)),
131 CborValue::Bytes(bytes) => Ok(JsonValue::Array(
132 bytes.iter().map(|byte| JsonValue::from(*byte)).collect(),
133 )),
134 CborValue::Float(float) => Ok(JsonValue::from(*float)),
135 CborValue::Text(text) => Ok(JsonValue::from(text.clone())),
136 CborValue::Bool(boolean) => Ok(JsonValue::from(*boolean)),
137 CborValue::Null => Ok(JsonValue::Null),
138 CborValue::Array(arr) => Ok(JsonValue::Array(
139 arr.iter()
140 .map(cbor_value_to_json_value)
141 .collect::<Result<Vec<JsonValue>, anyhow::Error>>()?,
142 )),
143 CborValue::Map(map) => cbor_map_to_json_map(map),
144 _ => Err(anyhow!("Can't convert CBOR to JSON: unknown type")),
145 }
146}
147
148pub fn cbor_value_into_json_value(cbor: CborValue) -> Result<serde_json::Value, anyhow::Error> {
149 match cbor {
150 CborValue::Integer(num) => Ok(JsonValue::from(i128::from(num) as i64)),
151 CborValue::Bytes(bytes) => Ok(JsonValue::Array(
152 bytes.into_iter().map(JsonValue::from).collect(),
153 )),
154 CborValue::Float(float) => Ok(JsonValue::from(float)),
155 CborValue::Text(text) => Ok(JsonValue::from(text)),
156 CborValue::Bool(boolean) => Ok(JsonValue::from(boolean)),
157 CborValue::Null => Ok(JsonValue::Null),
158 CborValue::Array(arr) => Ok(JsonValue::Array(
159 arr.into_iter()
160 .map(cbor_value_into_json_value)
161 .collect::<Result<Vec<JsonValue>, anyhow::Error>>()?,
162 )),
163 CborValue::Map(map) => cbor_map_into_json_map(map),
164 _ => Err(anyhow!("Can't convert CBOR to JSON: unknown type")),
165 }
166}
167
168pub fn cbor_map_to_json_map(
169 cbor_map: &[(CborValue, CborValue)],
170) -> Result<serde_json::Value, anyhow::Error> {
171 let mut json_vec = cbor_map
172 .iter()
173 .map(|(key, value)| {
174 Ok((
175 key.as_text()
176 .ok_or_else(|| anyhow!("Expect key to be a string"))?
177 .to_string(),
178 cbor_value_to_json_value(value)?,
179 ))
180 })
181 .collect::<Result<Vec<(String, JsonValue)>, anyhow::Error>>()?;
182
183 let mut json_map = Map::new();
184
185 for (key, value) in json_vec.drain(..) {
186 json_map.insert(key, value);
187 }
188
189 Ok(serde_json::Value::Object(json_map))
190}
191
192pub fn cbor_map_into_json_map(
193 cbor_map: Vec<(CborValue, CborValue)>,
194) -> Result<serde_json::Value, anyhow::Error> {
195 let mut json_vec = cbor_map
196 .into_iter()
197 .map(|(key, value)| {
198 Ok((
199 key.into_text()
200 .map_err(|_| anyhow!("Expect key to be a string"))?,
201 cbor_value_into_json_value(value)?,
202 ))
203 })
204 .collect::<Result<Vec<(String, JsonValue)>, anyhow::Error>>()?;
205
206 let mut json_map = Map::new();
207
208 for (key, value) in json_vec.drain(..) {
209 json_map.insert(key, value);
210 }
211
212 Ok(serde_json::Value::Object(json_map))
213}
214
215#[cfg(test)]
216#[allow(clippy::approx_constant)]
217mod tests {
218 use super::*;
219 use ciborium::value::Value as CborValue;
220 use serde_json::json;
221
222 #[test]
225 fn get_key_from_cbor_map_found() {
226 let map = vec![
227 (
228 CborValue::Text("name".to_string()),
229 CborValue::Text("Alice".to_string()),
230 ),
231 (
232 CborValue::Text("age".to_string()),
233 CborValue::Integer(30.into()),
234 ),
235 ];
236 let result = get_key_from_cbor_map(&map, "name");
237 assert_eq!(result, Some(&CborValue::Text("Alice".to_string())));
238 }
239
240 #[test]
241 fn get_key_from_cbor_map_not_found() {
242 let map = vec![(
243 CborValue::Text("name".to_string()),
244 CborValue::Text("Alice".to_string()),
245 )];
246 let result = get_key_from_cbor_map(&map, "missing");
247 assert!(result.is_none());
248 }
249
250 #[test]
251 fn get_key_from_cbor_map_skips_non_text_keys() {
252 let map = vec![
253 (CborValue::Integer(1.into()), CborValue::Bool(true)),
254 (CborValue::Text("key".to_string()), CborValue::Bool(false)),
255 ];
256 let result = get_key_from_cbor_map(&map, "key");
257 assert_eq!(result, Some(&CborValue::Bool(false)));
258 }
259
260 fn make_cbor_map(pairs: Vec<(&str, CborValue)>) -> Vec<(CborValue, CborValue)> {
263 pairs
264 .into_iter()
265 .map(|(k, v)| (CborValue::Text(k.to_string()), v))
266 .collect()
267 }
268
269 #[test]
270 fn cbor_map_extension_as_u16() {
271 let map = make_cbor_map(vec![("val", CborValue::Integer(1234.into()))]);
272 let result = (&map).as_u16("val", "err");
273 assert_eq!(result.unwrap(), 1234);
274 }
275
276 #[test]
277 fn cbor_map_extension_as_u16_missing() {
278 let map = make_cbor_map(vec![]);
279 let result = (&map).as_u16("val", "missing");
280 assert!(result.is_err());
281 }
282
283 #[test]
284 fn cbor_map_extension_as_u16_wrong_type() {
285 let map = make_cbor_map(vec![("val", CborValue::Text("hello".to_string()))]);
286 let result = (&map).as_u16("val", "err");
287 assert!(result.is_err());
288 }
289
290 #[test]
291 fn cbor_map_extension_as_u8() {
292 let map = make_cbor_map(vec![("val", CborValue::Integer(255.into()))]);
293 let result = (&map).as_u8("val", "err");
294 assert_eq!(result.unwrap(), 255);
295 }
296
297 #[test]
298 fn cbor_map_extension_as_bool() {
299 let map = make_cbor_map(vec![("flag", CborValue::Bool(true))]);
300 let result = (&map).as_bool("flag", "err");
301 assert!(result.unwrap());
302 }
303
304 #[test]
305 fn cbor_map_extension_as_bool_missing() {
306 let map = make_cbor_map(vec![]);
307 let result = (&map).as_bool("flag", "missing");
308 assert!(result.is_err());
309 }
310
311 #[test]
312 fn cbor_map_extension_as_bool_wrong_type() {
313 let map = make_cbor_map(vec![("flag", CborValue::Integer(1.into()))]);
314 let result = (&map).as_bool("flag", "err");
315 assert!(result.is_err());
316 }
317
318 #[test]
319 fn cbor_map_extension_as_bytes_from_bytes() {
320 let data = vec![1u8, 2, 3, 4];
321 let map = make_cbor_map(vec![("data", CborValue::Bytes(data.clone()))]);
322 let result = (&map).as_bytes("data", "err");
323 assert_eq!(result.unwrap(), data);
324 }
325
326 #[test]
327 fn cbor_map_extension_as_bytes_from_array() {
328 let array = vec![CborValue::Integer(10.into()), CborValue::Integer(20.into())];
329 let map = make_cbor_map(vec![("data", CborValue::Array(array))]);
330 let result = (&map).as_bytes("data", "err");
331 assert_eq!(result.unwrap(), vec![10u8, 20]);
332 }
333
334 #[test]
335 fn cbor_map_extension_as_bytes_wrong_type() {
336 let map = make_cbor_map(vec![("data", CborValue::Bool(true))]);
337 let result = (&map).as_bytes("data", "err");
338 assert!(result.is_err());
339 }
340
341 #[test]
342 fn cbor_map_extension_as_string() {
343 let map = make_cbor_map(vec![("s", CborValue::Text("hello".to_string()))]);
344 let result = (&map).as_string("s", "err");
345 assert_eq!(result.unwrap(), "hello");
346 }
347
348 #[test]
349 fn cbor_map_extension_as_string_wrong_type() {
350 let map = make_cbor_map(vec![("s", CborValue::Integer(1.into()))]);
351 let result = (&map).as_string("s", "err");
352 assert!(result.is_err());
353 }
354
355 #[test]
356 fn cbor_map_extension_as_u64() {
357 let map = make_cbor_map(vec![("n", CborValue::Integer(999999.into()))]);
358 let result = (&map).as_u64("n", "err");
359 assert_eq!(result.unwrap(), 999999);
360 }
361
362 #[test]
365 fn cbor_integer_to_json() {
366 let result = cbor_value_to_json_value(&CborValue::Integer(42.into())).unwrap();
367 assert_eq!(result, json!(42));
368 }
369
370 #[test]
371 fn cbor_text_to_json() {
372 let result = cbor_value_to_json_value(&CborValue::Text("hello".to_string())).unwrap();
373 assert_eq!(result, json!("hello"));
374 }
375
376 #[test]
377 fn cbor_bool_to_json() {
378 let result = cbor_value_to_json_value(&CborValue::Bool(true)).unwrap();
379 assert_eq!(result, json!(true));
380 }
381
382 #[test]
383 fn cbor_null_to_json() {
384 let result = cbor_value_to_json_value(&CborValue::Null).unwrap();
385 assert!(result.is_null());
386 }
387
388 #[test]
389 fn cbor_float_to_json() {
390 let result = cbor_value_to_json_value(&CborValue::Float(3.14)).unwrap();
391 assert_eq!(result, json!(3.14));
392 }
393
394 #[test]
395 fn cbor_bytes_to_json_array() {
396 let result = cbor_value_to_json_value(&CborValue::Bytes(vec![1, 2, 3])).unwrap();
397 assert_eq!(result, json!([1, 2, 3]));
398 }
399
400 #[test]
401 fn cbor_array_to_json_array() {
402 let cbor = CborValue::Array(vec![
403 CborValue::Integer(1.into()),
404 CborValue::Text("two".to_string()),
405 ]);
406 let result = cbor_value_to_json_value(&cbor).unwrap();
407 assert_eq!(result, json!([1, "two"]));
408 }
409
410 #[test]
411 fn cbor_map_to_json_object() {
412 let cbor = CborValue::Map(vec![(
413 CborValue::Text("key".to_string()),
414 CborValue::Integer(10.into()),
415 )]);
416 let result = cbor_value_to_json_value(&cbor).unwrap();
417 assert_eq!(result, json!({"key": 10}));
418 }
419
420 #[test]
423 fn cbor_into_json_integer() {
424 let result = cbor_value_into_json_value(CborValue::Integer(99.into())).unwrap();
425 assert_eq!(result, json!(99));
426 }
427
428 #[test]
429 fn cbor_into_json_text() {
430 let result = cbor_value_into_json_value(CborValue::Text("world".to_string())).unwrap();
431 assert_eq!(result, json!("world"));
432 }
433
434 #[test]
435 fn cbor_into_json_null() {
436 let result = cbor_value_into_json_value(CborValue::Null).unwrap();
437 assert!(result.is_null());
438 }
439
440 #[test]
441 fn cbor_into_json_nested_array() {
442 let cbor = CborValue::Array(vec![CborValue::Array(vec![CborValue::Integer(1.into())])]);
443 let result = cbor_value_into_json_value(cbor).unwrap();
444 assert_eq!(result, json!([[1]]));
445 }
446
447 #[test]
450 fn test_cbor_map_to_json_map_valid() {
451 let map = vec![
452 (
453 CborValue::Text("a".to_string()),
454 CborValue::Integer(1.into()),
455 ),
456 (CborValue::Text("b".to_string()), CborValue::Bool(false)),
457 ];
458 let result = cbor_map_to_json_map(&map).unwrap();
459 assert_eq!(result, json!({"a": 1, "b": false}));
460 }
461
462 #[test]
463 fn test_cbor_map_to_json_map_non_string_key() {
464 let map = vec![(CborValue::Integer(1.into()), CborValue::Bool(true))];
465 let result = cbor_map_to_json_map(&map);
466 assert!(result.is_err());
467 }
468
469 #[test]
472 fn test_cbor_map_into_json_map_valid() {
473 let map = vec![(
474 CborValue::Text("x".to_string()),
475 CborValue::Text("y".to_string()),
476 )];
477 let result = cbor_map_into_json_map(map).unwrap();
478 assert_eq!(result, json!({"x": "y"}));
479 }
480
481 #[test]
482 fn test_cbor_map_into_json_map_non_string_key() {
483 let map = vec![(CborValue::Integer(1.into()), CborValue::Bool(true))];
484 let result = cbor_map_into_json_map(map);
485 assert!(result.is_err());
486 }
487}