Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/fdt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ use zerocopy::byteorder::big_endian;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};

pub use self::node::FdtNode;
pub use self::property::{Cells, FdtProperty};
pub use self::property::FdtProperty;
use crate::Node;
use crate::error::{FdtErrorKind, FdtParseError};
use crate::memreserve::MemoryReservation;

Expand Down Expand Up @@ -487,7 +488,9 @@ impl<'a> Fdt<'a> {
/// # Examples
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// use dtoolkit::Node;
/// use dtoolkit::fdt::Fdt;
///
/// # let dtb = include_bytes!("../../tests/dtb/test.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let root = fdt.root();
Expand Down Expand Up @@ -528,15 +531,19 @@ impl<'a> Fdt<'a> {
/// # Examples
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// use dtoolkit::Node;
/// use dtoolkit::fdt::Fdt;
///
/// # let dtb = include_bytes!("../../tests/dtb/test_traversal.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let node = fdt.find_node("/a/b/c").unwrap();
/// assert_eq!(node.name(), "c");
/// ```
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// use dtoolkit::Node;
/// use dtoolkit::fdt::Fdt;
///
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let node = fdt.find_node("/child2").unwrap();
Expand Down
143 changes: 25 additions & 118 deletions src/fdt/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use core::fmt::{self, Display, Formatter};

use super::{FDT_TAGSIZE, Fdt, FdtToken};
use crate::Node;
use crate::fdt::property::{FdtPropIter, FdtProperty};
use crate::standard::AddressSpaceProperties;

Expand All @@ -24,14 +25,8 @@ pub struct FdtNode<'a> {
pub(crate) parent_address_space: AddressSpaceProperties,
}

impl<'a> FdtNode<'a> {
pub(crate) fn new(fdt: Fdt<'a>, offset: usize) -> Self {
Self {
fdt,
offset,
parent_address_space: AddressSpaceProperties::default(),
}
}
impl<'a> Node<'a> for FdtNode<'a> {
type Property = FdtProperty<'a>;

/// Returns the name of this node.
///
Expand All @@ -44,71 +39,30 @@ impl<'a> FdtNode<'a> {
/// # Examples
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// use dtoolkit::Node;
/// use dtoolkit::fdt::Fdt;
///
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let root = fdt.root();
/// let child = root.child("child1").unwrap();
/// assert_eq!(child.name(), "child1");
/// ```
#[must_use]
pub fn name(&self) -> &'a str {
fn name(&self) -> &'a str {
let name_offset = self.offset + FDT_TAGSIZE;
self.fdt
.string_at_offset(name_offset, None)
.expect("Fdt should be valid")
}

/// Returns the name of this node without the unit address, if any.
///
/// # Panics
///
/// Panics if the [`Fdt`] structure was constructed using
/// [`Fdt::new_unchecked`] or [`Fdt::from_raw_unchecked`] and the FDT is not
/// valid.
#[must_use]
pub fn name_without_address(&self) -> &'a str {
let name = self.name();
if let Some((name, _)) = name.split_once('@') {
name
} else {
name
}
}

/// Returns a property by its name.
///
/// # Performance
///
/// This method iterates through all properties of the node.
///
/// # Examples
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let node = fdt.find_node("/test-props").unwrap();
/// let prop = node.property("u32-prop").unwrap();
/// assert_eq!(prop.name(), "u32-prop");
/// ```
///
/// # Panics
///
/// Panics if the [`Fdt`] structure was constructed using
/// [`Fdt::new_unchecked`] or [`Fdt::from_raw_unchecked`] and the FDT is not
/// valid.
#[must_use]
pub fn property(&self, name: &str) -> Option<FdtProperty<'a>> {
self.properties().find(|property| property.name() == name)
}

/// Returns an iterator over the properties of this node.
///
/// # Examples
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// use dtoolkit::fdt::Fdt;
/// use dtoolkit::{Node, Property};
///
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let node = fdt.find_node("/test-props").unwrap();
Expand All @@ -117,78 +71,21 @@ impl<'a> FdtNode<'a> {
/// assert_eq!(props.next().unwrap().name(), "u64-prop");
/// assert_eq!(props.next().unwrap().name(), "str-prop");
/// ```
pub fn properties(&self) -> impl Iterator<Item = FdtProperty<'a>> + use<'a> {
fn properties(&self) -> impl Iterator<Item = FdtProperty<'a>> + use<'a> {
FdtPropIter::Start {
fdt: self.fdt,
offset: self.offset,
}
}

/// Returns a child node by its name.
///
/// If the given name contains a _unit-address_ (the part after the `@`
/// sign) then both the _node-name_ and _unit-address_ must match. If it
/// doesn't have a _unit-address_, then nodes with any _unit-address_ or
/// none will be allowed.
///
/// For example, searching for `memory` as a child of `/` would match either
/// `/memory` or `/memory@4000`, while `memory@4000` would match only the
/// latter.
///
/// # Performance
///
/// This method's performance is linear in the number of children of this
/// node because it iterates through the children. If you need to call this
/// often, consider converting to a
/// [`DeviceTreeNode`](crate::model::DeviceTreeNode) first. Child lookup
/// on a [`DeviceTreeNode`](crate::model::DeviceTreeNode) is a
/// constant-time operation.
///
/// # Panics
///
/// Panics if the [`Fdt`] structure was constructed using
/// [`Fdt::new_unchecked`] or [`Fdt::from_raw_unchecked`] and the FDT is not
/// valid.
///
/// # Examples
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let root = fdt.root();
/// let child = root.child("child1").unwrap();
/// assert_eq!(child.name(), "child1");
/// ```
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let root = fdt.root();
/// let child = root.child("child2").unwrap();
/// assert_eq!(child.name(), "child2@42");
/// let child = root.child("child2@42").unwrap();
/// assert_eq!(child.name(), "child2@42");
/// ```
#[must_use]
pub fn child(&self, name: &str) -> Option<FdtNode<'a>> {
let include_address = name.contains('@');
self.children().find(|&child| {
if include_address {
child.name() == name
} else {
child.name_without_address() == name
}
})
}

/// Returns an iterator over the children of this node.
///
/// # Examples
///
/// ```
/// # use dtoolkit::fdt::Fdt;
/// use dtoolkit::Node;
/// use dtoolkit::fdt::Fdt;
///
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
/// let fdt = Fdt::new(dtb).unwrap();
/// let root = fdt.root();
Expand All @@ -197,9 +94,19 @@ impl<'a> FdtNode<'a> {
/// assert_eq!(children.next().unwrap().name(), "child2@42");
/// assert!(children.next().is_none());
/// ```
pub fn children(&self) -> impl Iterator<Item = FdtNode<'a>> + use<'a> {
fn children(&self) -> impl Iterator<Item = FdtNode<'a>> + use<'a> {
FdtChildIter::Start { node: *self }
}
}

impl<'a> FdtNode<'a> {
pub(crate) fn new(fdt: Fdt<'a>, offset: usize) -> Self {
Self {
fdt,
offset,
parent_address_space: AddressSpaceProperties::default(),
}
}

pub(crate) fn fmt_recursive(&self, f: &mut Formatter, indent: usize) -> fmt::Result {
let name = self.name();
Expand Down
Loading
Loading