dpp/util/cbor_value/
mod.rs

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
127// TODO: the issue with stack overflow should be address through re-implementation of the algorithm
128pub 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)]
216mod tests {
217    use super::*;
218    use ciborium::value::Value as CborValue;
219    use serde_json::json;
220
221    // --- get_key_from_cbor_map ---
222
223    #[test]
224    fn get_key_from_cbor_map_found() {
225        let map = vec![
226            (
227                CborValue::Text("name".to_string()),
228                CborValue::Text("Alice".to_string()),
229            ),
230            (
231                CborValue::Text("age".to_string()),
232                CborValue::Integer(30.into()),
233            ),
234        ];
235        let result = get_key_from_cbor_map(&map, "name");
236        assert_eq!(result, Some(&CborValue::Text("Alice".to_string())));
237    }
238
239    #[test]
240    fn get_key_from_cbor_map_not_found() {
241        let map = vec![(
242            CborValue::Text("name".to_string()),
243            CborValue::Text("Alice".to_string()),
244        )];
245        let result = get_key_from_cbor_map(&map, "missing");
246        assert!(result.is_none());
247    }
248
249    #[test]
250    fn get_key_from_cbor_map_skips_non_text_keys() {
251        let map = vec![
252            (CborValue::Integer(1.into()), CborValue::Bool(true)),
253            (CborValue::Text("key".to_string()), CborValue::Bool(false)),
254        ];
255        let result = get_key_from_cbor_map(&map, "key");
256        assert_eq!(result, Some(&CborValue::Bool(false)));
257    }
258
259    // --- CborMapExtension for &Vec<(CborValue, CborValue)> ---
260
261    fn make_cbor_map(pairs: Vec<(&str, CborValue)>) -> Vec<(CborValue, CborValue)> {
262        pairs
263            .into_iter()
264            .map(|(k, v)| (CborValue::Text(k.to_string()), v))
265            .collect()
266    }
267
268    #[test]
269    fn cbor_map_extension_as_u16() {
270        let map = make_cbor_map(vec![("val", CborValue::Integer(1234.into()))]);
271        let result = (&map).as_u16("val", "err");
272        assert_eq!(result.unwrap(), 1234);
273    }
274
275    #[test]
276    fn cbor_map_extension_as_u16_missing() {
277        let map = make_cbor_map(vec![]);
278        let result = (&map).as_u16("val", "missing");
279        assert!(result.is_err());
280    }
281
282    #[test]
283    fn cbor_map_extension_as_u16_wrong_type() {
284        let map = make_cbor_map(vec![("val", CborValue::Text("hello".to_string()))]);
285        let result = (&map).as_u16("val", "err");
286        assert!(result.is_err());
287    }
288
289    #[test]
290    fn cbor_map_extension_as_u8() {
291        let map = make_cbor_map(vec![("val", CborValue::Integer(255.into()))]);
292        let result = (&map).as_u8("val", "err");
293        assert_eq!(result.unwrap(), 255);
294    }
295
296    #[test]
297    fn cbor_map_extension_as_bool() {
298        let map = make_cbor_map(vec![("flag", CborValue::Bool(true))]);
299        let result = (&map).as_bool("flag", "err");
300        assert!(result.unwrap());
301    }
302
303    #[test]
304    fn cbor_map_extension_as_bool_missing() {
305        let map = make_cbor_map(vec![]);
306        let result = (&map).as_bool("flag", "missing");
307        assert!(result.is_err());
308    }
309
310    #[test]
311    fn cbor_map_extension_as_bool_wrong_type() {
312        let map = make_cbor_map(vec![("flag", CborValue::Integer(1.into()))]);
313        let result = (&map).as_bool("flag", "err");
314        assert!(result.is_err());
315    }
316
317    #[test]
318    fn cbor_map_extension_as_bytes_from_bytes() {
319        let data = vec![1u8, 2, 3, 4];
320        let map = make_cbor_map(vec![("data", CborValue::Bytes(data.clone()))]);
321        let result = (&map).as_bytes("data", "err");
322        assert_eq!(result.unwrap(), data);
323    }
324
325    #[test]
326    fn cbor_map_extension_as_bytes_from_array() {
327        let array = vec![CborValue::Integer(10.into()), CborValue::Integer(20.into())];
328        let map = make_cbor_map(vec![("data", CborValue::Array(array))]);
329        let result = (&map).as_bytes("data", "err");
330        assert_eq!(result.unwrap(), vec![10u8, 20]);
331    }
332
333    #[test]
334    fn cbor_map_extension_as_bytes_wrong_type() {
335        let map = make_cbor_map(vec![("data", CborValue::Bool(true))]);
336        let result = (&map).as_bytes("data", "err");
337        assert!(result.is_err());
338    }
339
340    #[test]
341    fn cbor_map_extension_as_string() {
342        let map = make_cbor_map(vec![("s", CborValue::Text("hello".to_string()))]);
343        let result = (&map).as_string("s", "err");
344        assert_eq!(result.unwrap(), "hello");
345    }
346
347    #[test]
348    fn cbor_map_extension_as_string_wrong_type() {
349        let map = make_cbor_map(vec![("s", CborValue::Integer(1.into()))]);
350        let result = (&map).as_string("s", "err");
351        assert!(result.is_err());
352    }
353
354    #[test]
355    fn cbor_map_extension_as_u64() {
356        let map = make_cbor_map(vec![("n", CborValue::Integer(999999.into()))]);
357        let result = (&map).as_u64("n", "err");
358        assert_eq!(result.unwrap(), 999999);
359    }
360
361    // --- cbor_value_to_json_value ---
362
363    #[test]
364    fn cbor_integer_to_json() {
365        let result = cbor_value_to_json_value(&CborValue::Integer(42.into())).unwrap();
366        assert_eq!(result, json!(42));
367    }
368
369    #[test]
370    fn cbor_text_to_json() {
371        let result = cbor_value_to_json_value(&CborValue::Text("hello".to_string())).unwrap();
372        assert_eq!(result, json!("hello"));
373    }
374
375    #[test]
376    fn cbor_bool_to_json() {
377        let result = cbor_value_to_json_value(&CborValue::Bool(true)).unwrap();
378        assert_eq!(result, json!(true));
379    }
380
381    #[test]
382    fn cbor_null_to_json() {
383        let result = cbor_value_to_json_value(&CborValue::Null).unwrap();
384        assert!(result.is_null());
385    }
386
387    #[test]
388    fn cbor_float_to_json() {
389        let result = cbor_value_to_json_value(&CborValue::Float(3.14)).unwrap();
390        assert_eq!(result, json!(3.14));
391    }
392
393    #[test]
394    fn cbor_bytes_to_json_array() {
395        let result = cbor_value_to_json_value(&CborValue::Bytes(vec![1, 2, 3])).unwrap();
396        assert_eq!(result, json!([1, 2, 3]));
397    }
398
399    #[test]
400    fn cbor_array_to_json_array() {
401        let cbor = CborValue::Array(vec![
402            CborValue::Integer(1.into()),
403            CborValue::Text("two".to_string()),
404        ]);
405        let result = cbor_value_to_json_value(&cbor).unwrap();
406        assert_eq!(result, json!([1, "two"]));
407    }
408
409    #[test]
410    fn cbor_map_to_json_object() {
411        let cbor = CborValue::Map(vec![(
412            CborValue::Text("key".to_string()),
413            CborValue::Integer(10.into()),
414        )]);
415        let result = cbor_value_to_json_value(&cbor).unwrap();
416        assert_eq!(result, json!({"key": 10}));
417    }
418
419    // --- cbor_value_into_json_value (owned) ---
420
421    #[test]
422    fn cbor_into_json_integer() {
423        let result = cbor_value_into_json_value(CborValue::Integer(99.into())).unwrap();
424        assert_eq!(result, json!(99));
425    }
426
427    #[test]
428    fn cbor_into_json_text() {
429        let result = cbor_value_into_json_value(CborValue::Text("world".to_string())).unwrap();
430        assert_eq!(result, json!("world"));
431    }
432
433    #[test]
434    fn cbor_into_json_null() {
435        let result = cbor_value_into_json_value(CborValue::Null).unwrap();
436        assert!(result.is_null());
437    }
438
439    #[test]
440    fn cbor_into_json_nested_array() {
441        let cbor = CborValue::Array(vec![CborValue::Array(vec![CborValue::Integer(1.into())])]);
442        let result = cbor_value_into_json_value(cbor).unwrap();
443        assert_eq!(result, json!([[1]]));
444    }
445
446    // --- cbor_map_to_json_map ---
447
448    #[test]
449    fn test_cbor_map_to_json_map_valid() {
450        let map = vec![
451            (
452                CborValue::Text("a".to_string()),
453                CborValue::Integer(1.into()),
454            ),
455            (CborValue::Text("b".to_string()), CborValue::Bool(false)),
456        ];
457        let result = cbor_map_to_json_map(&map).unwrap();
458        assert_eq!(result, json!({"a": 1, "b": false}));
459    }
460
461    #[test]
462    fn test_cbor_map_to_json_map_non_string_key() {
463        let map = vec![(CborValue::Integer(1.into()), CborValue::Bool(true))];
464        let result = cbor_map_to_json_map(&map);
465        assert!(result.is_err());
466    }
467
468    // --- cbor_map_into_json_map (owned) ---
469
470    #[test]
471    fn test_cbor_map_into_json_map_valid() {
472        let map = vec![(
473            CborValue::Text("x".to_string()),
474            CborValue::Text("y".to_string()),
475        )];
476        let result = cbor_map_into_json_map(map).unwrap();
477        assert_eq!(result, json!({"x": "y"}));
478    }
479
480    #[test]
481    fn test_cbor_map_into_json_map_non_string_key() {
482        let map = vec![(CborValue::Integer(1.into()), CborValue::Bool(true))];
483        let result = cbor_map_into_json_map(map);
484        assert!(result.is_err());
485    }
486}