1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
//! Implementation of [coap_message::ReadableMessage] based on a serialized message
//!
//! [Message] is the main struct of this module -- if the message is available as a slice that
//! lives as long as the message, that's the type to use. Otherwise, implement [EncodedMessage] on
//! your data, and wrap it in an [EncodedMessageView]. (The [Message] is nothing else than the
//! options/payload slice plus the code in a struct).

use coap_message::*;

use crate::option_iteration::*;

/// An iterator producing [MessageOption]s by running along an encoded CoAP message options stream
/// by using a [OptPayloadReader] and discarding the payload.
pub struct OptionsIter<'a>(pub(crate) OptPayloadReader<'a>);

/// Option value used by this library to indicate a format error in the message that was not
/// detected by the time option / payload processing was started.
///
/// As this option is critical and proxy-unsafe, no application can expect to successfully process
/// any message that contains this option. (The number is from the experimental-use range;
/// implementations using this module will simply not support that option in experiments, as they
/// can not distinguish it from an option formatting error).
pub const OPTION_INVALID: u16 = u16::MAX;

impl<'a> Iterator for OptionsIter<'a> {
    type Item = MessageOption<'a>;

    fn next(&mut self) -> Option<MessageOption<'a>> {
        match self.0.next() {
            Some(OptItem::Option { number, data }) => Some(MessageOption {
                number,
                value: data,
            }),
            Some(OptItem::Error { .. }) => Some(MessageOption {
                number: OPTION_INVALID,
                value: &[],
            }),
            // No need to recurse or loop -- it's always the last one
            Some(OptItem::Payload(_)) => None,
            None => None,
        }
    }
}

/// A simple [coap_message::MessageOption] implementation for memory-mapped CoAP messages
pub struct MessageOption<'a> {
    number: u16,
    value: &'a [u8],
}

impl<'a> coap_message::MessageOption for MessageOption<'a> {
    fn number(&self) -> u16 {
        self.number
    }
    fn value(&self) -> &[u8] {
        self.value
    }
}

/// A CoAP message that resides in contiguous readable memory
///
/// This implementation does not attempt to do any early validation. On encoding errors discovered
/// at runtime, it simply emits the critical-and-not-safe-to-forward CoAP option 65535
/// ([OPTION_INVALID]), which to the indication indicates that something went wrong
#[derive(Clone)]
pub struct Message<'a> {
    inner: EncodedMessageView<SliceMessage<'a>>,
}

#[derive(Clone)]
struct SliceMessage<'a> {
    code: u8,
    options_and_payload: &'a [u8],
}

impl<'a> EncodedMessage for SliceMessage<'a> {
    fn code(&self) -> u8 {
        self.code
    }
    fn options_and_payload(&self) -> &[u8] {
        self.options_and_payload
    }
}

impl<'a> Message<'a> {
    pub fn new(code: u8, options_and_payload: &'a [u8]) -> Self {
        Self {
            inner: EncodedMessageView::new(SliceMessage {
                code,
                options_and_payload,
            }),
        }
    }
}

impl<'m> ReadableMessage for Message<'m> {
    type Code = u8;
    type MessageOption<'a> = MessageOption<'a>
    where
        Self: 'a,
    ;
    type OptionsIter<'a> = OptionsIter<'a>
    where
        Self: 'a,
    ;

    fn code(&self) -> u8 {
        self.inner.code()
    }

    fn payload(&self) -> &[u8] {
        self.inner.payload()
    }

    fn options(&self) -> OptionsIter<'_> {
        self.inner.options()
    }
}

/// A trait that can implemented on in-memory encoded messages; then, an [EncodedMessageView]
/// struct can be placed around the implementer to implement [coap_message::ReadableMessage].
pub trait EncodedMessage {
    /// The code of the message
    fn code(&self) -> u8;
    /// The memory area containing the encoded options, payload marker and payload
    fn options_and_payload(&self) -> &[u8];
}

/// A wrapper around any data structure containing a readable message
///
/// This is not `Sync` -- while it is currently a zero-sized wrapper, it may gain optimizations
/// later such as memoizing where the payload begins (and this is only practical with interior
/// mutability).
///
/// See [Message] for how this does not perform early validation and handles message errors.
// FIXME test whether the _phantom does the right thing
#[derive(Clone, Debug)]
pub struct EncodedMessageView<EM: EncodedMessage> {
    inner: EM,
    _phantom: core::marker::PhantomData<core::cell::Cell<()>>,
}

impl<EM: EncodedMessage> EncodedMessageView<EM> {
    pub fn new(inner: EM) -> Self {
        Self {
            inner,
            _phantom: core::marker::PhantomData,
        }
    }
}

/// When the inner item stores more than just the code and encoded options, this can be used to
/// gain read-only access to any additional data. (Mutating access is blocked to ensure that future
/// optimizations like memoizing the payload position are possible; it might still be enabled if
/// memoized data is cleared just to be on the safe side).
// FIXME: Might even dereference into it?
impl<EM: EncodedMessage> AsRef<EM> for EncodedMessageView<EM> {
    fn as_ref(&self) -> &EM {
        &self.inner
    }
}

impl<EM: EncodedMessage> ReadableMessage for EncodedMessageView<EM> {
    type Code = u8;
    type MessageOption<'a> = MessageOption<'a>
    where
        Self: 'a,
    ;
    type OptionsIter<'a> = OptionsIter<'a>
    where
        Self: 'a,
    ;

    fn code(&self) -> u8 {
        self.inner.code()
    }

    // This is one of the not-most-efficient things mentioned in the module introduction: It's
    // iterating through the complete options stream on every payload call, rather than memoizing
    // its location when the options are iterated over.
    fn payload(&self) -> &[u8] {
        let empty: &[u8] = &[];

        // ... into which we'll index
        let optpayload = self.inner.options_and_payload();

        OptPayloadReader::new(optpayload)
            .find(|x| !matches!(x, OptItem::Option { .. }))
            .map(|x| {
                if let OptItem::Payload(data) = x {
                    // Can't return data itself because the iterator doesn't outlive this function
                    // To be replaced when ptr_wrapping_offset_from is stabilized
                    let offset = data.as_ptr() as usize - optpayload.as_ptr() as usize;
                    &optpayload[offset..]
                } else {
                    // Silently produce empty payload -- the user will need to have checked the
                    // options and have found the 65535 option.
                    &[]
                }
            })
            .unwrap_or(empty)
    }

    fn options(&self) -> OptionsIter<'_> {
        OptionsIter(OptPayloadReader::new(self.inner.options_and_payload()))
    }
}