From 27d7c8c9fe2c504f6350926bc74959df659c4202 Mon Sep 17 00:00:00 2001 From: kadiwa Date: Fri, 29 Sep 2023 18:52:17 +0200 Subject: [PATCH] - add `prop_value::Status` - add an output value to `NodeContext::deserialize_node` --- readme.md => README.md | 0 devicetree_derive/lib.rs | 2 +- src/blob.rs | 9 +++--- src/blob/node.rs | 8 ++--- src/blob/token.rs | 2 ++ src/lib.rs | 6 ++-- src/prop_value.rs | 70 ++++++++++++++++++++++++++++++++++------ 7 files changed, 77 insertions(+), 20 deletions(-) rename readme.md => README.md (100%) diff --git a/readme.md b/README.md similarity index 100% rename from readme.md rename to README.md diff --git a/devicetree_derive/lib.rs b/devicetree_derive/lib.rs index dd59bd8..b249ecb 100644 --- a/devicetree_derive/lib.rs +++ b/devicetree_derive/lib.rs @@ -169,7 +169,7 @@ pub fn derive_deserialize_node(tokens: proc_macro::TokenStream) -> proc_macro::T let cx_deserialize_node = |child_stmts| { quote! { - let cursor = cx.deserialize_node( + let (_, cursor) = cx.deserialize_node( blob_node, |name, prop| { match name { diff --git a/src/blob.rs b/src/blob.rs index 268125c..ff5420e 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -21,7 +21,7 @@ use std_alloc::{boxed::Box, vec::Vec}; use zerocopy::{AsBytes, FromBytes, FromZeroes, Ref}; -use crate::{util, DeserializeNode, DeserializeProperty, NodeContext, Path, ReserveEntries}; +use crate::{DeserializeNode, DeserializeProperty, NodeContext, Path, ReserveEntries}; /// Any low level, technical error caused by this crate. #[derive(Clone, Debug, PartialEq, Eq)] @@ -315,7 +315,7 @@ impl Devicetree { // Safety: bounds check was done in Self::late_checks unsafe { - util::slice_get_with_len_unchecked( + crate::util::slice_get_with_len_unchecked( self.blob_u32(), offset / STRUCT_BLOCK_ALIGN, len / STRUCT_BLOCK_ALIGN, @@ -329,7 +329,7 @@ impl Devicetree { let offset = u32::from_be(header.off_dt_strings) as usize; let len = u32::from_be(header.size_dt_strings) as usize; // Safety: bounds check was done in Self::late_checks - unsafe { util::slice_get_with_len_unchecked(self.blob_u8(), offset, len) } + unsafe { crate::util::slice_get_with_len_unchecked(self.blob_u8(), offset, len) } } /// Gets a node from the struct block by (loosely-matching) path. @@ -426,7 +426,8 @@ impl<'dtb> Property<'dtb> { /// # Errors /// Fails if the string is invalid. pub fn name(self) -> Result<&'dtb str> { - util::str_from_ascii(util::get_c_str(self.name_blob)?).ok_or(Error::InvalidString) + crate::util::str_from_ascii(crate::util::get_c_str(self.name_blob)?) + .ok_or(Error::InvalidString) } /// The property's value. diff --git a/src/blob/node.rs b/src/blob/node.rs index 0bb7491..23abc9d 100644 --- a/src/blob/node.rs +++ b/src/blob/node.rs @@ -9,7 +9,7 @@ use fallible_iterator::FallibleIterator; use crate::{ blob::{self, Cursor, Devicetree, Item, Property, Token, TOKEN_SIZE}, - util, Error, NodeContext, PushDeserializedNode, Result, + Error, NodeContext, PushDeserializedNode, Result, }; /// A node of the tree structure in a [`Devicetree`] blob's struct block. @@ -29,7 +29,7 @@ impl<'dtb> Node<'dtb> { /// The node's name. pub fn name(&self) -> blob::Result<&'dtb str> { - util::str_from_ascii(self.name).ok_or(blob::Error::InvalidString) + crate::util::str_from_ascii(self.name).ok_or(blob::Error::InvalidString) } /// The name as it would show up in a devicetree source file. @@ -50,7 +50,7 @@ impl<'dtb> Node<'dtb> { /// /// There cannot be more than one `@`. pub fn split_name(&self) -> Result<(&'dtb str, Option<&'dtb str>)> { - util::split_node_name(self.name()?) + crate::util::split_node_name(self.name()?) } /// Cursor pointing to this node's [`Token`]. @@ -115,7 +115,7 @@ impl<'dtb> Node<'dtb> { /// has to be unambiguous. pub fn get_child(&self, name: &str) -> Result>> { let mut iter = Children(Items::new(self, self.contents)); - if util::split_node_name(name)?.1.is_some() { + if crate::util::split_node_name(name)?.1.is_some() { iter.find(|n| Ok(n.name()? == name)) } else if let Some((candidate, (_, candidate_addr))) = (&mut iter) .map(|n| n.split_name().map(|split| (n, split))) diff --git a/src/blob/token.rs b/src/blob/token.rs index ddca120..c1e5335 100644 --- a/src/blob/token.rs +++ b/src/blob/token.rs @@ -33,6 +33,8 @@ impl<'dtb> Token<'dtb> { /// A position inside the [`Devicetree`] blob's struct block. /// +/// You can think of this as a byte offset from the blob's start address, but it +/// is a little more complicated in reality. /// Can be obtained from [`Node::content_cursor`] and advanced using /// [`Devicetree::next_token`]. /// diff --git a/src/lib.rs b/src/lib.rs index d9e5653..e32914c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,7 @@ pub enum Error { InvalidNodeName, InvalidPath, TooManyCells, + UnsuitableNode, UnsuitableProperty, } @@ -57,6 +58,7 @@ impl Display for Error { InvalidNodeName => "invalid node name", InvalidPath => "invalid path", TooManyCells => "too many cells", + UnsuitableNode => "unsuitable node", UnsuitableProperty => "unsuitable property", }; write!(f, "devicetree error: {description}") @@ -197,7 +199,7 @@ impl<'a> NodeContext<'a> { blob_node: &Node<'dtb>, mut f_prop: impl FnMut(&'dtb str, Property<'dtb>) -> Result<()>, mut f_child: impl FnMut(Node<'dtb>, Self, &mut Cursor) -> Result<()>, - ) -> Result { + ) -> Result<(Self, Cursor)> { let mut child_cx = Self { custom: self.custom, ..Self::default() @@ -225,7 +227,7 @@ impl<'a> NodeContext<'a> { } } } - Ok(items.cursor) + Ok((child_cx, items.cursor)) } } diff --git a/src/prop_value.rs b/src/prop_value.rs index 3a55df8..2031d2c 100644 --- a/src/prop_value.rs +++ b/src/prop_value.rs @@ -1,7 +1,10 @@ //! Types representing property values. use crate::{blob::Property, util, Cells, DeserializeProperty, Error, NodeContext, Result}; -use core::iter::FusedIterator; +use core::{ + fmt::{Display, Formatter}, + iter::FusedIterator, +}; use fallible_iterator::{DoubleEndedFallibleIterator, FallibleIterator}; @@ -47,22 +50,71 @@ impl<'dtb> DeserializeProperty<'dtb> for SizeCells { } } +/// Value of `status`. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +#[non_exhaustive] +pub enum Status<'a> { + #[default] + Ok, + Disabled, + Reserved, + Fail, + FailCondition(&'a str), +} + +impl<'dtb> DeserializeProperty<'dtb> for Status<'dtb> { + fn deserialize(blob_prop: Property<'dtb>, cx: NodeContext<'_>) -> Result { + <&str>::deserialize(blob_prop, cx)?.try_into() + } +} + +impl<'a> TryFrom<&'a str> for Status<'a> { + type Error = Error; + + fn try_from(string: &'a str) -> Result { + let ret = match string { + "okay" => Self::Ok, + "disabled" => Self::Disabled, + "reserved" => Self::Reserved, + "fail" => Self::Fail, + _ => Self::FailCondition( + string + .strip_prefix("fail-") + .ok_or(Error::UnsuitableProperty)?, + ), + }; + Ok(ret) + } +} + +impl Display for Status<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + match *self { + Self::Ok => f.write_str("okay"), + Self::Disabled => f.write_str("disabled"), + Self::Reserved => f.write_str("reserved"), + Self::Fail => f.write_str("fail"), + Self::FailCondition(condition) => write!(f, "fail-{condition}"), + } + } +} + /// Iterator over the strings contained in the property's value. /// /// Fused (see [`core::iter::FusedIterator`]). #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Strings<'dtb> { - value: &'dtb [u8], +pub struct Strings<'a> { + value: &'a [u8], } -impl<'dtb> Strings<'dtb> { +impl<'a> Strings<'a> { /// Empty iterator. Cannot be obtained from deserializing a property. pub const EMPTY: Self = Self { value: &[] }; /// Creates a new iterator over the strings contained in the value. /// /// Returns `None` if the value does not end in a null byte. - pub fn new(value: &'dtb [u8]) -> Option { + pub fn new(value: &'a [u8]) -> Option { matches!(value, [.., 0]).then_some(Self { value }) } } @@ -73,8 +125,8 @@ impl<'dtb> DeserializeProperty<'dtb> for Strings<'dtb> { } } -impl<'dtb> FallibleIterator for Strings<'dtb> { - type Item = &'dtb str; +impl<'a> FallibleIterator for Strings<'a> { + type Item = &'a str; type Error = Error; fn next(&mut self) -> Result, Self::Error> { @@ -96,7 +148,7 @@ impl<'dtb> FallibleIterator for Strings<'dtb> { } } -impl<'dtb> DoubleEndedFallibleIterator for Strings<'dtb> { +impl<'a> DoubleEndedFallibleIterator for Strings<'a> { fn next_back(&mut self) -> Result, Self::Error> { let [value @ .., _] = self.value else { return Ok(None); @@ -108,7 +160,7 @@ impl<'dtb> DoubleEndedFallibleIterator for Strings<'dtb> { } } -impl Default for Strings<'static> { +impl<'a> Default for Strings<'a> { fn default() -> Self { Self::EMPTY }