dpp/util/cbor_value/
value.rs1use std::convert::{TryFrom, TryInto};
2
3use ciborium::value::Value;
4use itertools::Itertools;
5
6use crate::util::{
7 cbor_value::convert::convert_to,
8 json_path::{JsonPath, JsonPathLiteral, JsonPathStep},
9};
10
11use super::{FieldType, ReplacePaths, ValuesCollection};
12
13impl ValuesCollection for ciborium::value::Value {
14 type Value = ciborium::value::Value;
15 type Key = ciborium::value::Value;
16
17 fn get(&self, key: &Self::Value) -> Option<&Self::Value> {
18 match self {
19 Value::Array(ref arr) => {
20 if let Some(idx) = key.as_integer() {
21 let idx: usize = idx.try_into().ok()?;
22 arr.get(idx)
23 } else {
24 None
25 }
26 }
27 Value::Map(map) => map
28 .iter()
29 .find_map(|(k, v)| if k == key { Some(v) } else { None }),
30
31 _ => None,
32 }
33 }
34
35 fn get_mut(&mut self, key: &Self::Value) -> Option<&mut Self::Value> {
36 match self {
37 Value::Array(ref mut arr) => {
38 if let Some(idx) = key.as_integer() {
39 let idx: usize = idx.try_into().ok()?;
40 arr.get_mut(idx)
41 } else {
42 None
43 }
44 }
45 Value::Map(map) => map
46 .iter_mut()
47 .find_map(|(k, v)| if k == key { Some(v) } else { None }),
48
49 _ => None,
50 }
51 }
52
53 fn remove(&mut self, key: impl Into<Self::Key>) -> Option<Self::Value> {
54 let key_cbor: Self::Key = key.into();
55 match self {
56 Value::Array(ref mut arr) => {
57 if let Some(idx) = key_cbor.as_integer() {
58 let idx: usize = idx.try_into().ok()?;
59 if arr.len() < idx {
60 return Some(arr.remove(idx));
61 }
62 }
63 None
64 }
65 Value::Map(map) => {
66 if let Some(idx) = map.iter().position(|(el_key, _)| el_key == &key_cbor) {
67 let (_, v) = map.remove(idx);
68 return Some(v);
69 }
70 None
71 }
72 _ => None,
73 }
74 }
75}
76
77impl ReplacePaths for ciborium::value::Value {
78 type Value = ciborium::value::Value;
79
80 fn replace_paths<I, C>(&mut self, paths: I, from: FieldType, to: FieldType)
81 where
82 I: IntoIterator<Item = C>,
83 C: AsRef<str>,
84 {
85 for path in paths.into_iter() {
86 self.replace_path(path.as_ref(), from, to);
87 }
88 }
89
90 fn replace_path(&mut self, path: &str, from: FieldType, to: FieldType) -> Option<()> {
91 let cbor_value = self.get_path_mut(path)?;
92 let replace_with = convert_to(cbor_value, from, to)?;
93
94 *cbor_value = replace_with;
95
96 Some(())
97 }
98
99 fn get_path_mut(&mut self, path: &str) -> Option<&mut Value> {
100 let cbor_path = to_path_of_cbors(path).ok()?;
101
102 if cbor_path.is_empty() {
103 return None;
104 }
105 if cbor_path.len() == 1 {
106 return self.get_mut(&cbor_path[0]);
107 }
108
109 let mut current_level: &mut Value = self.get_mut(&cbor_path[0])?;
110 for step in cbor_path.iter().skip(1) {
111 match current_level {
112 Value::Map(ref mut cbor_map) => current_level = get_from_cbor_map(cbor_map, step)?,
113 Value::Array(ref mut cbor_array) => {
114 if let Some(idx) = step.as_integer() {
115 let id: usize = idx.try_into().ok()?;
116 current_level = cbor_array.get_mut(id)?
117 } else {
118 return None;
119 }
120 }
121 _ => {
122 }
124 }
125 }
126 Some(current_level)
127 }
128}
129
130pub fn get_from_cbor_map<'a>(
131 cbor_map: &'a mut [(Value, Value)],
132 key: &Value,
133) -> Option<&'a mut Value> {
134 cbor_map.iter_mut().find_map(|(current_key, value)| {
135 if current_key == key {
136 Some(value)
137 } else {
138 None
139 }
140 })
141}
142
143pub fn to_path_of_cbors(path: &str) -> Result<Vec<Value>, anyhow::Error> {
144 let json_path = JsonPath::try_from(JsonPathLiteral(path))?;
145
146 Ok(json_path
147 .into_iter()
148 .map(|step| match step {
149 JsonPathStep::Key(key) => Value::Text(key),
150 JsonPathStep::Index(index) => Value::Integer(index.into()),
151 })
152 .collect_vec())
153}