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}