Skip to content

Commit 9670df7

Browse files
committed
WIP: Try adding trait for both node types.
1 parent 5522b25 commit 9670df7

File tree

6 files changed

+129
-62
lines changed

6 files changed

+129
-62
lines changed

src/fdt/mod.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,9 @@ impl<'a> Fdt<'a> {
360360
/// # Examples
361361
///
362362
/// ```
363-
/// # use dtoolkit::fdt::Fdt;
363+
/// use dtoolkit::fdt::Fdt;
364+
/// use dtoolkit::standard::DtNode;
365+
///
364366
/// # let dtb = include_bytes!("../../tests/dtb/test.dtb");
365367
/// let fdt = Fdt::new(dtb).unwrap();
366368
/// let root = fdt.root().unwrap();
@@ -408,15 +410,19 @@ impl<'a> Fdt<'a> {
408410
/// # Examples
409411
///
410412
/// ```
411-
/// # use dtoolkit::fdt::Fdt;
413+
/// use dtoolkit::fdt::Fdt;
414+
/// use dtoolkit::standard::DtNode;
415+
///
412416
/// # let dtb = include_bytes!("../../tests/dtb/test_traversal.dtb");
413417
/// let fdt = Fdt::new(dtb).unwrap();
414418
/// let node = fdt.find_node("/a/b/c").unwrap().unwrap();
415419
/// assert_eq!(node.name().unwrap(), "c");
416420
/// ```
417421
///
418422
/// ```
419-
/// # use dtoolkit::fdt::Fdt;
423+
/// use dtoolkit::fdt::Fdt;
424+
/// use dtoolkit::standard::DtNode;
425+
///
420426
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
421427
/// let fdt = Fdt::new(dtb).unwrap();
422428
/// let node = fdt.find_node("/child2").unwrap().unwrap();

src/fdt/node.rs

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use core::fmt;
1313
use super::{FDT_TAGSIZE, Fdt, FdtToken};
1414
use crate::error::FdtParseError;
1515
use crate::fdt::property::{FdtPropIter, FdtProperty};
16-
use crate::standard::{DEFAULT_ADDRESS_CELLS, DEFAULT_SIZE_CELLS};
16+
use crate::standard::{DEFAULT_ADDRESS_CELLS, DEFAULT_SIZE_CELLS, DtNode};
1717

1818
/// A node in a flattened device tree.
1919
#[derive(Debug, Clone, Copy)]
@@ -26,15 +26,16 @@ pub struct FdtNode<'a> {
2626
pub(crate) address_cells: u32,
2727
}
2828

29-
impl<'a> FdtNode<'a> {
30-
pub(crate) fn new(fdt: Fdt<'a>, offset: usize) -> Self {
31-
Self {
32-
fdt,
33-
offset,
34-
address_cells: DEFAULT_ADDRESS_CELLS,
35-
size_cells: DEFAULT_SIZE_CELLS,
36-
}
37-
}
29+
impl<'a> DtNode for FdtNode<'a> {
30+
type Error = FdtParseError;
31+
type StrRef<'x>
32+
= &'a str
33+
where
34+
Self: 'x;
35+
type Property<'x>
36+
= FdtProperty<'x>
37+
where
38+
Self: 'x;
3839

3940
/// Returns the name of this node.
4041
///
@@ -49,36 +50,20 @@ impl<'a> FdtNode<'a> {
4950
/// # Examples
5051
///
5152
/// ```
52-
/// # use dtoolkit::fdt::Fdt;
53+
/// use dtoolkit::fdt::Fdt;
54+
/// use dtoolkit::standard::DtNode;
55+
///
5356
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
5457
/// let fdt = Fdt::new(dtb).unwrap();
5558
/// let root = fdt.root().unwrap();
5659
/// let child = root.child("child1").unwrap().unwrap();
5760
/// assert_eq!(child.name().unwrap(), "child1");
5861
/// ```
59-
pub fn name(&self) -> Result<&'a str, FdtParseError> {
62+
fn name(&self) -> Result<&'a str, FdtParseError> {
6063
let name_offset = self.offset + FDT_TAGSIZE;
6164
self.fdt.string_at_offset(name_offset, None)
6265
}
6366

64-
/// Returns the name of this node without the unit address, if any.
65-
///
66-
/// # Errors
67-
///
68-
/// Returns an
69-
/// [`FdtErrorKind::InvalidOffset`](crate::error::FdtErrorKind::InvalidOffset)
70-
/// if the name offset is invalid or an
71-
/// [`FdtErrorKind::InvalidString`](crate::error::FdtErrorKind::InvalidString) if the string at the offset is not null-terminated
72-
/// or contains invalid UTF-8.
73-
pub fn name_without_address(&self) -> Result<&'a str, FdtParseError> {
74-
let name = self.name()?;
75-
if let Some((name, _)) = name.split_once('@') {
76-
Ok(name)
77-
} else {
78-
Ok(name)
79-
}
80-
}
81-
8267
/// Returns a property by its name.
8368
///
8469
/// # Performance
@@ -99,7 +84,7 @@ impl<'a> FdtNode<'a> {
9984
/// # Errors
10085
///
10186
/// Returns an error if a property's name or value cannot be read.
102-
pub fn property(&self, name: &str) -> Result<Option<FdtProperty<'a>>, FdtParseError> {
87+
fn property(&self, name: &str) -> Result<Option<FdtProperty<'a>>, FdtParseError> {
10388
for property in self.properties() {
10489
let property = property?;
10590
if property.name() == name {
@@ -108,6 +93,17 @@ impl<'a> FdtNode<'a> {
10893
}
10994
Ok(None)
11095
}
96+
}
97+
98+
impl<'a> FdtNode<'a> {
99+
pub(crate) fn new(fdt: Fdt<'a>, offset: usize) -> Self {
100+
Self {
101+
fdt,
102+
offset,
103+
address_cells: DEFAULT_ADDRESS_CELLS,
104+
size_cells: DEFAULT_SIZE_CELLS,
105+
}
106+
}
111107

112108
/// Returns an iterator over the properties of this node.
113109
///
@@ -159,7 +155,9 @@ impl<'a> FdtNode<'a> {
159155
/// # Examples
160156
///
161157
/// ```
162-
/// # use dtoolkit::fdt::Fdt;
158+
/// use dtoolkit::fdt::Fdt;
159+
/// use dtoolkit::standard::DtNode;
160+
///
163161
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
164162
/// let fdt = Fdt::new(dtb).unwrap();
165163
/// let root = fdt.root().unwrap();
@@ -168,7 +166,9 @@ impl<'a> FdtNode<'a> {
168166
/// ```
169167
///
170168
/// ```
171-
/// # use dtoolkit::fdt::Fdt;
169+
/// use dtoolkit::fdt::Fdt;
170+
/// use dtoolkit::standard::DtNode;
171+
///
172172
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
173173
/// let fdt = Fdt::new(dtb).unwrap();
174174
/// let root = fdt.root().unwrap();
@@ -197,7 +197,9 @@ impl<'a> FdtNode<'a> {
197197
/// # Examples
198198
///
199199
/// ```
200-
/// # use dtoolkit::fdt::Fdt;
200+
/// use dtoolkit::fdt::Fdt;
201+
/// use dtoolkit::standard::DtNode;
202+
///
201203
/// # let dtb = include_bytes!("../../tests/dtb/test_children.dtb");
202204
/// let fdt = Fdt::new(dtb).unwrap();
203205
/// let root = fdt.root().unwrap();

src/model/node.rs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,15 @@
99
use alloc::borrow::ToOwned;
1010
use alloc::string::{String, ToString};
1111
use alloc::vec::Vec;
12+
use core::convert::Infallible;
1213

1314
use indexmap::IndexMap;
1415
use twox_hash::xxhash64;
1516

1617
use super::property::DeviceTreeProperty;
1718
use crate::error::FdtParseError;
1819
use crate::fdt::FdtNode;
20+
use crate::standard::DtNode;
1921

2022
/// A mutable, in-memory representation of a device tree node.
2123
///
@@ -38,6 +40,35 @@ impl Default for DeviceTreeNode {
3840
}
3941
}
4042

43+
impl DtNode for DeviceTreeNode {
44+
type Error = Infallible;
45+
type StrRef<'x> = &'x str;
46+
type Property<'x> = &'x DeviceTreeProperty;
47+
48+
fn name(&self) -> Result<&str, Self::Error> {
49+
Ok(&self.name)
50+
}
51+
52+
/// Finds a property by its name and returns a reference to it.
53+
///
54+
/// # Performance
55+
///
56+
/// This is a constant-time operation.
57+
///
58+
/// # Examples
59+
///
60+
/// ```
61+
/// # use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
62+
/// let mut node = DeviceTreeNode::new("my-node");
63+
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]));
64+
/// let prop = node.property("my-prop").unwrap();
65+
/// assert_eq!(prop.value(), &[1, 2, 3, 4]);
66+
/// ```
67+
fn property(&self, name: &str) -> Result<Option<&DeviceTreeProperty>, Self::Error> {
68+
Ok(self.properties.get(name))
69+
}
70+
}
71+
4172
impl DeviceTreeNode {
4273
/// Creates a new [`DeviceTreeNode`] with the given name.
4374
///
@@ -86,26 +117,6 @@ impl DeviceTreeNode {
86117
self.properties.values_mut()
87118
}
88119

89-
/// Finds a property by its name and returns a reference to it.
90-
///
91-
/// # Performance
92-
///
93-
/// This is a constant-time operation.
94-
///
95-
/// # Examples
96-
///
97-
/// ```
98-
/// # use dtoolkit::model::{DeviceTreeNode, DeviceTreeProperty};
99-
/// let mut node = DeviceTreeNode::new("my-node");
100-
/// node.add_property(DeviceTreeProperty::new("my-prop", vec![1, 2, 3, 4]));
101-
/// let prop = node.property("my-prop").unwrap();
102-
/// assert_eq!(prop.value(), &[1, 2, 3, 4]);
103-
/// ```
104-
#[must_use]
105-
pub fn property(&self, name: &str) -> Option<&DeviceTreeProperty> {
106-
self.properties.get(name)
107-
}
108-
109120
/// Finds a property by its name and returns a mutable reference to it.
110121
///
111122
/// # Performance

src/standard.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,63 @@ mod memory;
1212
mod reg;
1313
mod status;
1414

15+
use core::ops::Deref;
16+
1517
pub use self::memory::{InitialMappedArea, Memory};
1618
pub use self::reg::Reg;
1719
pub use self::status::Status;
1820
use crate::error::{FdtError, FdtParseError};
19-
use crate::fdt::FdtNode;
21+
use crate::fdt::{FdtNode, FdtProperty};
2022

2123
pub(crate) const DEFAULT_ADDRESS_CELLS: u32 = 2;
2224
pub(crate) const DEFAULT_SIZE_CELLS: u32 = 1;
2325

26+
/// A device tree node.
27+
pub trait DtNode {
28+
/// An error which can be returned while reading the node.
29+
type Error;
30+
/// A reference to a string slice, whose lifetime may be tied to the
31+
/// underlying device tree.
32+
type StrRef<'x>: Deref<Target = str>
33+
where
34+
Self: 'x;
35+
type Property<'x>
36+
where
37+
Self: 'x;
38+
39+
/// Returns the name of this node.
40+
///
41+
/// # Errors
42+
///
43+
/// Returns an error if there was a problem parsing the device tree.
44+
fn name(&self) -> Result<Self::StrRef<'_>, Self::Error>;
45+
46+
/// Returns the property with the given name, if any.
47+
///
48+
/// # Errors
49+
///
50+
/// Returns an error if a property's name or value cannot be read.
51+
fn property(&self, name: &str) -> Result<Option<Self::Property<'_>>, Self::Error>;
52+
53+
/// Returns the name of this node without the unit address, if any.
54+
///
55+
/// # Errors
56+
///
57+
/// Returns an
58+
/// [`FdtErrorKind::InvalidOffset`](crate::error::FdtErrorKind::InvalidOffset)
59+
/// if the name offset is invalid or an
60+
/// [`FdtErrorKind::InvalidString`](crate::error::FdtErrorKind::InvalidString) if the string at the offset is not null-terminated
61+
/// or contains invalid UTF-8.
62+
fn name_without_address(&self) -> Result<Self::StrRef<'_>, Self::Error> {
63+
let name = self.name()?;
64+
if let Some((name, _)) = name.split_once('@') {
65+
Ok(name)
66+
} else {
67+
Ok(name)
68+
}
69+
}
70+
}
71+
2472
impl<'a> FdtNode<'a> {
2573
/// Returns the value of the standard `compatible` property.
2674
///
@@ -30,9 +78,8 @@ impl<'a> FdtNode<'a> {
3078
pub fn compatible(
3179
&self,
3280
) -> Result<Option<impl Iterator<Item = &'a str> + use<'a>>, FdtParseError> {
33-
Ok(self
34-
.property("compatible")?
35-
.map(|property| property.as_str_list()))
81+
let property: Option<FdtProperty<'a>> = self.property("compatible")?;
82+
Ok(property.map(|property| property.as_str_list()))
3683
}
3784

3885
/// Returns whether this node has a `compatible` properties containing the

src/standard/memory.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use zerocopy::big_endian;
1212

1313
use crate::error::FdtError;
1414
use crate::fdt::{Fdt, FdtNode};
15+
use crate::standard::DtNode;
1516

1617
impl Fdt<'_> {
1718
/// Returns the /memory node.

tests/fdt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
use dtoolkit::fdt::Fdt;
1010
#[cfg(feature = "write")]
1111
use dtoolkit::model::DeviceTree;
12-
use dtoolkit::standard::{InitialMappedArea, Reg, Status};
12+
use dtoolkit::standard::{DtNode, InitialMappedArea, Reg, Status};
1313

1414
#[test]
1515
fn read_child_nodes() {

0 commit comments

Comments
 (0)