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}