Skip to main content

fdt_edit/node/
mod.rs

1use core::fmt::{Debug, Display};
2
3use alloc::{collections::btree_map::BTreeMap, string::String, vec::Vec};
4use fdt_raw::{Phandle, Status};
5
6use crate::{NodeId, Property, RangesEntry};
7
8pub(crate) mod view;
9
10/// A mutable device tree node.
11///
12/// Represents a node in the device tree with a name, properties, and child node IDs.
13/// Nodes are stored in a flat `BTreeMap<NodeId, Node>` within the `Fdt` struct,
14/// and children are referenced by their `NodeId`.
15#[derive(Clone)]
16pub struct Node {
17    /// Node name (without path)
18    pub name: String,
19    /// Property list (maintains original order)
20    properties: Vec<Property>,
21    /// Property name to index mapping (for fast lookup)
22    prop_cache: BTreeMap<String, usize>,
23    /// Child node IDs
24    children: Vec<NodeId>,
25    /// Child name to children-vec index mapping (for fast lookup).
26    /// Note: the name key here needs to be resolved through the arena.
27    name_cache: BTreeMap<String, usize>,
28}
29
30impl Node {
31    /// Creates a new node with the given name.
32    pub fn new(name: &str) -> Self {
33        Self {
34            name: name.into(),
35            properties: Vec::new(),
36            prop_cache: BTreeMap::new(),
37            children: Vec::new(),
38            name_cache: BTreeMap::new(),
39        }
40    }
41
42    /// Returns the node's name.
43    pub fn name(&self) -> &str {
44        &self.name
45    }
46
47    /// Returns an iterator over the node's properties.
48    pub fn properties(&self) -> &[Property] {
49        &self.properties
50    }
51
52    /// Returns the child node IDs.
53    pub fn children(&self) -> &[NodeId] {
54        &self.children
55    }
56
57    /// Adds a child node ID to this node.
58    ///
59    /// Updates the name cache for fast lookups.
60    pub fn add_child(&mut self, name: &str, id: NodeId) {
61        let index = self.children.len();
62        self.name_cache.insert(name.into(), index);
63        self.children.push(id);
64    }
65
66    /// Adds a property to this node.
67    ///
68    /// Updates the property cache for fast lookups.
69    pub fn add_property(&mut self, prop: Property) {
70        let name = prop.name.clone();
71        let index = self.properties.len();
72        self.prop_cache.insert(name, index);
73        self.properties.push(prop);
74    }
75
76    /// Gets a child node ID by name.
77    ///
78    /// Uses the cache for fast lookup.
79    pub fn get_child(&self, name: &str) -> Option<NodeId> {
80        self.name_cache
81            .get(name)
82            .and_then(|&idx| self.children.get(idx).copied())
83    }
84
85    /// Removes a child node by name, returning its `NodeId`.
86    ///
87    /// Rebuilds the name cache after removal.
88    pub fn remove_child(&mut self, name: &str) -> Option<NodeId> {
89        let &idx = self.name_cache.get(name)?;
90        if idx >= self.children.len() {
91            return None;
92        }
93        let removed = self.children.remove(idx);
94        self.rebuild_name_cache_from(name);
95        Some(removed)
96    }
97
98    /// Rebuild name cache. Requires node names, provided externally.
99    /// This is called with a mapping of node_id -> name.
100    pub(crate) fn rebuild_name_cache_from(&mut self, _removed_name: &str) {
101        // We can't rebuild fully here since we don't have access to the arena.
102        // Instead, we remove the stale entry and shift indices.
103        self.name_cache.remove(_removed_name);
104        // Rebuild all indices from scratch — caller should use rebuild_name_cache_with_names
105        // For now, just clear and note that the Fdt layer handles this correctly.
106        self.name_cache.clear();
107    }
108
109    /// Rebuild name cache from a list of (name, index) pairs.
110    pub(crate) fn rebuild_name_cache_with_names(&mut self, names: &[(String, usize)]) {
111        self.name_cache.clear();
112        for (name, idx) in names {
113            self.name_cache.insert(name.clone(), *idx);
114        }
115    }
116
117    /// Sets a property, adding it if it doesn't exist or updating if it does.
118    pub fn set_property(&mut self, prop: Property) {
119        let name = prop.name.clone();
120        if let Some(&idx) = self.prop_cache.get(&name) {
121            // Update existing property
122            self.properties[idx] = prop;
123        } else {
124            // Add new property
125            let idx = self.properties.len();
126            self.prop_cache.insert(name, idx);
127            self.properties.push(prop);
128        }
129    }
130
131    /// Gets a property by name.
132    pub fn get_property(&self, name: &str) -> Option<&Property> {
133        self.prop_cache.get(name).map(|&idx| &self.properties[idx])
134    }
135
136    /// Gets a mutable reference to a property by name.
137    pub fn get_property_mut(&mut self, name: &str) -> Option<&mut Property> {
138        self.prop_cache
139            .get(name)
140            .map(|&idx| &mut self.properties[idx])
141    }
142
143    fn rebuild_prop_cache(&mut self) {
144        self.prop_cache.clear();
145        for (idx, prop) in self.properties.iter().enumerate() {
146            self.prop_cache.insert(prop.name.clone(), idx);
147        }
148    }
149
150    /// Removes a property by name.
151    ///
152    /// Updates indices after removal to keep the cache consistent.
153    pub fn remove_property(&mut self, name: &str) -> Option<Property> {
154        if let Some(&idx) = self.prop_cache.get(name) {
155            let prop = self.properties.remove(idx);
156            self.rebuild_prop_cache();
157            Some(prop)
158        } else {
159            None
160        }
161    }
162
163    /// Returns the `#address-cells` property value.
164    pub fn address_cells(&self) -> Option<u32> {
165        self.get_property("#address-cells")
166            .and_then(|prop| prop.get_u32())
167    }
168
169    /// Returns the `#size-cells` property value.
170    pub fn size_cells(&self) -> Option<u32> {
171        self.get_property("#size-cells")
172            .and_then(|prop| prop.get_u32())
173    }
174
175    /// Returns the `phandle` property value.
176    pub fn phandle(&self) -> Option<Phandle> {
177        self.get_property("phandle")
178            .and_then(|prop| prop.get_u32())
179            .map(Phandle::from)
180    }
181
182    /// Returns the local `interrupt-parent` property value.
183    pub fn interrupt_parent(&self) -> Option<Phandle> {
184        self.get_property("interrupt-parent")
185            .and_then(|prop| prop.get_u32())
186            .map(Phandle::from)
187    }
188
189    /// Returns the `status` property value.
190    pub fn status(&self) -> Option<Status> {
191        let prop = self.get_property("status")?;
192        let s = prop.as_str()?;
193        match s {
194            "okay" => Some(Status::Okay),
195            "disabled" => Some(Status::Disabled),
196            _ => None,
197        }
198    }
199
200    /// Parses the `ranges` property for address translation.
201    ///
202    /// Returns a vector of range entries mapping child bus addresses to parent bus addresses.
203    pub fn ranges(&self, parent_address_cells: u32) -> Option<Vec<RangesEntry>> {
204        let prop = self.get_property("ranges")?;
205        let mut entries = Vec::new();
206        let mut reader = prop.as_reader();
207
208        let child_address_cells = self.address_cells().unwrap_or(2) as usize;
209        let parent_addr_cells = parent_address_cells as usize;
210        let size_cells = self.size_cells().unwrap_or(1) as usize;
211
212        while let (Some(child_addr), Some(parent_addr), Some(size)) = (
213            reader.read_cells(child_address_cells),
214            reader.read_cells(parent_addr_cells),
215            reader.read_cells(size_cells),
216        ) {
217            entries.push(RangesEntry {
218                child_bus_address: child_addr,
219                parent_bus_address: parent_addr,
220                length: size,
221            });
222        }
223
224        Some(entries)
225    }
226
227    /// Returns the `compatible` property as a string iterator.
228    pub fn compatible(&self) -> Option<impl Iterator<Item = &str>> {
229        let prop = self.get_property("compatible")?;
230        Some(prop.as_str_iter())
231    }
232
233    /// Returns an iterator over all compatible strings.
234    pub fn compatibles(&self) -> impl Iterator<Item = &str> {
235        self.get_property("compatible")
236            .map(|prop| prop.as_str_iter())
237            .into_iter()
238            .flatten()
239    }
240
241    /// Returns the `device_type` property value.
242    pub fn device_type(&self) -> Option<&str> {
243        let prop = self.get_property("device_type")?;
244        prop.as_str()
245    }
246
247    /// Returns true if this node is a memory node.
248    pub fn is_memory(&self) -> bool {
249        if let Some(dt) = self.device_type()
250            && dt == "memory"
251        {
252            return true;
253        }
254        self.name.starts_with("memory")
255    }
256
257    /// Returns true if this node is an interrupt controller.
258    pub fn is_interrupt_controller(&self) -> bool {
259        self.name.starts_with("interrupt-controller")
260            || self.get_property("interrupt-controller").is_some()
261    }
262
263    /// Returns the `#interrupt-cells` property value.
264    pub fn interrupt_cells(&self) -> Option<u32> {
265        self.get_property("#interrupt-cells")
266            .and_then(|prop| prop.get_u32())
267    }
268
269    /// Returns true if this node is a clock provider.
270    pub fn is_clock(&self) -> bool {
271        self.get_property("#clock-cells").is_some()
272    }
273
274    /// Returns true if this node is a PCI bridge.
275    pub fn is_pci(&self) -> bool {
276        self.device_type() == Some("pci")
277    }
278}
279
280impl From<&fdt_raw::Node<'_>> for Node {
281    fn from(raw: &fdt_raw::Node<'_>) -> Self {
282        let mut new_node = Node::new(raw.name());
283        // Copy properties only; children are managed by Fdt
284        for raw_prop in raw.properties() {
285            let prop = Property::from(&raw_prop);
286            new_node.set_property(prop);
287        }
288        new_node
289    }
290}
291
292impl Display for Node {
293    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
294        write!(f, "Node(name: {})", self.name)
295    }
296}
297
298impl Debug for Node {
299    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
300        write!(
301            f,
302            "Node {{ name: {}, properties: {}, children: {} }}",
303            self.name,
304            self.properties.len(),
305            self.children.len()
306        )
307    }
308}