1use bondrewd::Bitfields;
13use core::cell::Cell;
14
15use super::{
16 codes::Code, header::MessageHeader, options::OptionIterator, token::Token, Error, Message, Type,
17};
18
19#[derive(Debug, Clone, Eq)]
21pub struct EncodedMessage<'data> {
22 pub(crate) data: &'data [u8],
23 payload_offset_cache: Cell<Option<usize>>,
29}
30
31impl<'data> PartialEq for EncodedMessage<'data> {
32 fn eq(&self, other: &Self) -> bool {
33 self.data == other.data
34 }
35}
36
37impl<'data> EncodedMessage<'data> {
38 pub fn try_new(data: &'data [u8]) -> Result<Self, Error> {
43 if data.len() >= MessageHeader::BYTE_SIZE {
44 Ok(Self {
45 data,
46 payload_offset_cache: Cell::new(None),
47 })
48 } else {
49 Err(Error::MsgTooShort)
50 }
51 }
52
53 pub fn new_ack(message_id: u16, buf: &'data mut [u8; 4]) -> Self {
55 Message::<0>::new_ack(message_id).encode(buf).unwrap()
56 }
57
58 pub fn new_rst(message_id: u16, buf: &'data mut [u8; 4]) -> Self {
60 Message::<0>::new_rst(message_id).encode(buf).unwrap()
61 }
62
63 pub fn new_ping(message_id: u16, buf: &'data mut [u8; 4]) -> Self {
65 Message::<0>::new_ping(message_id).encode(buf).unwrap()
66 }
67
68 fn empty(message_type: Type, message_id: u16) -> [u8; 4] {
70 let mut buf = [0u8; 4];
71 Message::<0>::new_empty(message_type, message_id)
72 .encode(&mut buf)
73 .unwrap();
74 buf
75 }
76
77 pub fn ack(message_id: u16) -> [u8; 4] {
79 Self::empty(Type::Acknowledgement, message_id)
80 }
81
82 pub fn rst(message_id: u16) -> [u8; 4] {
84 Self::empty(Type::Reset, message_id)
85 }
86
87 pub fn ping(message_id: u16) -> [u8; 4] {
89 Self::empty(Type::Confirmable, message_id)
90 }
91
92 pub fn message_length(&self) -> usize {
94 self.data.len()
95 }
96
97 fn header(&self) -> MessageHeader {
99 let mut buf = [0_u8; MessageHeader::BYTE_SIZE];
100 buf.clone_from_slice(&self.data[..MessageHeader::BYTE_SIZE]);
101 MessageHeader::from_bytes(buf)
102 }
103
104 pub fn version(&self) -> u8 {
106 self.header().version()
107 }
108
109 pub fn message_type(&self) -> Type {
111 self.header().message_type()
112 }
113
114 pub fn code(&self) -> Result<Code, Error> {
116 self.header().code()
117 }
118
119 pub fn message_id(&self) -> u16 {
121 self.header().message_id()
122 }
123
124 pub fn token(&self) -> Result<Token, Error> {
126 let mut token = Token {
127 length: self.header().token_length()?,
128 ..Token::default()
129 };
130
131 token.bytes[..token.length.into()].copy_from_slice(
132 &self.data[MessageHeader::BYTE_SIZE
133 ..MessageHeader::BYTE_SIZE + self.header().token_length()? as usize],
134 );
135
136 Ok(token)
137 }
138
139 pub fn options_iter<'encmsg>(&'encmsg self) -> Result<OptionIterator<'encmsg, 'data>, Error> {
142 Ok(OptionIterator::new(
143 self,
144 MessageHeader::BYTE_SIZE + self.header().token_length()? as usize,
145 ))
146 }
147
148 fn payload_offset(&self) -> Result<usize, Error> {
150 if let Some(payload_offset) = self.payload_offset_cache.get() {
151 return Ok(payload_offset);
152 }
153 let mut iter = self.options_iter()?;
154 for option in iter.by_ref() {
157 let _ = option.map_err(Error::InvalidOption)?; }
159
160 Ok(self.payload_offset_cache.get().unwrap())
161 }
162
163 pub(crate) fn set_payload_offset(&self, payload_offset: usize) {
164 self.payload_offset_cache.set(Some(payload_offset))
165 }
166
167 pub fn payload(&self) -> Result<Option<&'data [u8]>, Error> {
175 let start_index = self.payload_offset()?;
176 if self.data.len() > start_index && self.data[start_index] == 0xFF {
178 Ok(Some(&self.data[start_index + 1..]))
179 } else {
180 assert!(
187 start_index == self.data.len(),
188 "No payload marker found but more data available"
189 );
190 Ok(None)
191 }
192 }
193
194 pub fn is_empty(&self) -> Result<bool, Error> {
196 Ok(matches!(self.code()?, Code::Empty))
197 }
198
199 pub fn is_request(&self) -> Result<bool, Error> {
201 Ok(matches!(self.code()?, Code::Request(_)))
202 }
203
204 pub fn is_response(&self) -> Result<bool, Error> {
206 Ok(matches!(self.code()?, Code::Response(_)))
207 }
208
209 pub fn is_empty_ack(&self) -> Result<bool, Error> {
211 Ok(matches!(self.message_type(), Type::Acknowledgement) && self.is_empty()?)
212 }
213
214 pub fn is_rst(&self) -> Result<bool, Error> {
216 Ok(matches!(self.message_type(), Type::Reset) && self.is_empty()?)
217 }
218
219 pub fn is_ping(&self) -> Result<bool, Error> {
221 Ok(matches!(self.message_type(), Type::Confirmable) && self.is_empty()?)
222 }
223
224 pub fn check_msg_format<const MAX_OPTION_SIZE: usize>(&self) -> Result<(), Error> {
249 use Error::*;
250 self.token()?;
251 let is_empty = self.is_empty()?;
254 if self.message_type() == Type::NonConfirmable && is_empty {
255 Err(EmptyNon)
256 } else if self.message_type() == Type::Acknowledgement && self.is_request().unwrap() {
257 Err(RequestAck)
258 } else if self.message_type() == Type::Reset && !is_empty {
259 Err(NonEmptyRst)
260 } else if is_empty {
261 if self.token().unwrap() == Token::default()
263 && self.options_iter()?.next().is_none()
264 && self.payload()?.is_none()
265 {
266 Ok(())
267 } else {
268 Err(EmptyWithContent)
269 }
270 } else {
271 Ok(())
272 }
273 }
274}
275
276#[cfg(test)]
277mod tests {
278 use super::*;
279 use crate::message::options::{CoapOption, CoapOptionName};
280 use crate::message::{self, Message};
281 use heapless::Vec;
282
283 fn enc_message<'payload, 'buffer>(
286 options: Vec<CoapOption<'_>, 2>,
287 payload: Option<&'payload [u8]>,
288 buf: &'buffer mut [u8],
289 ) -> EncodedMessage<'buffer> {
290 Message::new(
291 message::Type::Confirmable,
292 message::Code::Empty,
293 0,
294 message::Token::default(),
295 options,
296 payload,
297 )
298 .encode(buf)
299 .unwrap()
300 }
301
302 fn rec_message<'payload, 'buffer>(
305 options: Vec<CoapOption<'_>, 2>,
306 payload: Option<&'payload [u8]>,
307 buf: &'buffer mut [u8],
308 ) -> EncodedMessage<'buffer> {
309 let message = enc_message(options, payload, buf);
310 message.payload_offset_cache.set(None);
311 message
312 }
313
314 #[test]
317 fn decode_payload_marker_positions() {
318 let mut buf = [0; 1000];
320 let option0 = CoapOption {
322 name: CoapOptionName::Accept,
323 value: b"",
324 };
325 let option1 = CoapOption {
326 name: CoapOptionName::Accept,
327 value: b"option value",
328 };
329 let m = rec_message(Vec::new(), None, &mut buf);
331 assert_eq!(m.payload_offset_cache.get(), None);
332 for _ in m.options_iter().unwrap() {}
333 assert!(m.payload_offset_cache.get().is_some());
334 let m = rec_message(
336 Vec::from_slice(&[option0.clone(), option1.clone()]).unwrap(),
337 None,
338 &mut buf,
339 );
340 assert!(m.payload_offset_cache.get().is_none());
341 let mut iter = m.options_iter().unwrap();
342 iter.next();
343 iter.next();
344 assert!(m.payload_offset_cache.get().is_none());
345 iter.next();
346 assert!(m.payload_offset_cache.get().is_some());
347 let m = rec_message(Vec::new(), Some(b"payload"), &mut buf);
349 assert_eq!(m.payload_offset_cache.get(), None);
350 m.options_iter().unwrap().next();
351 assert!(m.payload_offset_cache.get().is_some());
352 let m = rec_message(
354 Vec::from_slice(&[option0.clone(), option1.clone()]).unwrap(),
355 Some(b"payload"),
356 &mut buf,
357 );
358 let mut iter = m.options_iter().unwrap();
359 iter.next();
360 iter.next();
361 assert!(m.payload_offset_cache.get().is_none());
362 iter.next();
363 assert!(m.payload_offset_cache.get().is_some());
364 let original = rec_message(Vec::new(), None, &mut buf);
366 let clone = original.clone();
367 original.options_iter().unwrap().next();
368 assert!(original.payload_offset_cache.get().is_some());
369 assert!(clone.payload_offset_cache.get().is_none());
370 let original = rec_message(Vec::new(), None, &mut buf);
372 original.options_iter().unwrap().next();
373 let clone = original.clone();
374 assert!(original.payload_offset_cache.get().is_some());
375 assert!(clone.payload_offset_cache.get().is_some());
376 let m = rec_message(Vec::new(), None, &mut buf);
378 m.payload_offset().unwrap();
379 assert!(m.payload_offset_cache.get().is_some());
380 let m = rec_message(
382 Vec::from_slice(&[option0.clone(), option1.clone()]).unwrap(),
383 None,
384 &mut buf,
385 );
386 let len = m.data.len();
389 buf[4] = 0xF0;
390 let m = EncodedMessage::try_new(&buf[..len]).unwrap();
391 for _ in m.options_iter().unwrap() {}
392 assert!(m.payload_offset_cache.get().is_none());
393 }
394
395 #[test]
397 fn encode_payload_marker_positions() {
398 let mut buf = [0; 1000];
400 let option0 = CoapOption {
402 name: CoapOptionName::Accept,
403 value: b"",
404 };
405 let option1 = CoapOption {
406 name: CoapOptionName::Accept,
407 value: b"option value",
408 };
409 let m = enc_message(Vec::new(), None, &mut buf);
411 assert!(m.payload_offset_cache.get().is_some());
412 let m = enc_message(
414 Vec::from_slice(&[option0.clone(), option1.clone()]).unwrap(),
415 None,
416 &mut buf,
417 );
418 assert!(m.payload_offset_cache.get().is_some());
419 let m = enc_message(Vec::new(), Some(b"payload"), &mut buf);
421 assert!(m.payload_offset_cache.get().is_some());
422 let m = enc_message(
424 Vec::from_slice(&[option0.clone(), option1.clone()]).unwrap(),
425 Some(b"payload"),
426 &mut buf,
427 );
428 assert!(m.payload_offset_cache.get().is_some());
429 }
430}