devicetree_tool/
node.rs

1// Copyright (c) 2023, Michael Zhao
2// SPDX-License-Identifier: MIT
3
4use crate::dts_generator::DtsGenerator;
5use crate::property::Property;
6use std::sync::{Arc, Mutex};
7
8/// A node that is used to describe a device.
9///
10/// A node has a list of properties that are represented with a vector of `Property`.
11///
12/// `Node` can also contain other nodes.
13pub struct Node {
14    pub name: String,
15    pub label: Option<String>,
16    pub properties: Vec<Arc<Mutex<Property>>>,
17    pub sub_nodes: Vec<Arc<Mutex<Node>>>,
18}
19
20impl Node {
21    /// Create an empty `Node` with name.
22    ///
23    /// # Example
24    ///
25    /// ```
26    /// use devicetree_tool::Node;
27    ///
28    /// let node = Node::new("node");
29    ///
30    /// assert_eq!(format!("{}", node), "node {\n};\n");
31    /// ```
32    pub fn new(name: &str) -> Self {
33        Node {
34            name: String::from(name),
35            label: None,
36            properties: Vec::new(),
37            sub_nodes: Vec::new(),
38        }
39    }
40
41    /// Create an empty `Node` with name and label.
42    ///
43    /// # Example
44    ///
45    /// ```
46    /// use devicetree_tool::Node;
47    ///
48    /// let node = Node::new_with_label("node", "label");
49    ///
50    /// assert_eq!(format!("{}", node), "label: node {\n};\n");
51    /// ```
52    pub fn new_with_label(name: &str, label: &str) -> Self {
53        Node {
54            name: String::from(name),
55            label: Some(String::from(label)),
56            properties: Vec::new(),
57            sub_nodes: Vec::new(),
58        }
59    }
60
61    /// Add a `Property` to the `Node`.
62    ///
63    /// # Example
64    ///
65    /// ```
66    /// use devicetree_tool::Node;
67    /// use devicetree_tool::Property;
68    ///
69    /// let mut node = Node::new("node");
70    ///
71    /// node.add_property(Property::new_u32("prop1", 42));
72    /// node.add_property(Property::new_str("prop2", "hello"));
73    ///
74    /// assert_eq!(node.properties.len(), 2);
75    ///
76    /// assert_eq!(format!("{}", node),
77    ///            "node {\n\tprop1 = <0x0 0x0 0x0 0x2a>;\n\t\
78    ///            prop2 = <0x68 0x65 0x6c 0x6c 0x6f 0x0>;\n};\n");
79    /// ```
80    pub fn add_property(&mut self, prop: Property) {
81        self.properties.push(Arc::new(Mutex::new(prop)));
82    }
83
84    /// Add a sub node to the `Node`.
85    ///
86    /// # Example
87    ///
88    /// ```
89    /// use devicetree_tool::Node;
90    /// use devicetree_tool::Property;
91    ///
92    /// let mut node = Node::new("node");
93    ///
94    /// // Create a sub node
95    /// let mut sub_node = Node::new("sub_node");
96    /// sub_node.add_property(Property::new_u32("prop", 42));
97    ///
98    /// // Add the sub node
99    /// node.add_sub_node(sub_node);
100    ///
101    /// assert_eq!(node.sub_nodes.len(), 1);
102    /// assert_eq!(format!("{}", node),
103    ///            "node {\n\n\tsub_node {\n\t\tprop = <0x0 0x0 0x0 0x2a>;\n\t};\n};\n");
104    /// ```
105    pub fn add_sub_node(&mut self, sub_node: Node) {
106        self.sub_nodes.push(Arc::new(Mutex::new(sub_node)));
107    }
108
109    /// Find `Property` from a `Node` by name.
110    ///
111    /// # Example
112    ///
113    /// ```
114    /// use devicetree_tool::Node;
115    /// use devicetree_tool::Property;
116    ///
117    /// let mut node = Node::new("node");
118    ///
119    /// // Now the node hasn't any property
120    /// assert_eq!(node.find_property("prop").is_none(), true);
121    ///
122    /// // Add a property
123    /// node.add_property(Property::new_u32("prop", 42));
124    ///
125    /// // Find the property from the node
126    /// let prop = node.find_property("prop").unwrap();
127    ///
128    /// assert_eq!(prop.lock().unwrap().value, vec![0u8, 0u8, 0u8, 42u8]);
129    /// ```
130    pub fn find_property(&self, name: &str) -> Option<Arc<Mutex<Property>>> {
131        for prop in &self.properties {
132            if name == prop.lock().unwrap().name {
133                return Some(prop.clone());
134            }
135        }
136        None
137    }
138
139    /// Find sub node from a `Node` by name.
140    ///
141    /// # Example
142    ///
143    /// ```
144    /// use devicetree_tool::Node;
145    /// use devicetree_tool::Property;
146    ///
147    /// let mut node = Node::new("node");
148    ///
149    /// // Now the node hasn't any sub node
150    /// assert_eq!(node.find_subnode_by_name("subnode").is_none(), true);
151    ///
152    /// // Add a sub node
153    /// node.add_sub_node(Node::new("subnode"));
154    ///
155    /// // Find the sub node from the node
156    /// let sub_node = node.find_subnode_by_name("subnode").unwrap();
157    ///
158    /// assert_eq!(sub_node.lock().unwrap().name, "subnode");
159    /// ```
160    pub fn find_subnode_by_name(&self, name: &str) -> Option<Arc<Mutex<Node>>> {
161        for sub_node in &self.sub_nodes {
162            if sub_node.lock().unwrap().name == name {
163                return Some(sub_node.clone());
164            }
165        }
166        None
167    }
168
169    /// Find sub node from a `Node` by label.
170    ///
171    /// # Example
172    ///
173    /// ```
174    /// use devicetree_tool::Node;
175    /// use devicetree_tool::Property;
176    ///
177    /// let mut node = Node::new("node");
178    ///
179    /// // Now the node hasn't any sub node
180    /// assert_eq!(node.find_subnode_by_label("label").is_none(), true);
181    ///
182    /// // Add a sub node
183    /// node.add_sub_node(Node::new_with_label("subnode", "label"));
184    ///
185    /// // Find the sub node from the node
186    /// let sub_node = node.find_subnode_by_label("label").unwrap();
187    ///
188    /// assert_eq!(sub_node.lock().unwrap().name, "subnode");
189    /// ```
190    pub fn find_subnode_by_label(&self, label: &str) -> Option<Arc<Mutex<Node>>> {
191        for sub_node in &self.sub_nodes {
192            if let Some(sub_node_label) = &sub_node.lock().unwrap().label {
193                if sub_node_label == label {
194                    return Some(sub_node.clone());
195                }
196            }
197            let sub_node_with_label = sub_node.lock().unwrap().find_subnode_by_label(label);
198            if sub_node_with_label.is_some() {
199                return sub_node_with_label;
200            }
201        }
202        None
203    }
204
205    /// Find sub node from a `Node` by path.
206    ///
207    /// # Example
208    ///
209    /// ```
210    /// use devicetree_tool::Node;
211    /// use devicetree_tool::Property;
212    ///
213    /// let mut node_layer_1 = Node::new("node_layer_1");
214    ///
215    /// // Now the node hasn't any sub node
216    /// assert_eq!(node_layer_1.find_subnode_by_path(vec![ "node_layer_2", "node_layer_3"]).is_none(), true);
217    ///
218    /// // Create a layer-2 sub node
219    /// let mut node_layer_2 = Node::new("node_layer_2");
220    ///
221    /// // Add a layer-3 sub node
222    /// node_layer_2.add_sub_node(Node::new("node_layer_3"));
223    ///
224    /// node_layer_1.add_sub_node(node_layer_2);
225    ///
226    /// // Find the layer-3 sub node
227    /// let sub_node = node_layer_1.find_subnode_by_path(vec!["node_layer_2", "node_layer_3"]).unwrap();
228    ///
229    /// assert_eq!(sub_node.lock().unwrap().name, "node_layer_3");
230    /// ```
231    pub fn find_subnode_by_path(&self, path: Vec<&str>) -> Option<Arc<Mutex<Node>>> {
232        for sub_node in &self.sub_nodes {
233            if sub_node.lock().unwrap().name == path[0] {
234                if path.len() == 1 {
235                    // Found the matching node
236                    return Some(sub_node.clone());
237                } else {
238                    // There are more to match
239                    let sub_node_with_path = sub_node
240                        .lock()
241                        .unwrap()
242                        .find_subnode_by_path(path[1..].to_vec());
243                    if sub_node_with_path.is_some() {
244                        return sub_node_with_path;
245                    }
246                }
247            }
248        }
249        None
250    }
251}
252
253impl std::fmt::Display for Node {
254    /// Print a `Property` in the format of DTS
255    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
256        let s = DtsGenerator::generate_node(self, 0);
257        writeln!(f, "{s}")
258    }
259}
260
261#[cfg(test)]
262mod tests {
263    use super::*;
264    use crate::property::Property;
265
266    #[test]
267    fn test_node_empty() {
268        let node = Node::new("node");
269        assert_eq!(node.properties.len(), 0);
270        assert_eq!(node.sub_nodes.len(), 0);
271    }
272
273    #[test]
274    fn test_node_sub_nodes() {
275        let mut node = Node::new("node");
276        node.add_sub_node(Node::new("sub_node_0"));
277        node.add_sub_node(Node::new("sub_node_1"));
278        node.add_sub_node(Node::new("sub_node_2"));
279
280        let mut sub_node_3 = Node::new("sub_node_3");
281        sub_node_3.add_sub_node(Node::new("sub_node_30"));
282        sub_node_3.add_sub_node(Node::new("sub_node_31"));
283
284        assert_eq!(sub_node_3.sub_nodes.len(), 2);
285
286        node.add_sub_node(sub_node_3);
287        assert_eq!(node.sub_nodes.len(), 4);
288    }
289
290    #[test]
291    fn test_node_properties() {
292        let mut node = Node::new("node");
293        node.add_property(Property::new_empty("prop0"));
294        node.add_property(Property::new_u32("prop1", 42));
295        assert_eq!(node.properties.len(), 2);
296    }
297
298    #[test]
299    fn test_property_print() {
300        let mut node = Node::new("node");
301        node.add_property(Property::new_u32("prop", 42));
302        let mut sub_node = Node::new("node");
303        sub_node.add_property(Property::new_u32("prop", 12));
304        node.add_sub_node(sub_node);
305
306        let printing = format!("{}", node);
307        assert_eq!(&printing, "node {\n\tprop = <0x0 0x0 0x0 0x2a>;\n\n\tnode {\n\t\tprop = <0x0 0x0 0x0 0xc>;\n\t};\n};\n");
308    }
309
310    #[test]
311    fn test_find_subnode_by_path() {
312        let mut node_layer_1 = Node::new("node_layer_1");
313
314        assert_eq!(
315            node_layer_1
316                .find_subnode_by_path(vec!["node_layer_2", "node_layer_3"])
317                .is_none(),
318            true
319        );
320
321        let mut node_layer_2 = Node::new("node_layer_2");
322        node_layer_2.add_sub_node(Node::new("node_layer_3"));
323        node_layer_1.add_sub_node(node_layer_2);
324
325        let sub_node = node_layer_1
326            .find_subnode_by_path(vec!["node_layer_2", "node_layer_3"])
327            .unwrap();
328        assert_eq!(sub_node.lock().unwrap().name, "node_layer_3");
329    }
330}