use core::marker::PhantomData;
use core::mem::size_of;
use core::num::NonZeroUsize;
use core::str::from_utf8;
use crate::prelude::*;
use crate::base::parse::{next_devtree_token, ParsedTok};
use crate::base::{DevTree, DevTreeItem, DevTreeNode, DevTreeProp};
use crate::error::{DevTreeError, Result};
use crate::spec::fdt_reserve_entry;
pub use super::parse::DevTreeParseIter;
pub use crate::common::prop::StringPropIter;
use fallible_iterator::FallibleIterator;
#[derive(Clone)]
pub struct DevTreeReserveEntryIter<'a, 'dt: 'a> {
offset: usize,
fdt: &'a DevTree<'dt>,
}
#[repr(transparent)]
pub struct DevTreeReserveEntryRef<'dt>(*const fdt_reserve_entry, PhantomData<DevTree<'dt>>);
impl<'dt> DevTreeReserveEntryRef<'dt> {
unsafe fn read_unaligned(&self) -> fdt_reserve_entry {
self.0.read_unaligned()
}
}
impl<'a, 'dt: 'a> DevTreeReserveEntryIter<'a, 'dt> {
pub(crate) fn new(fdt: &'a DevTree<'dt>) -> Self {
Self {
offset: fdt.off_mem_rsvmap(),
fdt,
}
}
unsafe fn ptr(&'a self) -> Result<DevTreeReserveEntryRef<'dt>> {
Ok(DevTreeReserveEntryRef(
self.fdt.ptr_at(self.offset)?,
PhantomData,
))
}
}
impl<'a, 'dt: 'a> Iterator for DevTreeReserveEntryIter<'a, 'dt> {
type Item = DevTreeReserveEntryRef<'dt>;
fn next(&mut self) -> Option<Self::Item> {
let next_offset = size_of::<fdt_reserve_entry>() + self.offset;
if next_offset > self.fdt.totalsize() {
None
} else {
unsafe {
let res = self.ptr().unwrap();
let data: fdt_reserve_entry = res.read_unaligned();
if data.address == 0.into() && data.size == 0.into() {
return None;
}
self.offset = next_offset;
Some(res)
}
}
}
}
#[derive(Clone, PartialEq)]
pub struct DevTreeIter<'a, 'dt: 'a> {
current_prop_parent_off: Option<NonZeroUsize>,
offset: usize,
pub(crate) fdt: &'a DevTree<'dt>,
}
#[derive(Clone, PartialEq)]
pub struct DevTreeNodeIter<'a, 'dt: 'a>(pub DevTreeIter<'a, 'dt>);
impl<'a, 'dt: 'a> FallibleIterator for DevTreeNodeIter<'a, 'dt> {
type Item = DevTreeNode<'a, 'dt>;
type Error = DevTreeError;
fn next(&mut self) -> Result<Option<Self::Item>> {
self.0.next_node()
}
}
#[derive(Clone, PartialEq)]
pub struct DevTreePropIter<'a, 'dt: 'a>(pub DevTreeIter<'a, 'dt>);
impl<'a, 'dt: 'a> FallibleIterator for DevTreePropIter<'a, 'dt> {
type Error = DevTreeError;
type Item = DevTreeProp<'a, 'dt>;
fn next(&mut self) -> Result<Option<Self::Item>> {
self.0.next_prop()
}
}
#[derive(Clone, PartialEq)]
pub struct DevTreeNodePropIter<'a, 'dt: 'a>(pub DevTreeIter<'a, 'dt>);
impl<'a, 'dt: 'a> FallibleIterator for DevTreeNodePropIter<'a, 'dt> {
type Error = DevTreeError;
type Item = DevTreeProp<'a, 'dt>;
fn next(&mut self) -> Result<Option<Self::Item>> {
self.0.next_node_prop()
}
}
#[derive(Clone, PartialEq)]
pub struct DevTreeCompatibleNodeIter<'s, 'a, 'dt: 'a> {
pub iter: DevTreeIter<'a, 'dt>,
pub string: &'s str,
}
impl<'s, 'a, 'dt: 'a> FallibleIterator for DevTreeCompatibleNodeIter<'s, 'a, 'dt> {
type Error = DevTreeError;
type Item = DevTreeNode<'a, 'dt>;
fn next(&mut self) -> Result<Option<Self::Item>> {
self.iter.next_compatible_node(self.string)
}
}
impl<'a, 'dt: 'a> DevTreeIter<'a, 'dt> {
pub fn new(fdt: &'a DevTree<'dt>) -> Self {
Self {
offset: fdt.off_dt_struct(),
current_prop_parent_off: None,
fdt,
}
}
fn current_node_itr(&self) -> Option<DevTreeIter<'a, 'dt>> {
self.current_prop_parent_off.map(|offset| DevTreeIter {
fdt: self.fdt,
current_prop_parent_off: Some(offset),
offset: offset.get(),
})
}
pub fn last_node(mut self) -> Option<DevTreeNode<'a, 'dt>> {
if let Some(off) = self.current_prop_parent_off.take() {
self.offset = off.get();
return self.next_node().unwrap();
}
None
}
pub fn next_item(&mut self) -> Result<Option<DevTreeItem<'a, 'dt>>> {
loop {
let old_offset = self.offset;
let res = unsafe { next_devtree_token(self.fdt.buf(), &mut self.offset)? };
match res {
Some(ParsedTok::BeginNode(node)) => {
self.current_prop_parent_off =
unsafe { Some(NonZeroUsize::new_unchecked(old_offset)) };
return Ok(Some(DevTreeItem::Node(DevTreeNode {
parse_iter: self.clone(),
name: from_utf8(node.name).map_err(|e| e.into()),
})));
}
Some(ParsedTok::Prop(prop)) => {
let prev_node = match self.current_node_itr() {
Some(n) => n,
None => return Err(DevTreeError::ParseError),
};
return Ok(Some(DevTreeItem::Prop(DevTreeProp::new(
prev_node,
prop.prop_buf,
prop.name_offset,
))));
}
Some(ParsedTok::EndNode) => {
self.current_prop_parent_off = None;
}
Some(_) => continue,
None => return Ok(None),
}
}
}
pub fn next_prop(&mut self) -> Result<Option<DevTreeProp<'a, 'dt>>> {
loop {
match self.next() {
Ok(Some(DevTreeItem::Prop(p))) => return Ok(Some(p)),
Ok(Some(_n)) => continue,
Ok(None) => return Ok(None),
Err(e) => return Err(e),
}
}
}
pub fn next_node(&mut self) -> Result<Option<DevTreeNode<'a, 'dt>>> {
loop {
match self.next() {
Ok(Some(DevTreeItem::Node(n))) => return Ok(Some(n)),
Ok(Some(_p)) => continue,
Ok(None) => return Ok(None),
Err(e) => return Err(e),
}
}
}
pub fn next_node_prop(&mut self) -> Result<Option<DevTreeProp<'a, 'dt>>> {
match self.next() {
Ok(Some(item)) => Ok(item.prop()),
Ok(None) => Ok(None),
Err(e) => Err(e),
}
}
pub fn next_compatible_node(&mut self, string: &str) -> Result<Option<DevTreeNode<'a, 'dt>>> {
self.next_node().and_then(|_| {
loop {
match self.next_prop() {
Ok(Some(prop)) => {
if prop.name()? == "compatible" {
let mut candidates = prop.iter_str();
while let Some(s) = candidates.next()? {
if s.eq(string) {
return Ok(Some(prop.node()));
}
}
}
continue;
}
Ok(None) => return Ok(None),
Err(e) => return Err(e),
}
}
})
}
}
impl<'a, 'dt: 'a> FallibleIterator for DevTreeIter<'a, 'dt> {
type Error = DevTreeError;
type Item = DevTreeItem<'a, 'dt>;
fn next(&mut self) -> Result<Option<Self::Item>> {
self.next_item()
}
}