Skip to main content

intel_crashlog/
node.rs

1// Copyright (C) 2025 Intel Corporation
2// SPDX-License-Identifier: MIT
3
4//! A tree-like data structure containing the decoded Crash Log registers.
5
6#[cfg(feature = "std")]
7use std::collections::{BTreeMap, btree_map};
8
9#[cfg(not(feature = "std"))]
10use alloc::{
11    collections::{BTreeMap, btree_map},
12    format,
13    string::String,
14};
15
16#[cfg(feature = "serialize")]
17use serde::ser::{Serialize, SerializeMap, Serializer};
18
19/// Crash Log register tree node type
20#[derive(Debug, Default, PartialEq, Eq)]
21pub enum NodeType {
22    /// Root of the register tree
23    #[default]
24    Root,
25    /// Component of the register tree
26    Section,
27    /// Root of the record section in the register tree
28    Record,
29    /// Crash Log field
30    Field { value: u64 },
31}
32
33/// Node of the Crash Log register tree
34#[derive(Debug, Default, PartialEq, Eq)]
35pub struct Node {
36    /// Name of the node
37    pub name: String,
38    /// Description of the node
39    pub description: String,
40    /// Type of the node
41    pub kind: NodeType,
42    children: BTreeMap<String, Node>,
43}
44
45impl Node {
46    /// Returns a new root node.
47    ///
48    /// # Examples
49    ///
50    /// ```
51    /// use intel_crashlog::prelude::*;
52    ///
53    /// let root = Node::root();
54    /// assert_eq!(root.kind, NodeType::Root);
55    /// ```
56    pub fn root() -> Node {
57        Node::default()
58    }
59
60    /// Returns a new section node.
61    ///
62    /// # Examples
63    ///
64    /// ```
65    /// use intel_crashlog::prelude::*;
66    ///
67    /// let node = Node::section("foo");
68    /// assert_eq!(node.kind, NodeType::Section);
69    /// assert_eq!(node.name, "foo");
70    /// ```
71    pub fn section(name: &str) -> Node {
72        Node {
73            name: name.to_lowercase(),
74            kind: NodeType::Section,
75            ..Node::default()
76        }
77    }
78
79    /// Returns a new record node.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use intel_crashlog::prelude::*;
85    ///
86    /// let node = Node::record("foo");
87    /// assert_eq!(node.kind, NodeType::Record);
88    /// assert_eq!(node.name, "foo");
89    /// ```
90    pub fn record(name: &str) -> Node {
91        Node {
92            name: name.to_lowercase(),
93            kind: NodeType::Record,
94            ..Node::default()
95        }
96    }
97
98    /// Returns a new field node.
99    ///
100    /// # Examples
101    ///
102    /// ```
103    /// use intel_crashlog::prelude::*;
104    ///
105    /// let node = Node::field("foo", 42);
106    /// assert_eq!(node.kind, NodeType::Field { value: 42 });
107    /// assert_eq!(node.name, "foo");
108    /// ```
109    pub fn field(name: &str, value: u64) -> Node {
110        Node {
111            name: name.to_lowercase(),
112            kind: NodeType::Field { value },
113            ..Node::default()
114        }
115    }
116
117    /// Returns a reference to a child of the node. If the child does not exist, [`None`] is
118    /// returned.
119    ///
120    /// # Examples
121    ///
122    /// ```
123    /// use intel_crashlog::prelude::*;
124    ///
125    /// let mut node = Node::section("foo");
126    /// node.add(Node::section("bar"));
127    /// assert_eq!(node.get("bar"), Some(&Node::section("bar")));
128    /// assert_eq!(node.get("baz"), None);
129    /// ```
130    pub fn get(&self, name: &str) -> Option<&Node> {
131        self.children.get(name)
132    }
133
134    /// Returns a mutable reference to a child of the node. If the child does not exist, [`None`]
135    /// is returned.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use intel_crashlog::prelude::*;
141    ///
142    /// let mut node = Node::section("foo");
143    /// node.add(Node::section("bar"));
144    /// if let Some(child) = node.get_mut("bar") {
145    ///     // Change the node type
146    ///     child.kind = NodeType::Field { value: 42 };
147    /// }
148    ///
149    /// assert_eq!(node.get("bar"), Some(&Node::field("bar", 42)));
150    /// ```
151    pub fn get_mut(&mut self, name: &str) -> Option<&mut Node> {
152        self.children.get_mut(name)
153    }
154
155    /// Returns a reference to the node in the tree located at the specified `path`. The `path`
156    /// consists in a `&str` representing the names of the parent nodes separated by `.` (For
157    /// example: `foo.bar.baz`).
158    ///
159    /// # Examples
160    ///
161    /// ```
162    /// use intel_crashlog::prelude::*;
163    ///
164    /// let mut foo = Node::section("foo");
165    /// foo.add(Node::section("bar"));
166    /// let mut root = Node::root();
167    /// root.add(foo);
168    ///
169    /// assert_eq!(root.get_by_path("foo.bar"), Some(&Node::section("bar")));
170    /// assert_eq!(root.get_by_path("foo.baz"), None);
171    /// ```
172    pub fn get_by_path(&self, path: &str) -> Option<&Node> {
173        let mut ptr = self;
174        for name in path.split('.') {
175            ptr = ptr.get(name)?
176        }
177        Some(ptr)
178    }
179
180    /// Returns the value associated to the node if present.
181    ///
182    /// # Examples
183    ///
184    /// ```
185    /// use intel_crashlog::prelude::*;
186    ///
187    /// let field = Node::field("foo", 42);
188    /// assert_eq!(field.value(), Some(42));
189    /// let section = Node::section("bar");
190    /// assert_eq!(section.value(), None);
191    /// ```
192    pub fn value(&self) -> Option<u64> {
193        if let NodeType::Field { value } = self.kind {
194            Some(value)
195        } else {
196            None
197        }
198    }
199
200    /// Returns the value of the field stored at the given path.
201    ///
202    /// # Examples
203    ///
204    /// ```
205    /// use intel_crashlog::prelude::*;
206    ///
207    /// let mut foo = Node::section("foo");
208    /// foo.add(Node::field("bar", 42));
209    /// let mut root = Node::root();
210    /// root.add(foo);
211    ///
212    /// assert_eq!(root.get_value_by_path("foo.bar"), Some(42));
213    /// assert_eq!(root.get_value_by_path("foo"), None);
214    /// assert_eq!(root.get_value_by_path("foo.baz"), None);
215    /// ```
216    pub fn get_value_by_path(&self, path: &str) -> Option<u64> {
217        self.get_by_path(path).and_then(|node| node.value())
218    }
219
220    fn merge_instance(&mut self, mut other: Node) {
221        let mut instance = 0;
222        let name = other.name.clone();
223        while self.children.contains_key(&other.name) {
224            other.name = format!("{name}{instance}");
225            instance += 1
226        }
227        self.add(other)
228    }
229
230    pub fn merge(&mut self, other: Node) {
231        for (_, child) in other.children {
232            if let Some(self_child) = self.children.get_mut(&child.name) {
233                if let NodeType::Record | NodeType::Field { .. } = self_child.kind {
234                    self.merge_instance(child)
235                } else {
236                    self_child.merge(child)
237                }
238            } else {
239                self.add(child)
240            }
241        }
242    }
243
244    pub fn add(&mut self, node: Node) {
245        let _ = self.children.insert(node.name.clone(), node);
246    }
247
248    pub fn create_hierarchy(&mut self, path: &str) -> &mut Node {
249        self.create_hierarchy_from_iter(path.split("."))
250    }
251
252    pub(crate) fn create_hierarchy_from_iter<S, I>(&mut self, path: I) -> &mut Node
253    where
254        I: IntoIterator<Item = S>,
255        S: AsRef<str>,
256    {
257        let mut ptr = self;
258        for name in path {
259            let name = name.as_ref();
260            if ptr.get(name).is_none() {
261                ptr.add(Node::section(name));
262            }
263            ptr = ptr
264                .get_mut(name)
265                .expect("Node should be present in the hierarchy")
266        }
267        ptr
268    }
269
270    /// Returns an iterator over the node's children. The children nodes are sorted alphabetically.
271    ///
272    /// # Examples
273    ///
274    /// ```
275    /// use intel_crashlog::prelude::*;
276    ///
277    /// let mut root = Node::root();
278    /// root.add(Node::section("foo"));
279    /// root.add(Node::section("bar"));
280    ///
281    /// let mut children = root.children();
282    /// assert_eq!(children.next(), Some(&Node::section("bar")));
283    /// assert_eq!(children.next(), Some(&Node::section("foo")));
284    /// assert_eq!(children.next(), None);
285    /// ```
286    pub fn children(&self) -> NodeChildren<'_> {
287        NodeChildren {
288            iter: self.children.values(),
289        }
290    }
291}
292
293#[cfg(feature = "serialize")]
294impl Serialize for Node {
295    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
296    where
297        S: Serializer,
298    {
299        match self.kind {
300            NodeType::Field { value } => {
301                if self.children.is_empty() {
302                    serializer.serialize_str(&format!("0x{value:x}"))
303                } else {
304                    let mut map = serializer.serialize_map(Some(self.children.len() + 1))?;
305                    map.serialize_entry("_value", &format!("0x{value:x}"))?;
306                    for (k, v) in self.children.iter() {
307                        map.serialize_entry(k, v)?;
308                    }
309                    map.end()
310                }
311            }
312            NodeType::Root => {
313                let mut map = serializer.serialize_map(Some(1))?;
314                map.serialize_entry("crashlog_data", &self.children)?;
315                map.end()
316            }
317            _ => {
318                let mut map = serializer.serialize_map(Some(self.children.len()))?;
319                for (k, v) in self.children.iter() {
320                    map.serialize_entry(k, v)?;
321                }
322                map.end()
323            }
324        }
325    }
326}
327
328/// An iterator over the children of a node.
329///
330/// This struct is created by the [`children`] method on a [`Node`].
331///
332/// [`children`]: Node::children
333pub struct NodeChildren<'a> {
334    iter: btree_map::Values<'a, String, Node>,
335}
336
337impl<'a> Iterator for NodeChildren<'a> {
338    type Item = &'a Node;
339
340    fn next(&mut self) -> Option<Self::Item> {
341        self.iter.next()
342    }
343}