holium_rs_sdk/internal/
data_tree.rs

1//! Data trees are responsible for recursively holding holium data. Leaves hold scalar CBOR values
2//! while non-leaf nodes point to ordered children.
3
4use crate::internal::key_tree::Node as KeyNode;
5use anyhow::Result;
6use serde::{Deserialize, Serialize};
7use serde_cbor::Value as CborValue;
8use std::collections::BTreeMap;
9
10#[derive(thiserror::Error, Debug)]
11enum Error {
12    #[error("float types are currently unhandled")]
13    FloatUnhandled,
14}
15
16#[derive(Debug, PartialEq, Serialize, Deserialize)]
17/// Value held by the leaf of a data tree
18pub(crate) enum Value {
19    Null,
20    Bool(bool),
21    Integer(i128),
22    Bytes(Vec<u8>),
23    Text(String),
24}
25
26impl Value {
27    pub(crate) fn to_cbor(&self) -> CborValue {
28        match self {
29            Value::Null => CborValue::Null,
30            Value::Bool(v) => CborValue::Bool(*v),
31            Value::Integer(v) => CborValue::Integer(*v),
32            Value::Bytes(v) => CborValue::Bytes(v.clone()),
33            Value::Text(v) => CborValue::Text(v.clone()),
34        }
35    }
36}
37
38#[derive(Debug, PartialEq, Serialize, Deserialize)]
39/// Recursive structure building simple data trees
40pub struct Node {
41    pub(crate) value: Option<Value>,
42    pub(crate) children: Vec<Node>,
43}
44
45impl Node {
46    /// Create a data tree from a Cbor value
47    pub fn new(src_value: CborValue) -> Result<Self> {
48        fn new_leaf(v: Value) -> Result<Node> {
49            Ok(Node {
50                value: Some(v),
51                children: vec![],
52            })
53        }
54        fn new_non_leaf(children: Vec<Node>) -> Result<Node> {
55            Ok(Node {
56                value: None,
57                children,
58            })
59        }
60
61        match src_value {
62            CborValue::Null => new_leaf(Value::Null),
63            CborValue::Bool(v) => new_leaf(Value::Bool(v)),
64            CborValue::Integer(v) => new_leaf(Value::Integer(v)),
65            CborValue::Float(_) => Err(Error::FloatUnhandled.into()),
66            CborValue::Bytes(v) => new_leaf(Value::Bytes(v)),
67            CborValue::Text(v) => new_leaf(Value::Text(v)),
68            CborValue::Tag(_, boxed_value) => Self::new(*boxed_value),
69            CborValue::Array(values) => new_non_leaf(
70                values
71                    .into_iter()
72                    .map(|v| Self::new(v))
73                    .collect::<Result<Vec<Node>>>()?,
74            ),
75            CborValue::Map(tree_map) => new_non_leaf(
76                tree_map
77                    .into_values()
78                    .map(|v| Self::new(v))
79                    .collect::<Result<Vec<Node>>>()?,
80            ),
81            CborValue::__Hidden => unreachable!(),
82        }
83    }
84
85    /// Fuse a key tree and a node tree to generate a Cbor structure based on them
86    pub fn assign_keys(&self, key_node: &KeyNode) -> CborValue {
87        match &self.value {
88            Some(value) => value.to_cbor(),
89            None => {
90                if &key_node.children.len() > &(0usize) {
91                    let mut map: BTreeMap<CborValue, CborValue> = BTreeMap::new();
92
93                    for (i, child) in self.children.iter().enumerate() {
94                        // todo We can unwrap here as we will handle the error more properly later on
95                        let key = &key_node.children.get(i).unwrap();
96                        map.insert(
97                            CborValue::Text(String::from(key.value.unwrap())),
98                            child.assign_keys(key),
99                        );
100                    }
101
102                    CborValue::Map(map)
103                } else {
104                    let mut cbor_values: Vec<CborValue> = Vec::new();
105                    for node in self.children.iter() {
106                        cbor_values.push(node.assign_keys(&KeyNode::default()));
107                    }
108                    CborValue::Array(cbor_values)
109                }
110            }
111        }
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use serde::Serialize;
118    use serde_cbor::value::to_value;
119    use std::collections::BTreeMap;
120
121    use crate::internal::key_tree::GenerateNode;
122
123    use super::*;
124
125    #[test]
126    fn can_represent_null_value() {
127        assert_eq!(
128            Node::new(CborValue::Null).unwrap(),
129            Node {
130                value: Some(Value::Null),
131                children: vec![]
132            }
133        )
134    }
135
136    #[test]
137    fn can_represent_boolean_value() {
138        assert_eq!(
139            Node::new(CborValue::from(true)).unwrap(),
140            Node {
141                value: Some(Value::Bool(true)),
142                children: vec![]
143            }
144        );
145        assert_eq!(
146            Node::new(CborValue::from(false)).unwrap(),
147            Node {
148                value: Some(Value::Bool(false)),
149                children: vec![]
150            }
151        )
152    }
153
154    #[test]
155    fn can_represent_array() {
156        assert_eq!(
157            Node::new(CborValue::from(vec![
158                CborValue::from(vec![CborValue::Null]),
159                CborValue::Null,
160            ]))
161            .unwrap(),
162            Node {
163                value: None,
164                children: vec![
165                    Node {
166                        value: None,
167                        children: vec![Node {
168                            value: Some(Value::Null),
169                            children: vec![]
170                        }],
171                    },
172                    Node {
173                        value: Some(Value::Null),
174                        children: vec![]
175                    },
176                ],
177            }
178        )
179    }
180
181    #[test]
182    fn can_represent_map() {
183        let mut tree_map = BTreeMap::new();
184        tree_map.insert(CborValue::Null, CborValue::Integer(0));
185        assert_eq!(
186            Node::new(CborValue::from(tree_map)).unwrap(),
187            Node {
188                value: None,
189                children: vec![Node {
190                    value: Some(Value::Integer(0)),
191                    children: vec![]
192                },],
193            }
194        )
195    }
196
197    #[test]
198    fn can_import_tagged_value() {
199        assert_eq!(
200            Node::new(CborValue::Tag(0, Box::from(CborValue::Null),)).unwrap(),
201            Node {
202                value: Some(Value::Null),
203                children: vec![]
204            }
205        )
206    }
207
208    #[test]
209    fn can_assign_map() {
210        #[derive(Eq, PartialEq, Serialize)]
211        struct Structure {
212            key: NestedStructure,
213        }
214        // This code is generated in the wasm module while compiling
215        impl GenerateNode for Structure {
216            fn generate_node() -> KeyNode {
217                KeyNode {
218                    value: None,
219                    children: vec![KeyNode {
220                        value: Some("key"),
221                        children: NestedStructure::generate_node().children,
222                    }],
223                }
224            }
225        }
226
227        #[derive(Eq, PartialEq, Serialize)]
228        struct NestedStructure {
229            key: u8,
230        }
231
232        // This code is generated in the wasm module while compiling
233        impl GenerateNode for NestedStructure {
234            fn generate_node() -> KeyNode {
235                KeyNode {
236                    value: None,
237                    children: vec![KeyNode {
238                        value: Some("key"),
239                        children: u8::generate_node().children,
240                    }],
241                }
242            }
243        }
244
245        let structure = Structure {
246            key: NestedStructure { key: 0 },
247        };
248
249        let structure_cbor = to_value(structure).unwrap();
250
251        let structure_data = Node::new(structure_cbor.clone()).unwrap();
252
253        let structure_assigned = structure_data.assign_keys(&Structure::generate_node());
254
255        assert_eq!(structure_cbor, structure_assigned);
256    }
257
258    #[test]
259    fn can_assign_array() {
260        #[derive(Eq, PartialEq, Serialize)]
261        struct Structure {
262            key: Vec<u8>,
263        }
264
265        // This code is generated in the wasm module while compiling
266        impl GenerateNode for Structure {
267            fn generate_node() -> KeyNode {
268                KeyNode {
269                    value: None,
270                    children: vec![KeyNode {
271                        value: Some("key"),
272                        children: Vec::<u8>::generate_node().children,
273                    }],
274                }
275            }
276        }
277
278        let structure = Structure {
279            key: vec![0, 1, 2, 3],
280        };
281
282        let structure_cbor = to_value(structure).unwrap();
283
284        let structure_data = Node::new(structure_cbor.clone()).unwrap();
285
286        let structure_assigned = structure_data.assign_keys(&Structure::generate_node());
287
288        assert_eq!(structure_cbor, structure_assigned);
289    }
290}