Skip to content

Commit 6f43988

Browse files
committed
Add traits for common methods on nodes and properties.
1 parent 8898527 commit 6f43988

File tree

13 files changed

+436
-340
lines changed

13 files changed

+436
-340
lines changed

src/fdt/mod.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub use self::node::FdtNode;
3030
pub use self::property::{Cells, FdtProperty};
3131
use crate::error::{FdtErrorKind, FdtParseError};
3232
use crate::memreserve::MemoryReservation;
33+
use crate::standard::Node;
3334

3435
/// Version of the FDT specification supported by this library.
3536
const FDT_VERSION: u32 = 17;
@@ -487,7 +488,9 @@ impl<'a> Fdt<'a> {
487488
/// # Examples
488489
///
489490
/// ```
490-
/// # use dtoolkit::fdt::Fdt;
491+
/// use dtoolkit::fdt::Fdt;
492+
/// use dtoolkit::standard::Node;
493+
///
491494
/// # let dtb = include_bytes!("../../tests/dtb/test.dtb");
492495
/// let fdt = Fdt::new(dtb).unwrap();
493496
/// let root = fdt.root();
@@ -528,15 +531,19 @@ impl<'a> Fdt<'a> {
528531
/// # Examples
529532
///
530533
/// ```
531-
/// # use dtoolkit::fdt::Fdt;
534+
/// use dtoolkit::fdt::Fdt;
535+
/// use dtoolkit::standard::Node;
536+
///
532537
/// # let dtb = include_bytes!("../../tests/dtb/test_traversal.dtb");
533538
/// let fdt = Fdt::new(dtb).unwrap();
534539
/// let node = fdt.find_node("/a/b/c").unwrap();
535540
/// assert_eq!(node.name(), "c");
536541
/// ```
537542
///
538543
/// ```
539-
/// # use dtoolkit::fdt::Fdt;
544+
/// use dtoolkit::fdt::Fdt;
545+
/// use dtoolkit::standard::Node;
546+
///
540547
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
541548
/// let fdt = Fdt::new(dtb).unwrap();
542549
/// let node = fdt.find_node("/child2").unwrap();

src/fdt/node.rs

Lines changed: 29 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use core::fmt::{self, Display, Formatter};
1212

1313
use super::{FDT_TAGSIZE, Fdt, FdtToken};
1414
use crate::fdt::property::{FdtPropIter, FdtProperty};
15-
use crate::standard::AddressSpaceProperties;
15+
use crate::standard::{AddressSpaceProperties, Node, Property};
1616

1717
/// A node in a flattened device tree.
1818
#[derive(Debug, Clone, Copy)]
@@ -24,14 +24,8 @@ pub struct FdtNode<'a> {
2424
pub(crate) parent_address_space: AddressSpaceProperties,
2525
}
2626

27-
impl<'a> FdtNode<'a> {
28-
pub(crate) fn new(fdt: Fdt<'a>, offset: usize) -> Self {
29-
Self {
30-
fdt,
31-
offset,
32-
parent_address_space: AddressSpaceProperties::default(),
33-
}
34-
}
27+
impl<'a> Node<'a> for FdtNode<'a> {
28+
type Property = FdtProperty<'a>;
3529

3630
/// Returns the name of this node.
3731
///
@@ -44,38 +38,22 @@ impl<'a> FdtNode<'a> {
4438
/// # Examples
4539
///
4640
/// ```
47-
/// # use dtoolkit::fdt::Fdt;
41+
/// use dtoolkit::fdt::Fdt;
42+
/// use dtoolkit::standard::Node;
43+
///
4844
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
4945
/// let fdt = Fdt::new(dtb).unwrap();
5046
/// let root = fdt.root();
5147
/// let child = root.child("child1").unwrap();
5248
/// assert_eq!(child.name(), "child1");
5349
/// ```
54-
#[must_use]
55-
pub fn name(&self) -> &'a str {
50+
fn name(&self) -> &'a str {
5651
let name_offset = self.offset + FDT_TAGSIZE;
5752
self.fdt
5853
.string_at_offset(name_offset, None)
5954
.expect("Fdt should be valid")
6055
}
6156

62-
/// Returns the name of this node without the unit address, if any.
63-
///
64-
/// # Panics
65-
///
66-
/// Panics if the [`Fdt`] structure was constructed using
67-
/// [`Fdt::new_unchecked`] or [`Fdt::from_raw_unchecked`] and the FDT is not
68-
/// valid.
69-
#[must_use]
70-
pub fn name_without_address(&self) -> &'a str {
71-
let name = self.name();
72-
if let Some((name, _)) = name.split_once('@') {
73-
name
74-
} else {
75-
name
76-
}
77-
}
78-
7957
/// Returns a property by its name.
8058
///
8159
/// # Performance
@@ -85,7 +63,9 @@ impl<'a> FdtNode<'a> {
8563
/// # Examples
8664
///
8765
/// ```
88-
/// # use dtoolkit::fdt::Fdt;
66+
/// use dtoolkit::fdt::Fdt;
67+
/// use dtoolkit::standard::{Node, Property};
68+
///
8969
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
9070
/// let fdt = Fdt::new(dtb).unwrap();
9171
/// let node = fdt.find_node("/test-props").unwrap();
@@ -98,8 +78,7 @@ impl<'a> FdtNode<'a> {
9878
/// Panics if the [`Fdt`] structure was constructed using
9979
/// [`Fdt::new_unchecked`] or [`Fdt::from_raw_unchecked`] and the FDT is not
10080
/// valid.
101-
#[must_use]
102-
pub fn property(&self, name: &str) -> Option<FdtProperty<'a>> {
81+
fn property(&self, name: &str) -> Option<FdtProperty<'a>> {
10382
self.properties().find(|property| property.name() == name)
10483
}
10584

@@ -108,7 +87,9 @@ impl<'a> FdtNode<'a> {
10887
/// # Examples
10988
///
11089
/// ```
111-
/// # use dtoolkit::fdt::Fdt;
90+
/// use dtoolkit::fdt::Fdt;
91+
/// use dtoolkit::standard::{Node, Property};
92+
///
11293
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
11394
/// let fdt = Fdt::new(dtb).unwrap();
11495
/// let node = fdt.find_node("/test-props").unwrap();
@@ -117,78 +98,21 @@ impl<'a> FdtNode<'a> {
11798
/// assert_eq!(props.next().unwrap().name(), "u64-prop");
11899
/// assert_eq!(props.next().unwrap().name(), "str-prop");
119100
/// ```
120-
pub fn properties(&self) -> impl Iterator<Item = FdtProperty<'a>> + use<'a> {
101+
fn properties(&self) -> impl Iterator<Item = FdtProperty<'a>> + use<'a> {
121102
FdtPropIter::Start {
122103
fdt: self.fdt,
123104
offset: self.offset,
124105
}
125106
}
126107

127-
/// Returns a child node by its name.
128-
///
129-
/// If the given name contains a _unit-address_ (the part after the `@`
130-
/// sign) then both the _node-name_ and _unit-address_ must match. If it
131-
/// doesn't have a _unit-address_, then nodes with any _unit-address_ or
132-
/// none will be allowed.
133-
///
134-
/// For example, searching for `memory` as a child of `/` would match either
135-
/// `/memory` or `/memory@4000`, while `memory@4000` would match only the
136-
/// latter.
137-
///
138-
/// # Performance
139-
///
140-
/// This method's performance is linear in the number of children of this
141-
/// node because it iterates through the children. If you need to call this
142-
/// often, consider converting to a
143-
/// [`DeviceTreeNode`](crate::model::DeviceTreeNode) first. Child lookup
144-
/// on a [`DeviceTreeNode`](crate::model::DeviceTreeNode) is a
145-
/// constant-time operation.
146-
///
147-
/// # Panics
148-
///
149-
/// Panics if the [`Fdt`] structure was constructed using
150-
/// [`Fdt::new_unchecked`] or [`Fdt::from_raw_unchecked`] and the FDT is not
151-
/// valid.
152-
///
153-
/// # Examples
154-
///
155-
/// ```
156-
/// # use dtoolkit::fdt::Fdt;
157-
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
158-
/// let fdt = Fdt::new(dtb).unwrap();
159-
/// let root = fdt.root();
160-
/// let child = root.child("child1").unwrap();
161-
/// assert_eq!(child.name(), "child1");
162-
/// ```
163-
///
164-
/// ```
165-
/// # use dtoolkit::fdt::Fdt;
166-
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
167-
/// let fdt = Fdt::new(dtb).unwrap();
168-
/// let root = fdt.root();
169-
/// let child = root.child("child2").unwrap();
170-
/// assert_eq!(child.name(), "child2@42");
171-
/// let child = root.child("child2@42").unwrap();
172-
/// assert_eq!(child.name(), "child2@42");
173-
/// ```
174-
#[must_use]
175-
pub fn child(&self, name: &str) -> Option<FdtNode<'a>> {
176-
let include_address = name.contains('@');
177-
self.children().find(|&child| {
178-
if include_address {
179-
child.name() == name
180-
} else {
181-
child.name_without_address() == name
182-
}
183-
})
184-
}
185-
186108
/// Returns an iterator over the children of this node.
187109
///
188110
/// # Examples
189111
///
190112
/// ```
191-
/// # use dtoolkit::fdt::Fdt;
113+
/// use dtoolkit::fdt::Fdt;
114+
/// use dtoolkit::standard::Node;
115+
///
192116
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
193117
/// let fdt = Fdt::new(dtb).unwrap();
194118
/// let root = fdt.root();
@@ -197,9 +121,19 @@ impl<'a> FdtNode<'a> {
197121
/// assert_eq!(children.next().unwrap().name(), "child2@42");
198122
/// assert!(children.next().is_none());
199123
/// ```
200-
pub fn children(&self) -> impl Iterator<Item = FdtNode<'a>> + use<'a> {
124+
fn children(&self) -> impl Iterator<Item = FdtNode<'a>> + use<'a> {
201125
FdtChildIter::Start { node: *self }
202126
}
127+
}
128+
129+
impl<'a> FdtNode<'a> {
130+
pub(crate) fn new(fdt: Fdt<'a>, offset: usize) -> Self {
131+
Self {
132+
fdt,
133+
offset,
134+
parent_address_space: AddressSpaceProperties::default(),
135+
}
136+
}
203137

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

src/fdt/property.rs

Lines changed: 9 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use zerocopy::{FromBytes, big_endian};
1616

1717
use super::{FDT_TAGSIZE, Fdt, FdtToken};
1818
use crate::error::{PropertyError, StandardError};
19+
use crate::standard::Property;
1920

2021
/// A property of a device tree node.
2122
#[derive(Debug, PartialEq)]
@@ -25,108 +26,35 @@ pub struct FdtProperty<'a> {
2526
value_offset: usize,
2627
}
2728

28-
impl<'a> FdtProperty<'a> {
29-
/// Returns the name of this property.
30-
#[must_use]
31-
pub fn name(&self) -> &'a str {
29+
impl<'a> Property<'a> for FdtProperty<'a> {
30+
fn name(&self) -> &'a str {
3231
self.name
3332
}
3433

35-
/// Returns the value of this property.
36-
#[must_use]
37-
pub fn value(&self) -> &'a [u8] {
34+
fn value(&self) -> &'a [u8] {
3835
self.value
3936
}
4037

41-
/// Returns the value of this property as a `u32`.
42-
///
43-
/// # Errors
44-
///
45-
/// Returns an [`PropertyError::InvalidLength`] if the property's value is
46-
/// not 4 bytes long.
47-
///
48-
/// # Examples
49-
///
50-
/// ```
51-
/// # use dtoolkit::fdt::Fdt;
52-
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
53-
/// let fdt = Fdt::new(dtb).unwrap();
54-
/// let node = fdt.find_node("/test-props").unwrap();
55-
/// let prop = node.property("u32-prop").unwrap();
56-
/// assert_eq!(prop.as_u32().unwrap(), 0x12345678);
57-
/// ```
58-
pub fn as_u32(&self) -> Result<u32, PropertyError> {
38+
fn as_u32(&self) -> Result<u32, PropertyError> {
5939
big_endian::U32::ref_from_bytes(self.value)
6040
.map(|val| val.get())
6141
.map_err(|_e| PropertyError::InvalidLength)
6242
}
6343

64-
/// Returns the value of this property as a `u64`.
65-
///
66-
/// # Errors
67-
///
68-
/// Returns an [`PropertyError::InvalidLength`] if the property's value is
69-
/// not 8 bytes long.
70-
///
71-
/// # Examples
72-
///
73-
/// ```
74-
/// # use dtoolkit::fdt::Fdt;
75-
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
76-
/// let fdt = Fdt::new(dtb).unwrap();
77-
/// let node = fdt.find_node("/test-props").unwrap();
78-
/// let prop = node.property("u64-prop").unwrap();
79-
/// assert_eq!(prop.as_u64().unwrap(), 0x1122334455667788);
80-
/// ```
81-
pub fn as_u64(&self) -> Result<u64, PropertyError> {
44+
fn as_u64(&self) -> Result<u64, PropertyError> {
8245
big_endian::U64::ref_from_bytes(self.value)
8346
.map(|val| val.get())
8447
.map_err(|_e| PropertyError::InvalidLength)
8548
}
8649

87-
/// Returns the value of this property as a string.
88-
///
89-
/// # Errors
90-
///
91-
/// Returns an [`PropertyError::InvalidString`] if the property's value is
92-
/// not a null-terminated string or contains invalid UTF-8.
93-
///
94-
/// # Examples
95-
///
96-
/// ```
97-
/// # use dtoolkit::fdt::Fdt;
98-
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
99-
/// let fdt = Fdt::new(dtb).unwrap();
100-
/// let node = fdt.find_node("/test-props").unwrap();
101-
/// let prop = node.property("str-prop").unwrap();
102-
/// assert_eq!(prop.as_str().unwrap(), "hello world");
103-
/// ```
104-
pub fn as_str(&self) -> Result<&'a str, PropertyError> {
50+
fn as_str(&self) -> Result<&'a str, PropertyError> {
10551
let cstr =
10652
CStr::from_bytes_with_nul(self.value).map_err(|_| PropertyError::InvalidString)?;
10753
cstr.to_str().map_err(|_| PropertyError::InvalidString)
10854
}
55+
}
10956

110-
/// Returns an iterator over the strings in this property.
111-
///
112-
/// # Examples
113-
///
114-
/// ```
115-
/// # use dtoolkit::fdt::Fdt;
116-
/// # let dtb = include_bytes!("../../tests/dtb/test_props.dtb");
117-
/// let fdt = Fdt::new(dtb).unwrap();
118-
/// let node = fdt.find_node("/test-props").unwrap();
119-
/// let prop = node.property("str-list-prop").unwrap();
120-
/// let mut str_list = prop.as_str_list();
121-
/// assert_eq!(str_list.next(), Some("first"));
122-
/// assert_eq!(str_list.next(), Some("second"));
123-
/// assert_eq!(str_list.next(), Some("third"));
124-
/// assert_eq!(str_list.next(), None);
125-
/// ```
126-
pub fn as_str_list(&self) -> impl Iterator<Item = &'a str> + use<'a> {
127-
FdtStringListIterator { value: self.value }
128-
}
129-
57+
impl<'a> FdtProperty<'a> {
13058
pub(crate) fn as_prop_encoded_array<const N: usize>(
13159
&self,
13260
fields_cells: [usize; N],
@@ -269,24 +197,6 @@ impl<'a> FdtPropIter<'a> {
269197
}
270198
}
271199

272-
struct FdtStringListIterator<'a> {
273-
value: &'a [u8],
274-
}
275-
276-
impl<'a> Iterator for FdtStringListIterator<'a> {
277-
type Item = &'a str;
278-
279-
fn next(&mut self) -> Option<Self::Item> {
280-
if self.value.is_empty() {
281-
return None;
282-
}
283-
let cstr = CStr::from_bytes_until_nul(self.value).ok()?;
284-
let s = cstr.to_str().ok()?;
285-
self.value = &self.value[s.len() + 1..];
286-
Some(s)
287-
}
288-
}
289-
290200
/// An integer value split into several big-endian u32 parts.
291201
///
292202
/// This is generally used in prop-encoded-array properties.

0 commit comments

Comments
 (0)