fdt_rs/base/
iters.rs

1//! Iterative parsers of a [`DevTree`].
2use core::marker::PhantomData;
3use core::mem::size_of;
4use core::num::NonZeroUsize;
5use core::str::from_utf8;
6
7use crate::prelude::*;
8
9use crate::base::parse::{next_devtree_token, ParsedTok};
10use crate::base::{DevTree, DevTreeItem, DevTreeNode, DevTreeProp};
11use crate::error::{DevTreeError, Result};
12use crate::spec::fdt_reserve_entry;
13
14// Re-export the basic parse iterator.
15pub use super::parse::DevTreeParseIter;
16pub use crate::common::prop::StringPropIter;
17
18use fallible_iterator::FallibleIterator;
19
20/// An iterator over [`fdt_reserve_entry`] objects within the FDT.
21#[derive(Clone)]
22pub struct DevTreeReserveEntryIter<'a, 'dt: 'a> {
23    offset: usize,
24    fdt: &'a DevTree<'dt>,
25}
26
27#[repr(transparent)]
28pub struct DevTreeReserveEntryRef<'dt>(*const fdt_reserve_entry, PhantomData<DevTree<'dt>>);
29
30impl<'dt> DevTreeReserveEntryRef<'dt> {
31    unsafe fn read_unaligned(&self) -> fdt_reserve_entry {
32        self.0.read_unaligned()
33    }
34}
35
36impl<'a, 'dt: 'a> DevTreeReserveEntryIter<'a, 'dt> {
37    pub(crate) fn new(fdt: &'a DevTree<'dt>) -> Self {
38        Self {
39            offset: fdt.off_mem_rsvmap(),
40            fdt,
41        }
42    }
43
44    /// Return the current offset as a fdt_reserve_entry pointer.
45    unsafe fn ptr(&'a self) -> Result<DevTreeReserveEntryRef<'dt>> {
46        Ok(DevTreeReserveEntryRef(
47            self.fdt.ptr_at(self.offset)?,
48            PhantomData,
49        ))
50    }
51}
52
53impl<'a, 'dt: 'a> Iterator for DevTreeReserveEntryIter<'a, 'dt> {
54    type Item = DevTreeReserveEntryRef<'dt>;
55    fn next(&mut self) -> Option<Self::Item> {
56        let next_offset = size_of::<fdt_reserve_entry>() + self.offset;
57        if next_offset > self.fdt.totalsize() {
58            None
59        } else {
60            // - We previously guarunteed enough memory with next_offset check.
61            // - All reads will be called through unaligned_read and are therefore
62            //   safe.
63            // - We will assume that given the iterator should be constructed
64            //   over a valid FDT that interpretting data is valid.
65            unsafe {
66                let res = self.ptr().unwrap();
67                let data: fdt_reserve_entry = res.read_unaligned();
68                if data.address == 0.into() && data.size == 0.into() {
69                    return None;
70                }
71                self.offset = next_offset;
72                Some(res)
73            }
74        }
75    }
76}
77
78/// An iterator over all [`DevTreeItem`] objects.
79#[derive(Clone, PartialEq)]
80pub struct DevTreeIter<'a, 'dt: 'a> {
81    /// Offset of the last opened Device Tree Node.
82    /// This is used to set properties' parent DevTreeNode.
83    ///
84    /// As defined by the spec, DevTreeProps must preceed Node definitions.
85    /// Therefore, once a node has been closed this offset is reset to None to indicate no
86    /// properties should follow.
87    current_prop_parent_off: Option<NonZeroUsize>,
88
89    /// Current offset into the flattened dt_struct section of the device tree.
90    offset: usize,
91    pub(crate) fdt: &'a DevTree<'dt>,
92}
93
94#[derive(Clone, PartialEq)]
95pub struct DevTreeNodeIter<'a, 'dt: 'a>(pub DevTreeIter<'a, 'dt>);
96impl<'a, 'dt: 'a> FallibleIterator for DevTreeNodeIter<'a, 'dt> {
97    type Item = DevTreeNode<'a, 'dt>;
98    type Error = DevTreeError;
99    fn next(&mut self) -> Result<Option<Self::Item>> {
100        self.0.next_node()
101    }
102}
103
104#[derive(Clone, PartialEq)]
105pub struct DevTreePropIter<'a, 'dt: 'a>(pub DevTreeIter<'a, 'dt>);
106impl<'a, 'dt: 'a> FallibleIterator for DevTreePropIter<'a, 'dt> {
107    type Error = DevTreeError;
108    type Item = DevTreeProp<'a, 'dt>;
109    fn next(&mut self) -> Result<Option<Self::Item>> {
110        self.0.next_prop()
111    }
112}
113
114#[derive(Clone, PartialEq)]
115pub struct DevTreeNodePropIter<'a, 'dt: 'a>(pub DevTreeIter<'a, 'dt>);
116impl<'a, 'dt: 'a> FallibleIterator for DevTreeNodePropIter<'a, 'dt> {
117    type Error = DevTreeError;
118    type Item = DevTreeProp<'a, 'dt>;
119    fn next(&mut self) -> Result<Option<Self::Item>> {
120        self.0.next_node_prop()
121    }
122}
123
124#[derive(Clone, PartialEq)]
125pub struct DevTreeCompatibleNodeIter<'s, 'a, 'dt: 'a> {
126    pub iter: DevTreeIter<'a, 'dt>,
127    pub string: &'s str,
128}
129impl<'s, 'a, 'dt: 'a> FallibleIterator for DevTreeCompatibleNodeIter<'s, 'a, 'dt> {
130    type Error = DevTreeError;
131    type Item = DevTreeNode<'a, 'dt>;
132    fn next(&mut self) -> Result<Option<Self::Item>> {
133        self.iter.next_compatible_node(self.string)
134    }
135}
136
137impl<'a, 'dt: 'a> DevTreeIter<'a, 'dt> {
138    pub fn new(fdt: &'a DevTree<'dt>) -> Self {
139        Self {
140            offset: fdt.off_dt_struct(),
141            current_prop_parent_off: None,
142            fdt,
143        }
144    }
145
146    fn current_node_itr(&self) -> Option<DevTreeIter<'a, 'dt>> {
147        self.current_prop_parent_off.map(|offset| DevTreeIter {
148            fdt: self.fdt,
149            current_prop_parent_off: Some(offset),
150            offset: offset.get(),
151        })
152    }
153
154    pub fn last_node(mut self) -> Option<DevTreeNode<'a, 'dt>> {
155        if let Some(off) = self.current_prop_parent_off.take() {
156            self.offset = off.get();
157            return self.next_node().unwrap();
158        }
159        None
160    }
161
162    pub fn next_item(&mut self) -> Result<Option<DevTreeItem<'a, 'dt>>> {
163        loop {
164            let old_offset = self.offset;
165            // Safe because we only pass offsets which are returned by next_devtree_token.
166            let res = unsafe { next_devtree_token(self.fdt.buf(), &mut self.offset)? };
167
168            match res {
169                Some(ParsedTok::BeginNode(node)) => {
170                    self.current_prop_parent_off =
171                        unsafe { Some(NonZeroUsize::new_unchecked(old_offset)) };
172                    return Ok(Some(DevTreeItem::Node(DevTreeNode {
173                        parse_iter: self.clone(),
174                        name: from_utf8(node.name).map_err(|e| e.into()),
175                    })));
176                }
177                Some(ParsedTok::Prop(prop)) => {
178                    // Prop must come after a node.
179                    let prev_node = match self.current_node_itr() {
180                        Some(n) => n,
181                        None => return Err(DevTreeError::ParseError),
182                    };
183
184                    return Ok(Some(DevTreeItem::Prop(DevTreeProp::new(
185                        prev_node,
186                        prop.prop_buf,
187                        prop.name_offset,
188                    ))));
189                }
190                Some(ParsedTok::EndNode) => {
191                    // The current node has ended.
192                    // No properties may follow until the next node starts.
193                    self.current_prop_parent_off = None;
194                }
195                Some(_) => continue,
196                None => return Ok(None),
197            }
198        }
199    }
200
201    pub fn next_prop(&mut self) -> Result<Option<DevTreeProp<'a, 'dt>>> {
202        loop {
203            match self.next() {
204                Ok(Some(DevTreeItem::Prop(p))) => return Ok(Some(p)),
205                Ok(Some(_n)) => continue,
206                Ok(None) => return Ok(None),
207                Err(e) => return Err(e),
208            }
209        }
210    }
211
212    pub fn next_node(&mut self) -> Result<Option<DevTreeNode<'a, 'dt>>> {
213        loop {
214            match self.next() {
215                Ok(Some(DevTreeItem::Node(n))) => return Ok(Some(n)),
216                Ok(Some(_p)) => continue,
217                Ok(None) => return Ok(None),
218                Err(e) => return Err(e),
219            }
220        }
221    }
222
223    pub fn next_node_prop(&mut self) -> Result<Option<DevTreeProp<'a, 'dt>>> {
224        match self.next() {
225            // Return if a new node or an EOF.
226            Ok(Some(item)) => Ok(item.prop()),
227            Ok(None) => Ok(None),
228            Err(e) => Err(e),
229        }
230    }
231
232    pub fn next_compatible_node(&mut self, string: &str) -> Result<Option<DevTreeNode<'a, 'dt>>> {
233        // If there is another node, advance our iterator to that node.
234        self.next_node().and_then(|_| {
235            // Iterate through all remaining properties in the tree looking for the compatible
236            // string.
237            loop {
238                match self.next_prop() {
239                    Ok(Some(prop)) => {
240                        if prop.name()? == "compatible" {
241                            let mut candidates = prop.iter_str();
242                            while let Some(s) = candidates.next()? {
243                                if s.eq(string) {
244                                    return Ok(Some(prop.node()));
245                                }
246                            }
247                        }
248                        continue;
249                    }
250                    Ok(None) => return Ok(None),
251                    Err(e) => return Err(e),
252                }
253            }
254        })
255    }
256}
257
258impl<'a, 'dt: 'a> FallibleIterator for DevTreeIter<'a, 'dt> {
259    type Error = DevTreeError;
260    type Item = DevTreeItem<'a, 'dt>;
261
262    fn next(&mut self) -> Result<Option<Self::Item>> {
263        self.next_item()
264    }
265}