libfdt: Add FdtNode::subnodes()
Bug: 277993056
Test: atest liblibfdt.integration_test
Change-Id: I8557b04c0fa4f4de28f6fdf79712dd5ee8f2b963
diff --git a/libs/libfdt/src/iterators.rs b/libs/libfdt/src/iterators.rs
index 13d262e..7bffd8c 100644
--- a/libs/libfdt/src/iterators.rs
+++ b/libs/libfdt/src/iterators.rs
@@ -295,3 +295,29 @@
}
}
}
+
+/// Iterator over subnodes
+#[derive(Debug)]
+pub struct SubnodeIterator<'a> {
+ subnode: Option<FdtNode<'a>>,
+}
+
+impl<'a> SubnodeIterator<'a> {
+ pub(crate) fn new(node: &'a FdtNode) -> Result<Self, FdtError> {
+ let subnode = node.first_subnode()?;
+
+ Ok(Self { subnode })
+ }
+}
+
+impl<'a> Iterator for SubnodeIterator<'a> {
+ type Item = FdtNode<'a>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let res = self.subnode;
+
+ self.subnode = self.subnode.and_then(|node| node.next_subnode().ok()?);
+
+ res
+ }
+}
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index b573697..758df2a 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -21,7 +21,7 @@
pub use iterators::{
AddressRange, CellIterator, CompatibleIterator, MemRegIterator, RangesIterator, Reg,
- RegIterator,
+ RegIterator, SubnodeIterator,
};
use core::cmp::max;
@@ -384,6 +384,25 @@
.try_into()
.map_err(|_| FdtError::Internal)
}
+
+ /// Returns an iterator of subnodes
+ pub fn subnodes(&'a self) -> Result<SubnodeIterator<'a>> {
+ SubnodeIterator::new(self)
+ }
+
+ fn first_subnode(&self) -> Result<Option<Self>> {
+ // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+ let ret = unsafe { libfdt_bindgen::fdt_first_subnode(self.fdt.as_ptr(), self.offset) };
+
+ Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
+ }
+
+ fn next_subnode(&self) -> Result<Option<Self>> {
+ // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+ let ret = unsafe { libfdt_bindgen::fdt_next_subnode(self.fdt.as_ptr(), self.offset) };
+
+ Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
+ }
}
/// Mutable FDT node.
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 866a2bb..513ffd8 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -87,3 +87,15 @@
let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
assert_eq!(nested_node.name().unwrap().to_str().unwrap(), "PowerPC,970@0");
}
+
+#[test]
+fn node_subnodes() {
+ let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
+ let fdt = Fdt::from_slice(&data).unwrap();
+ let root = fdt.root().unwrap();
+ let expected: Vec<&str> = vec!["cpus", "randomnode", "chosen"];
+
+ for (node, name) in root.subnodes().unwrap().zip(expected) {
+ assert_eq!(node.name().unwrap().to_str().unwrap(), name);
+ }
+}