Skip to content
Open
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
11 changes: 6 additions & 5 deletions src/fdt/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! A read-only API for inspecting a device tree property.

use core::fmt::{self, Display, Formatter};
use core::mem::size_of;

use zerocopy::FromBytes;

Expand All @@ -33,8 +34,6 @@ pub(crate) struct ParsedProperty<'a> {
}

impl<'a> Property for FdtProperty<'a> {
type Str = &'a str;
type StrList = crate::values::FdtStringListIterator<'a>;
type PropEncodedArray<const N: usize> = crate::values::PropEncodedArrayIterator<'a, N>;
type CellsItem = crate::Cells<'a>;

Expand Down Expand Up @@ -64,7 +63,9 @@ impl FdtProperty<'_> {
.all(|&ch| ch.is_ascii_graphic() || ch == b' ' || ch == 0);
let has_empty = self.value.windows(2).any(|window| window == [0, 0]);
if is_printable && self.value.ends_with(&[0]) && !has_empty {
let mut strings = (*self).as_str_list();
let mut strings = (*self)
.value_as::<crate::values::FdtStringListIterator>()
.map_err(|_| fmt::Error)?;
if let Some(first) = strings.next() {
write!(f, " = \"{first}\"")?;
for s in strings {
Expand All @@ -75,9 +76,9 @@ impl FdtProperty<'_> {
}
}

if self.value.len().is_multiple_of(4) {
if self.value.len().is_multiple_of(size_of::<u32>()) {
write!(f, " = <")?;
let (chunks, remainder) = self.value.as_chunks::<4>();
let (chunks, remainder) = self.value.as_chunks::<{ size_of::<u32>() }>();
debug_assert!(remainder.is_empty());
for (i, chunk) in chunks.iter().enumerate() {
if i > 0 {
Expand Down
24 changes: 12 additions & 12 deletions src/fdt_mut/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,6 @@ impl<B: FdtBuffer> Display for FdtPropertyMut<'_, B> {
}

impl<'a, B: FdtBuffer> Property for &'a FdtPropertyMut<'_, B> {
type Str = &'a str;
type StrList = crate::values::FdtStringListIterator<'a>;
type PropEncodedArray<const N: usize> = crate::values::PropEncodedArrayIterator<'a, N>;
type CellsItem = crate::Cells<'a>;

Expand All @@ -187,16 +185,18 @@ impl<'a, B: FdtBuffer> Property for &'a FdtPropertyMut<'_, B> {
.expect("Fdt should be valid")
}

fn as_cells(&self) -> Result<crate::Cells<'a>, crate::error::PropertyError> {
self.as_read_only().as_cells()
}

fn as_str(&self) -> Result<&'a str, crate::error::PropertyError> {
self.as_read_only().as_str()
}

fn as_str_list(&self) -> Self::StrList {
self.as_read_only().as_str_list()
fn value_as<'v, T: crate::FromPropertyValue<'v>>(
&self,
) -> Result<T, crate::error::PropertyError>
where
Self: 'v,
{
let fdt = self.data.as_read_only();
let value = fdt
.data
.get(self.value_offset..self.value_offset + self.len)
.expect("Fdt should be valid");
T::from_property_value(value)
}

fn as_prop_encoded_array<const N: usize>(
Expand Down
135 changes: 13 additions & 122 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
//! // Find the child node and read its property.
//! let child_node = fdt.find_node("/child").unwrap();
//! let prop = child_node.property("my-property").unwrap();
//! let val: &str = prop.as_str().unwrap().as_ref();
//! let val = prop.value_as::<&str>().unwrap();
//! assert_eq!(val, "hello");
//!
//! // Display the DTS
Expand Down Expand Up @@ -139,32 +139,21 @@ use core::ops::{BitOr, Shl};
use zerocopy::big_endian;

use crate::error::{PropertyError, StandardError};
pub use crate::values::ToPropertyValue;
pub use crate::values::{
FdtStringListIterator, FromPropertyValue, PropEncodedArrayIterator, ToPropertyValue,
};

macro_rules! impl_property_methods {
(get_value = |$self:ident| $get_value:expr) => {
fn as_cells(&$self) -> Result<$crate::Cells<'a>, $crate::error::PropertyError> {
Ok($crate::Cells(
<[zerocopy::big_endian::U32]>::ref_from_bytes($get_value)
.map_err(|_| $crate::error::PropertyError::InvalidLength)?,
))
}

fn as_str(&$self) -> Result<&'a str, $crate::error::PropertyError> {
let cstr =
core::ffi::CStr::from_bytes_with_nul($get_value).map_err(|_| $crate::error::PropertyError::InvalidString)?;
cstr.to_str().map_err(|_| $crate::error::PropertyError::InvalidString)
}

fn as_str_list(&$self) -> $crate::values::FdtStringListIterator<'a> {
$crate::values::FdtStringListIterator { value: $get_value }
fn value_as<'v, T: crate::FromPropertyValue<'v>>(&$self) -> Result<T, crate::error::PropertyError> where Self: 'v {
T::from_property_value($get_value)
}

fn as_prop_encoded_array<const N: usize>(
&$self,
fields_cells: [usize; N],
) -> Result<$crate::values::PropEncodedArrayIterator<'a, N>, $crate::error::PropertyError> {
$crate::values::PropEncodedArrayIterator::new($get_value, fields_cells)
) -> Result<crate::values::PropEncodedArrayIterator<'a, N>, crate::error::PropertyError> {
crate::values::PropEncodedArrayIterator::new($get_value, fields_cells)
}
};
}
Expand Down Expand Up @@ -287,12 +276,6 @@ pub trait Node: Sized {

/// A property of a device tree node.
pub trait Property: Sized {
/// The type used for strings in the property.
type Str: AsRef<str>;

/// The type used for the strings iterator.
type StrList: Iterator<Item = Self::Str>;

/// The type used for the prop-encoded-array iterator.
type PropEncodedArray<const N: usize>: Iterator<Item = [Self::CellsItem; N]>;

Expand All @@ -307,106 +290,14 @@ pub trait Property: Sized {
#[must_use]
fn value(&self) -> &[u8];

/// Returns the value of this property as a `u32`.
///
/// # Errors
///
/// Returns an [`PropertyError::InvalidLength`] if the property's value is
/// not 4 bytes long.
///
/// # Examples
///
/// ```
/// 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();
/// let prop = node.property("u32-prop").unwrap();
/// assert_eq!(prop.as_u32().unwrap(), 0x12345678);
/// ```
fn as_u32(&self) -> Result<u32, PropertyError> {
self.value()
.try_into()
.map(u32::from_be_bytes)
.map_err(|_| PropertyError::InvalidLength)
}

/// Returns the value of this property as a `u64`.
/// Returns the value of this property as a given type.
///
/// # Errors
///
/// Returns an [`PropertyError::InvalidLength`] if the property's value is
/// not 8 bytes long.
///
/// # Examples
///
/// ```
/// 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();
/// let prop = node.property("u64-prop").unwrap();
/// assert_eq!(prop.as_u64().unwrap(), 0x1122334455667788);
/// ```
fn as_u64(&self) -> Result<u64, PropertyError> {
self.value()
.try_into()
.map(u64::from_be_bytes)
.map_err(|_| PropertyError::InvalidLength)
}

/// Returns the value of this property as a slide of 32-bit cells.
///
/// # Errors
///
/// Returns an error if the value of the property isn't a multiple of 4
/// bytes long.
fn as_cells(&self) -> Result<Self::CellsItem, PropertyError>;

/// Returns the value of this property as a string.
///
/// # Errors
///
/// Returns an [`PropertyError::InvalidString`] if the property's value is
/// not a null-terminated string or contains invalid UTF-8.
///
/// # Examples
///
/// ```
/// 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();
/// let prop = node.property("str-prop").unwrap();
/// assert_eq!(prop.as_str().unwrap(), "hello world");
/// ```
fn as_str(&self) -> Result<Self::Str, PropertyError>;

/// Returns an iterator over the strings in this property.
///
/// # Examples
///
/// ```
/// 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();
/// let prop = node.property("str-list-prop").unwrap();
/// let mut str_list = prop.as_str_list();
/// assert_eq!(str_list.next(), Some("first"));
/// assert_eq!(str_list.next(), Some("second"));
/// assert_eq!(str_list.next(), Some("third"));
/// assert_eq!(str_list.next(), None);
/// ```
fn as_str_list(&self) -> Self::StrList;
/// Returns an error if the value cannot be parsed or has invalid length.
fn value_as<'a, T: FromPropertyValue<'a>>(&self) -> Result<T, PropertyError>
where
Self: 'a;

/// Returns an iterator over the elements of the property interpreted as a
/// `prop-encoded-array`.
Expand Down
10 changes: 5 additions & 5 deletions src/model/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,13 @@ impl<'a> OverlayApplier<'a> {
if let Some(sym_node) = self.base.root.child(NODE_SYMBOLS)
&& let Some(sym_prop) = sym_node.property(path)
{
let abs_path = sym_prop.as_str()?;
let abs_path = sym_prop.value_as::<&str>()?;
return Ok(abs_path.to_string());
}
if let Some(aliases_node) = self.base.root.child("aliases")
&& let Some(alias_prop) = aliases_node.property(path)
{
let abs_path = alias_prop.as_str()?;
let abs_path = alias_prop.value_as::<&str>()?;
return Ok(abs_path.to_string());
}
Err(OverlayError::TargetNotFound(path.to_string()))
Expand Down Expand Up @@ -319,7 +319,7 @@ fn relocate_local_phandles(
fn offset_node_phandles(node: &mut DeviceTreeNode, offset: u32) -> Result<(), OverlayError> {
for prop_name in PHANDLE_PROPS {
if let Some(prop) = node.property_mut(prop_name)
&& let Ok(val) = (&*prop).as_u32()
&& let Ok(val) = (&*prop).value_as::<u32>()
{
let new_val = val
.checked_add(offset)
Expand Down Expand Up @@ -423,7 +423,7 @@ fn resolve_external_fixups(
.child(NODE_SYMBOLS)
.and_then(|sym| sym.property(symbol_name))
.ok_or_else(|| OverlayError::UnresolvedSymbol(symbol_name.to_string()))?
.as_str()
.value_as::<&str>()
.map_err(|_| OverlayError::UnresolvedSymbol(symbol_name.to_string()))?
.to_string();

Expand All @@ -447,7 +447,7 @@ fn resolve_external_fixups(
new_p
};

for loc_str in fixup_prop.as_str_list() {
for loc_str in fixup_prop.value_as::<crate::values::FdtStringListIterator>()? {
let loc = FixupLocation::parse(loc_str)?;
let overlay_node = overlay
.find_node_mut(loc.node_path)
Expand Down
6 changes: 1 addition & 5 deletions src/model/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::str;

use zerocopy::FromBytes;

use crate::error::ModelError;
use crate::values::{FdtStringListIterator, PropEncodedArrayIterator};
use crate::values::PropEncodedArrayIterator;
use crate::{Cells, Property, ToPropertyValue};

/// A mutable, in-memory representation of a device tree property.
Expand All @@ -24,8 +22,6 @@ pub struct DeviceTreeProperty {
}

impl<'a> Property for &'a DeviceTreeProperty {
type Str = &'a str;
type StrList = FdtStringListIterator<'a>;
type PropEncodedArray<const N: usize> = PropEncodedArrayIterator<'a, N>;
type CellsItem = Cells<'a>;

Expand Down
10 changes: 4 additions & 6 deletions src/overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,13 @@ impl<N: Node> Fragment<N> {
/// FragmentTarget::Phandle(p) => println!("Targeting phandle: {}", p),
/// }
/// ```
pub fn target(
&self,
) -> Result<FragmentTarget<<N::Property<'_> as Property>::Str>, OverlayError> {
pub fn target(&self) -> Result<FragmentTarget<&str>, OverlayError> {
let target = self.node.property("target");
let target_path = self.node.property("target-path");

match (target, target_path) {
(Some(prop), None) => Ok(FragmentTarget::Phandle(prop.as_u32()?)),
(None, Some(prop)) => Ok(FragmentTarget::Path(prop.as_str()?)),
(Some(prop), None) => Ok(FragmentTarget::Phandle(prop.value_as::<u32>()?)),
(None, Some(prop)) => Ok(FragmentTarget::Path(prop.value_as::<&str>()?)),
_ => Err(OverlayError::InvalidFragmentTarget),
}
}
Expand Down Expand Up @@ -227,7 +225,7 @@ impl<'a> FixupLocation<'a> {
pub fn get_phandle<N: Node>(node: &N) -> Option<u32> {
for prop in PHANDLE_PROPS {
if let Some(p) = node.property(prop)
&& let Ok(val) = p.as_u32()
&& let Ok(val) = p.value_as::<u32>()
{
return Some(val);
}
Expand Down
Loading
Loading