libfdt: Add FdtNode::descendants()
Bug: 277993056
Test: atest liblibfdt.integration_test
Change-Id: I1efd3cd37e3a5036f532a3c15af9227d76672036
diff --git a/libs/libfdt/src/iterators.rs b/libs/libfdt/src/iterators.rs
index 000f723..a524655 100644
--- a/libs/libfdt/src/iterators.rs
+++ b/libs/libfdt/src/iterators.rs
@@ -323,6 +323,29 @@
}
}
+/// Iterator over descendants
+#[derive(Debug)]
+pub struct DescendantsIterator<'a> {
+ node: Option<(FdtNode<'a>, usize)>,
+}
+
+impl<'a> DescendantsIterator<'a> {
+ pub(crate) fn new(node: &'a FdtNode) -> Self {
+ Self { node: Some((*node, 0)) }
+ }
+}
+
+impl<'a> Iterator for DescendantsIterator<'a> {
+ type Item = (FdtNode<'a>, usize);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let (node, depth) = self.node?;
+ self.node = node.next_node(depth).ok().flatten().filter(|(_, depth)| *depth > 0);
+
+ self.node
+ }
+}
+
/// Iterator over properties
#[derive(Debug)]
pub struct PropertyIterator<'a> {
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index b513649..aae75f7 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -20,8 +20,8 @@
mod iterators;
pub use iterators::{
- AddressRange, CellIterator, CompatibleIterator, MemRegIterator, PropertyIterator,
- RangesIterator, Reg, RegIterator, SubnodeIterator,
+ AddressRange, CellIterator, CompatibleIterator, DescendantsIterator, MemRegIterator,
+ PropertyIterator, RangesIterator, Reg, RegIterator, SubnodeIterator,
};
use core::cmp::max;
@@ -486,6 +486,23 @@
Ok(fdt_err_or_option(ret)?.map(|offset| FdtNode { fdt: self.fdt, offset }))
}
+ /// Returns an iterator of descendants
+ pub fn descendants(&'a self) -> DescendantsIterator<'a> {
+ DescendantsIterator::new(self)
+ }
+
+ fn next_node(&self, depth: usize) -> Result<Option<(Self, usize)>> {
+ let mut next_depth: c_int = depth.try_into().unwrap();
+ // SAFETY: Accesses (read-only) are constrained to the DT totalsize.
+ let ret = unsafe {
+ libfdt_bindgen::fdt_next_node(self.fdt.as_ptr(), self.offset, &mut next_depth)
+ };
+ let Ok(next_depth) = usize::try_from(next_depth) else {
+ return Ok(None);
+ };
+ Ok(fdt_err_or_option(ret)?.map(|offset| (FdtNode { fdt: self.fdt, offset }, next_depth)))
+ }
+
/// Returns an iterator of properties
pub fn properties(&'a self) -> Result<PropertyIterator<'a>> {
PropertyIterator::new(self)
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 63cbdee..d5d6ece 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -308,3 +308,23 @@
// Just check whether borrow checker doesn't complain this.
memory.setprop_inplace(cstr!("device_type"), b"MEMORY\0").unwrap();
}
+
+#[test]
+fn node_descendants() {
+ let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
+ let fdt = Fdt::from_mut_slice(&mut data).unwrap();
+
+ let node_z = fdt.node(cstr!("/node_z")).unwrap().unwrap();
+ let descendants: Vec<_> =
+ node_z.descendants().map(|(node, depth)| (node.name().unwrap(), depth)).collect();
+
+ assert_eq!(
+ descendants,
+ vec![
+ (cstr!("node_za"), 1),
+ (cstr!("node_zb"), 1),
+ (cstr!("node_zz"), 1),
+ (cstr!("node_zzz"), 2)
+ ]
+ );
+}