dot15d4_frame/ie/
mod.rs

1//! Information Elements readers and writers.
2
3mod headers;
4pub use headers::*;
5
6mod payloads;
7pub use payloads::*;
8
9mod nested;
10pub use nested::*;
11
12use super::{Error, Result};
13
14/// IEEE 802.15.4 Information Element reader.
15pub struct InformationElements<T: AsRef<[u8]>> {
16    data: T,
17}
18
19impl<T: AsRef<[u8]>> InformationElements<T> {
20    /// Create a new [`InformationElements`] reader from a given buffer.
21    ///
22    /// # Errors
23    ///
24    /// Returns an error if the buffer is too short to contain the information
25    /// elements.
26    pub fn new(data: T) -> Result<Self> {
27        let ie = Self::new_unchecked(data);
28
29        if !ie.check_len() {
30            return Err(Error);
31        }
32
33        Ok(ie)
34    }
35
36    /// Returns `false` if the buffer is too short to contain the information
37    /// elements.
38    fn check_len(&self) -> bool {
39        let mut len = 0;
40
41        let mut iter = self.header_information_elements();
42        while iter.next().is_some() {}
43        len += iter.offset();
44
45        if len > self.data.as_ref().len() {
46            return false;
47        }
48
49        let mut iter = self.payload_information_elements();
50        while iter.next().is_some() {}
51        len += iter.offset();
52
53        self.data.as_ref().len() >= len
54    }
55
56    /// Create a new [`InformationElements`] reader from a given buffer without
57    /// length checking.
58    pub fn new_unchecked(data: T) -> Self {
59        Self { data }
60    }
61
62    /// Returns the length of the information elements.
63    #[allow(clippy::len_without_is_empty)]
64    pub fn len(&self) -> usize {
65        let mut len = 0;
66
67        let mut iter = self.header_information_elements();
68        while iter.next().is_some() {}
69        len += iter.offset();
70
71        let mut iter = self.payload_information_elements();
72        while iter.next().is_some() {}
73        len += iter.offset();
74
75        len
76    }
77
78    /// Returns an [`Iterator`] over [`HeaderInformationElement`].
79    pub fn header_information_elements(&self) -> HeaderInformationElementsIterator {
80        HeaderInformationElementsIterator {
81            data: self.data.as_ref(),
82            offset: 0,
83            terminated: self.data.as_ref().is_empty(),
84        }
85    }
86
87    /// Returns an [`Iterator`] over [`PayloadInformationElement`].
88    pub fn payload_information_elements(&self) -> PayloadInformationElementsIterator {
89        let start = self
90            .header_information_elements()
91            .map(|ie| ie.len() + 2)
92            .sum::<usize>();
93
94        let terminated = start >= self.data.as_ref().len();
95
96        PayloadInformationElementsIterator {
97            data: &self.data.as_ref()[start..],
98            offset: 0,
99            terminated,
100        }
101    }
102}