Skip to main content

coap_message_implementations/inmemory/
iterators.rs

1//! Implementations of option iteration.
2
3use super::*;
4
5use crate::option_iteration::{OptItem, OptPayloadReader};
6
7/// An iterator producing [`MessageOption`]s by running along an encoded CoAP message options stream
8/// by using a [`OptPayloadReader`] and discarding the payload.
9///
10/// As an implementation detail (which makes it non-[`Send`]), this keeps a reference to
11/// memoization inside the message so that running the iterator up to the payload stores that
12/// position for later easier access.
13pub struct OptionsIter<'a>(
14    pub(crate) OptPayloadReader<'a>,
15    pub(crate) Option<&'a core::cell::Cell<Option<Processing>>>,
16);
17
18/// Option value used by this library to indicate a format error in the message that was not
19/// detected by the time option / payload processing was started.
20///
21/// As this option is critical and proxy-unsafe, no application can expect to successfully process
22/// any message that contains this option. (The number is from the experimental-use range;
23/// implementations using this module will simply not support that option in experiments, as they
24/// can not distinguish it from an option formatting error).
25pub const OPTION_INVALID: u16 = u16::MAX;
26
27impl<'a> Iterator for OptionsIter<'a> {
28    type Item = MessageOption<'a>;
29
30    fn next(&mut self) -> Option<MessageOption<'a>> {
31        let (new_cache, result) = match self.0.next() {
32            Some(OptItem::Option { number, data }) => (
33                None,
34                Some(MessageOption {
35                    number,
36                    value: data,
37                }),
38            ),
39            Some(OptItem::Error { .. }) => (
40                Some(Processing::Error),
41                Some(MessageOption {
42                    number: OPTION_INVALID,
43                    value: &[],
44                }),
45            ),
46            // No need to recurse or loop -- it's always the last one
47            Some(OptItem::Payload(p)) => (Some(Processing::OkPayloadLength(p.len())), None),
48            // This is not a fused iterator, so users might keep iterating -- and then writing
49            // OkNoPayload would be erroneous. But we only write when first finding the end, and
50            // that needs to have happened before we reach this in an unfused iteration.
51            None => (Some(Processing::OkNoPayload), None),
52        };
53
54        if let (Some(new_value), Some(cache)) = (new_cache, self.1) {
55            // See None case above for why we have to check
56            if cache.get().is_none() {
57                cache.set(Some(new_value));
58            }
59        }
60
61        result
62    }
63}
64
65/// A simple [`coap_message::MessageOption`] implementation for memory-mapped CoAP messages
66pub struct MessageOption<'a> {
67    number: u16,
68    value: &'a [u8],
69}
70
71impl coap_message::MessageOption for MessageOption<'_> {
72    fn number(&self) -> u16 {
73        self.number
74    }
75    fn value(&self) -> &[u8] {
76        self.value
77    }
78}