coap_message_implementations/
option_iteration.rs1use crate::option_extension::take_extension;
6
7#[derive(Debug)]
9#[cfg_attr(feature = "defmt", derive(defmt::Format))]
10pub enum OptItem<'a> {
11    Option { number: u16, data: &'a [u8] },
12    Payload(&'a [u8]),
13    Error(&'static str),
14}
15
16pub struct OptPayloadReader<'a> {
29    slice: &'a [u8],
30    option_base: u16,
31}
32
33impl<'a> OptPayloadReader<'a> {
34    pub fn new(slice: &'a [u8]) -> Self {
39        Self {
40            slice,
41            option_base: 0,
42        }
43    }
44}
45
46impl<'a> Iterator for OptPayloadReader<'a> {
47    type Item = OptItem<'a>;
48
49    fn next(&mut self) -> Option<OptItem<'a>> {
50        let delta_len = *self.slice.first()?;
51        self.slice = &self.slice[1..];
52
53        if delta_len == 0xff {
54            return Some(OptItem::Payload(core::mem::take(&mut self.slice)));
55        }
56
57        let mut delta = (delta_len as u16) >> 4;
58        let mut len = (delta_len as u16) & 0x0f;
59
60        if take_extension(&mut delta, &mut self.slice).is_err() {
61            return Some(OptItem::Error("Erroneous delta"));
64        }
65        if take_extension(&mut len, &mut self.slice).is_err() {
66            return Some(OptItem::Error("Erroneous len"));
67        }
68
69        if let Some(s) = self.option_base.checked_add(delta) {
70            self.option_base = s;
71        } else {
72            return Some(OptItem::Error("Options wrap"));
73        }
74
75        let len = len.into();
76
77        if self.slice.len() < len {
78            return Some(OptItem::Error("Too short for option"));
79        }
80
81        let (retslice, tail) = self.slice.split_at(len);
82        self.slice = tail;
83
84        Some(OptItem::Option {
85            number: self.option_base,
86            data: retslice,
87        })
88    }
89}