Skip to content

Commit

Permalink
wip: more docs + remove some methods in favor of direct field access
Browse files Browse the repository at this point in the history
  • Loading branch information
repnop committed Jan 13, 2025
1 parent 904823f commit a36045c
Show file tree
Hide file tree
Showing 12 changed files with 91 additions and 57 deletions.
49 changes: 35 additions & 14 deletions src/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,20 @@ pub trait AsNode<'a, P: ParserWithMode<'a>> {
fn as_node(&self) -> Node<'a, P>;
}

/// A node name that can searched with.
#[derive(Debug, Clone, Copy)]
pub enum SearchableNodeName<'a> {
/// Node name without the unit address
Base(&'a str),
/// Node name with the unit address
WithUnitAddress(NodeName<'a>),
}

/// Convert from a type that can potentially represent a node name that is able
/// to be searched for during lookup operations.
///
/// Currently, two type impls are defined:
/// Currently, two type impls are defined on types other than
/// [`SearchableNodeName`]:
/// 1. [`NodeName`]: corresponds directly to a
/// [`SearchableNodeName::WithUnitAddress`].
/// 2. [`&str`]: attempts to parse the `str` as `name@unit-address`,
Expand All @@ -56,6 +60,13 @@ pub trait IntoSearchableNodeName<'a>: Sized + crate::sealed::Sealed {
fn into_searchable_node_name(self) -> SearchableNodeName<'a>;
}

impl crate::sealed::Sealed for SearchableNodeName<'_> {}
impl<'a> IntoSearchableNodeName<'a> for SearchableNodeName<'a> {
fn into_searchable_node_name(self) -> SearchableNodeName<'a> {
self
}
}

impl crate::sealed::Sealed for NodeName<'_> {}
impl<'a> IntoSearchableNodeName<'a> for NodeName<'a> {
fn into_searchable_node_name(self) -> SearchableNodeName<'a> {
Expand All @@ -75,9 +86,12 @@ impl<'a> IntoSearchableNodeName<'a> for &'a str {
}
}

/// A node name, split into its component parts.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NodeName<'a> {
/// Node name.
pub name: &'a str,
/// Optional unit address specified after the `@`.
pub unit_address: Option<&'a str>,
}

Expand Down Expand Up @@ -108,7 +122,7 @@ pub struct Node<'a, P: ParserWithMode<'a>> {
impl<'a, P: ParserWithMode<'a>> Node<'a, P> {
/// Change the type of this node's [`PanicMode`] to [`NoPanic`].
#[inline(always)]
pub(crate) fn fallible(self) -> FallibleNode<'a, P> {
pub fn fallible(self) -> FallibleNode<'a, P> {
self.alt()
}

Expand Down Expand Up @@ -377,6 +391,8 @@ impl<Granularity> RawNode<Granularity> {
}
}

/// Allows for searching and iterating over all of the properties of a given
/// [`Node`].
pub struct NodeProperties<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
data: &'a [<P as Parser<'a>>::Granularity],
strings: StringsBlock<'a>,
Expand All @@ -394,6 +410,7 @@ impl<'a, P: ParserWithMode<'a>> NodeProperties<'a, P> {
}
}

/// Create an iterator over the properties in the [`Node`].
#[inline(always)]
pub fn iter(self) -> NodePropertiesIter<'a, P> {
NodePropertiesIter { properties: self.alt(), _mode: core::marker::PhantomData }
Expand Down Expand Up @@ -426,6 +443,7 @@ impl<'a, P: ParserWithMode<'a>> NodeProperties<'a, P> {
}))
}

/// Attempt to find a property with the provided name.
#[inline]
#[track_caller]
pub fn find(&self, name: &str) -> P::Output<Option<NodeProperty<'a>>> {
Expand Down Expand Up @@ -465,6 +483,7 @@ impl<'a, P: ParserWithMode<'a>> IntoIterator for NodeProperties<'a, P> {
}
}

/// See [`NodeProperties::iter`].
#[derive(Clone)]
pub struct NodePropertiesIter<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
properties: NodeProperties<'a, (P::Parser, NoPanic)>,
Expand All @@ -486,10 +505,13 @@ impl<'a, P: ParserWithMode<'a>> Iterator for NodePropertiesIter<'a, P> {
}
}

/// Generic node property.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct NodeProperty<'a> {
name: &'a str,
value: &'a [u8],
/// Property name.
pub name: &'a str,
/// Raw property value.
pub value: &'a [u8],
}

impl<'a> NodeProperty<'a> {
Expand All @@ -498,22 +520,15 @@ impl<'a> NodeProperty<'a> {
Self { name, value }
}

#[inline(always)]
pub fn name(&self) -> &'a str {
self.name
}

#[inline(always)]
pub fn value(&self) -> &'a [u8] {
self.value
}

/// Attempt to convert this property's value to the specified
/// [`PropertyValue`] type.
#[inline(always)]
pub fn as_value<V: PropertyValue<'a>>(&self) -> Result<V, InvalidPropertyValue> {
V::parse(self.value)
}
}

/// Allows for searching and iterating over the children of a given [`Node`].
pub struct NodeChildren<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
data: &'a [<P as Parser<'a>>::Granularity],
parent: &'a RawNode<<P as Parser<'a>>::Granularity>,
Expand All @@ -523,6 +538,7 @@ pub struct NodeChildren<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)>
}

impl<'a, P: ParserWithMode<'a>> NodeChildren<'a, P> {
/// Create an iterator over the [`Node`]'s children.
#[inline(always)]
pub fn iter(&self) -> NodeChildrenIter<'a, P> {
NodeChildrenIter {
Expand Down Expand Up @@ -559,6 +575,10 @@ impl<'a, P: ParserWithMode<'a>> NodeChildren<'a, P> {
})
}

/// Attempt to find the first child matching the provided name, see
/// [`IntoSearchableNodeName`] for more details. If the name lacks a unit
/// address, unit addresses on the children will be ignored when checking if
/// the name matches.
#[inline]
#[track_caller]
pub fn find<'n, N>(&self, name: N) -> P::Output<Option<Node<'a, P>>>
Expand Down Expand Up @@ -609,6 +629,7 @@ impl<'a, P: ParserWithMode<'a>> IntoIterator for NodeChildren<'a, P> {
}
}

/// See [`NodeChildren::iter`].
#[derive(Clone)]
pub struct NodeChildrenIter<'a, P: ParserWithMode<'a> = (AlignedParser<'a>, Panic)> {
children: NodeChildren<'a, (P::Parser, NoPanic)>,
Expand Down
2 changes: 1 addition & 1 deletion src/nodes/aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ where
#[track_caller]
fn next(&mut self) -> Option<Self::Item> {
Some(P::to_output(match self.properties.next() {
Some(Ok(prop)) => crate::tryblock!({ Ok((prop.name(), prop.as_value::<&'a str>()?)) }),
Some(Ok(prop)) => crate::tryblock!({ Ok((prop.name, prop.as_value::<&'a str>()?)) }),
Some(Err(e)) => Err(e),
None => return None,
}))
Expand Down
8 changes: 4 additions & 4 deletions src/nodes/chosen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ impl<'a, P: ParserWithMode<'a>> Chosen<'a, P> {
pub fn bootargs(self) -> P::Output<Option<&'a str>> {
P::to_output(crate::tryblock!({
for prop in self.node.properties()?.into_iter().flatten() {
if prop.name() == "bootargs" {
if prop.name == "bootargs" {
return Ok(Some(
core::str::from_utf8(&prop.value()[..prop.value().len() - 1])
core::str::from_utf8(&prop.value[..prop.value.len() - 1])
.map_err(|_| FdtError::ParseError(ParseError::InvalidCStrValue))?,
));
}
Expand Down Expand Up @@ -91,7 +91,7 @@ impl<'a, P: ParserWithMode<'a>> Chosen<'a, P> {
.into_iter()
.find_map(|n| match n {
Err(e) => Some(Err(e)),
Ok(property) => match property.name() == "stdout-path" {
Ok(property) => match property.name == "stdout-path" {
false => None,
true => Some(property.as_value::<&'a str>().map_err(Into::into).map(|s| {
let (path, params) =
Expand Down Expand Up @@ -151,7 +151,7 @@ impl<'a, P: ParserWithMode<'a>> Chosen<'a, P> {
.into_iter()
.find_map(|n| match n {
Err(e) => Some(Err(e)),
Ok(property) => match property.name() == "stdin-path" {
Ok(property) => match property.name == "stdin-path" {
false => None,
true => Some(property.as_value::<&str>().map_err(Into::into).map(|s| {
let (path, params) =
Expand Down
16 changes: 8 additions & 8 deletions src/nodes/cpus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<'a, P: ParserWithMode<'a>> Cpus<'a, P> {
pub fn common_timebase_frequency(&self) -> P::Output<Option<u64>> {
P::to_output(crate::tryblock!({
match self.node.properties()?.find("timebase-frequency")? {
Some(prop) => match prop.value().len() {
Some(prop) => match prop.value.len() {
4 => Ok(Some(u64::from(prop.as_value::<u32>()?))),
8 => Ok(Some(prop.as_value::<u64>()?)),
_ => Err(FdtError::InvalidPropertyValue),
Expand All @@ -55,7 +55,7 @@ impl<'a, P: ParserWithMode<'a>> Cpus<'a, P> {
pub fn common_clock_frequency(&self) -> P::Output<Option<u64>> {
P::to_output(crate::tryblock!({
match self.node.properties()?.find("clock-frequency")? {
Some(prop) => match prop.value().len() {
Some(prop) => match prop.value.len() {
4 => Ok(Some(u64::from(prop.as_value::<u32>()?))),
8 => Ok(Some(prop.as_value::<u64>()?)),
_ => Err(FdtError::InvalidPropertyValue),
Expand Down Expand Up @@ -181,15 +181,15 @@ impl<'a, P: ParserWithMode<'a>> Cpu<'a, P> {
return Err(FdtError::MissingRequiredProperty("reg"));
};

if reg.value().is_empty() {
if reg.value.is_empty() {
return Err(FdtError::InvalidPropertyValue);
}

let Some(address_cells) = self.node.parent().unwrap().property::<AddressCells>()? else {
return Err(FdtError::MissingRequiredProperty("#address-cells"));
};

Ok(CpuIds { reg: reg.value(), address_cells: address_cells.0, _collector: core::marker::PhantomData })
Ok(CpuIds { reg: reg.value, address_cells: address_cells.0, _collector: core::marker::PhantomData })
}))
}

Expand All @@ -208,7 +208,7 @@ impl<'a, P: ParserWithMode<'a>> Cpu<'a, P> {
pub fn clock_frequency(self) -> P::Output<u64> {
P::to_output(crate::tryblock!({
match self.node.properties()?.find("clock-frequency")? {
Some(prop) => match prop.value().len() {
Some(prop) => match prop.value.len() {
4 => Ok(u64::from(prop.as_value::<u32>()?)),
8 => Ok(prop.as_value::<u64>()?),
_ => Err(FdtError::InvalidPropertyValue),
Expand All @@ -222,7 +222,7 @@ impl<'a, P: ParserWithMode<'a>> Cpu<'a, P> {
.find("clock-frequency")?
.ok_or(FdtError::MissingRequiredProperty("clock-frequency"))?;

match prop.value().len() {
match prop.value.len() {
4 => Ok(u64::from(prop.as_value::<u32>()?)),
8 => Ok(prop.as_value::<u64>()?),
_ => Err(FdtError::InvalidPropertyValue),
Expand All @@ -248,7 +248,7 @@ impl<'a, P: ParserWithMode<'a>> Cpu<'a, P> {
pub fn timebase_frequency(self) -> P::Output<u64> {
P::to_output(crate::tryblock!({
match self.node.properties()?.find("timebase-frequency")? {
Some(prop) => match prop.value().len() {
Some(prop) => match prop.value.len() {
4 => Ok(u64::from(prop.as_value::<u32>()?)),
8 => Ok(prop.as_value::<u64>()?),
_ => Err(FdtError::InvalidPropertyValue),
Expand All @@ -262,7 +262,7 @@ impl<'a, P: ParserWithMode<'a>> Cpu<'a, P> {
.find("timebase-frequency")?
.ok_or(FdtError::MissingRequiredProperty("timebase-frequency"))?;

match prop.value().len() {
match prop.value.len() {
4 => Ok(u64::from(prop.as_value::<u32>()?)),
8 => Ok(prop.as_value::<u64>()?),
_ => Err(FdtError::InvalidPropertyValue),
Expand Down
10 changes: 5 additions & 5 deletions src/nodes/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ impl<'a, P: ParserWithMode<'a>> Memory<'a, P> {
P::to_output(crate::tryblock!({
match self.node.properties()?.find("initial-mapped-area")? {
Some(prop) => {
let value = prop.value();
let value = prop.value;
if value.len() != (/* effective address */8 + /* physical address */ 8 + /* size */ 4) {
return Err(FdtError::InvalidPropertyValue);
}
Expand Down Expand Up @@ -207,13 +207,13 @@ impl<'a, P: ParserWithMode<'a>> ReservedMemoryChild<'a, P> {
// from the `NodeChildrenIter` struct
let size_cells = self.node.parent().unwrap().property::<SizeCells>()?.unwrap_or(SizeCells(1));

if size.value().len() % size_cells.0 != 0 {
if size.value.len() % size_cells.0 != 0 {
return Err(FdtError::InvalidPropertyValue);
}

let mut builder = <C as CellCollector>::Builder::default();

for component in size.value().chunks_exact(4) {
for component in size.value.chunks_exact(4) {
if builder.push(u32::from_be_bytes(component.try_into().unwrap())).is_err() {
return Ok(Some(Err(CollectCellsError)));
}
Expand All @@ -240,13 +240,13 @@ impl<'a, P: ParserWithMode<'a>> ReservedMemoryChild<'a, P> {
// from the `NodeChildrenIter` struct
let size_cells = self.node.parent().unwrap().property::<SizeCells>()?.unwrap_or(SizeCells(1));

if alignment.value().len() % size_cells.0 != 0 {
if alignment.value.len() % size_cells.0 != 0 {
return Err(FdtError::InvalidPropertyValue);
}

let mut builder = <C as CellCollector>::Builder::default();

for component in alignment.value().chunks_exact(4) {
for component in alignment.value.chunks_exact(4) {
if builder.push(u32::from_be_bytes(component.try_into().unwrap())).is_err() {
return Ok(Some(Err(CollectCellsError)));
}
Expand Down
12 changes: 6 additions & 6 deletions src/pretty_print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ fn print_properties<'a, P: Parser<'a>>(
any_props = true;
let prop = prop?;

match prop.name() {
match prop.name {
"reg" => {
write!(f, "{:width$}reg = <", ' ', width = depth * 4 + 4)?;
for (i, reg) in node.reg()?.unwrap().iter::<u64, Option<u64>>().enumerate() {
Expand All @@ -155,12 +155,12 @@ fn print_properties<'a, P: Parser<'a>>(
writeln!(f, "{:width$}{} = <{:#04x}>;", ' ', name, prop.as_value::<u32>()?, width = depth * 4 + 4)?;
}
_ => match prop.as_value::<&str>() {
Ok("") => writeln!(f, "{:width$}{};", ' ', prop.name(), width = depth * 4 + 4)?,
Ok(value) => writeln!(f, "{:width$}{} = {:?};", ' ', prop.name(), value, width = depth * 4 + 4)?,
_ => match prop.value().len() {
0 => writeln!(f, "{:width$}{};", ' ', prop.name(), width = depth * 4 + 4)?,
Ok("") => writeln!(f, "{:width$}{};", ' ', prop.name, width = depth * 4 + 4)?,
Ok(value) => writeln!(f, "{:width$}{} = {:?};", ' ', prop.name, value, width = depth * 4 + 4)?,
_ => match prop.value.len() {
0 => writeln!(f, "{:width$}{};", ' ', prop.name, width = depth * 4 + 4)?,
_ => {
write!(f, "{:width$}{} = <", ' ', prop.name(), width = depth * 4 + 4)?;
write!(f, "{:width$}{} = <", ' ', prop.name, width = depth * 4 + 4)?;

for (i, n) in prop.as_value::<U32List>()?.iter().enumerate() {
if i != 0 {
Expand Down
Loading

0 comments on commit a36045c

Please sign in to comment.