coap_message_implementations/
inmemory.rs

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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
//! 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).
//!
//! Note that the [`crate::inmemory_write`] has a similar mechanism but does without an equivalent
//! "view"; at the next breaking revision, those might be unified.
#![cfg_attr(feature = "downcast", allow(unsafe_code))]

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
///
/// Message is covariant over its lifetime because it only reads from there. FIXME: It should
/// express that using a Deref or something like that.
///
/// # Implementation details
///
/// When used with [coap_message::helpers::RefWithStaticType], it always uses its `'static`
/// counterpart as the corresponding type ID. Its [`Self::downcast_from`] method uses this, and
/// restores the lifetime based on the given impl Trait reference's lifetime using its covariance
/// property.
#[derive(Clone)]
pub struct Message<'a> {
    inner: EncodedMessageView<SliceMessage<'a>>,
}

#[derive(Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
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,
            }),
        }
    }

    #[cfg(feature = "downcast")]
    pub fn downcast_from<M: ReadableMessage>(generic: &'a M) -> Option<&'a Self> {
        let (reference, type_id) = generic.with_static_type_annotation()?.into_inner();
        if type_id != core::any::TypeId::of::<Message<'static>>() {
            return None;
        }
        // One of us, one of us.
        let ptr = reference as *const M as *const Self;
        // SAFETY: The RefWithStaticType matching our type ID will only be constructed if M is
        // Message, and whatever Message<'b> it was before, it will live at least for 'a (because
        // we got a &'a Message<'b> and is covariant.
        Some(unsafe { &*ptr })
    }
}

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()
    }

    #[cfg(feature = "downcast")]
    fn with_static_type_annotation(
        &self,
    ) -> Option<coap_message::helpers::RefWithStaticType<'_, Self>> {
        // SAFETY: It is this type's policy that its RefWithStaticType ID is the given
        // Message<'static>.
        Some(unsafe {
            coap_message::helpers::RefWithStaticType::new(
                self,
                core::any::TypeId::of::<Message<'static>>(),
            )
        })
    }
}

/// 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)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
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()))
    }
}