coap_message_implementations/
inmemory_write.rs1#![cfg_attr(feature = "downcast", allow(unsafe_code))]
13
14pub use crate::error::WriteError;
15
16pub type Message<'a> = GenericMessage<SliceMessage<'a>>;
18
19#[derive(Clone)]
21pub struct GenericMessage<EM: EncodedMessage> {
22 encoded: EM,
24
25 latest: u16,
27 end: usize,
29 payload_start: Option<usize>,
34}
35
36impl<EM: EncodedMessage> core::fmt::Debug for GenericMessage<EM> {
37 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
38 f.debug_struct("GenericMessage")
39 .field("EncodedMessage impl", &core::any::type_name::<EM>())
40 .field("encoded.code", &self.encoded.code())
41 .field("encoded.tail", &self.encoded.tail())
42 .field("latest", &self.latest)
43 .field("end", &self.end)
44 .field("payload_start", &self.payload_start)
45 .finish()
46 }
47}
48
49#[cfg(feature = "defmt")]
50impl<EM: EncodedMessage> defmt::Format for GenericMessage<EM> {
51 fn format(&self, f: defmt::Formatter<'_>) {
52 defmt::write!(
53 f,
54 "GenericMessage {{ EncodedMessage impl {=str}, code {=u8}, tail {=[u8]}, latest {=u16}, end {}, payload_start {} }}",
55 &core::any::type_name::<EM>(),
56 self.encoded.code(),
57 self.encoded.tail(),
58 self.latest,
59 self.end,
60 self.payload_start
61 );
62 }
63}
64
65pub trait EncodedMessage {
70 fn code(&self) -> &u8;
71 fn code_mut(&mut self) -> &mut u8;
72 fn tail(&self) -> &[u8];
73 fn tail_mut(&mut self) -> &mut [u8];
74}
75
76pub struct SliceMessage<'a> {
78 code: &'a mut u8,
79 tail: &'a mut [u8],
80}
81
82impl EncodedMessage for SliceMessage<'_> {
83 fn code_mut(&mut self) -> &mut u8 {
84 self.code
85 }
86
87 fn tail_mut(&mut self) -> &mut [u8] {
88 self.tail
89 }
90
91 fn code(&self) -> &u8 {
92 self.code
93 }
94
95 fn tail(&self) -> &[u8] {
96 self.tail
97 }
98}
99
100impl<'a> Message<'a> {
125 pub fn new(code: &'a mut u8, tail: &'a mut [u8]) -> Self {
126 Message {
127 encoded: SliceMessage { code, tail },
128 latest: 0,
129 end: 0,
130 payload_start: None,
131 }
132 }
133
134 pub fn new_from_existing(code: &'a mut u8, tail: &'a mut [u8]) -> Self {
145 let read_only = crate::inmemory::Message::new(*code, tail);
151 use coap_message::ReadableMessage;
154 let payload_len = read_only.payload().len();
155
156 let payload_start = match payload_len {
157 0 => None,
158 n => Some(tail.len() - n),
159 };
160 let end = tail.len();
161
162 Message {
163 encoded: SliceMessage { code, tail },
164 payload_start,
165 end,
166 latest: u16::MAX,
169 }
170 }
171
172 #[cfg(feature = "downcast")]
173 pub fn downcast_from<M: coap_message::MinimalWritableMessage>(
174 generic: &'a mut M,
175 ) -> Option<&'a mut Self> {
176 let (reference, type_id) = generic.with_static_type_annotation()?.into_inner();
177 if type_id != core::any::TypeId::of::<Message<'static>>() {
178 return None;
179 }
180 let ptr = reference as *mut M as *mut Self;
182 Some(unsafe { &mut *ptr })
186 }
187}
188
189impl<T: EncodedMessage> GenericMessage<T> {
190 pub fn new_from_empty_encoded(encoded: T) -> Self {
191 GenericMessage {
192 encoded,
193 latest: 0,
194 end: 0,
195 payload_start: None,
196 }
197 }
198}
199
200fn get_option_header_len(header: u8) -> u8 {
201 let mut res = 1;
202 match header >> 4 {
203 14 => res += 2,
204 13 => res += 1,
205 _ => (),
206 }
207 match header & 0b1111 {
208 14 => res += 2,
209 13 => res += 1,
210 _ => (),
211 }
212 res
213}
214
215impl<EM: EncodedMessage> GenericMessage<EM> {
216 fn options_end(&self) -> usize {
218 self.payload_start.map_or(self.end, |s| s - 1)
219 }
220
221 pub fn insert_option(&mut self, number: u16, data: &[u8]) -> Result<(), WriteError> {
233 use crate::{
234 option_extension::encode_extensions,
235 option_iteration::{OptItem, OptPayloadReader},
236 };
237
238 let Ok(data_len) = u16::try_from(data.len()) else {
239 return Err(WriteError::BadEncoding);
240 };
241
242 let mut insertion_point = 0;
243 let mut previous_option = 0u16;
244 let mut next_option = 0u16;
245 let mut next_len = None;
246
247 let options_end = self.options_end();
248
249 let tail = self.encoded.tail_mut();
250
251 if self.latest <= number {
252 insertion_point = options_end;
253 previous_option = self.latest;
254 } else {
255 let mut opt_iter = OptPayloadReader::new(tail);
256 loop {
257 match opt_iter.next() {
258 Some(OptItem::Option { number: num, data }) => {
259 if num <= number {
260 let (slice, base) = opt_iter.destruct();
261 insertion_point = tail.len() - slice.len();
262 previous_option = base;
263 opt_iter = OptPayloadReader::new_from(slice, base);
264 continue;
265 }
266
267 next_option = num;
268 next_len = Some(
269 u16::try_from(data.len()).expect("Guaranteed by OptPayloadReader"),
270 );
271 break;
272 }
273 _ => return Err(WriteError::BadEncoding),
274 }
275 }
276 }
277
278 let delta = number.checked_sub(previous_option).expect("Checked above");
280 let new_encoded = encode_extensions(delta, data_len);
281 let new_encoded = new_encoded.as_ref();
282
283 let current_encoded_len = get_option_header_len(tail[insertion_point]);
284
285 let encoding_length_delta;
287 let next_encoded;
288
289 let added_len = if let Some(next_len) = next_len {
291 let next_delta = next_option - number;
293 let next_encoded_tmp = encode_extensions(next_delta, next_len);
294
295 encoding_length_delta = usize::from(current_encoded_len)
298 .checked_sub(next_encoded_tmp.as_ref().len())
299 .expect("Encoding length can only shrink");
300
301 next_encoded = Some(next_encoded_tmp);
302 new_encoded.len() - encoding_length_delta + data.len()
303 } else {
304 next_encoded = None;
305
306 encoding_length_delta = 0;
307 new_encoded.len() + data.len()
308 };
309
310 if self.end + added_len > tail.len() {
311 return Err(WriteError::OutOfSpace);
312 }
313
314 let src = insertion_point + encoding_length_delta..self.end;
320 self.encoded
321 .tail_mut()
322 .copy_within(src, insertion_point + added_len);
323
324 if let Some(payload_start) = self.payload_start {
325 self.payload_start = Some(payload_start + added_len);
326 }
327
328 self.encoded
329 .tail_mut()
330 .get_mut(insertion_point..insertion_point + new_encoded.len())
331 .expect("Remaining length has been checked")
332 .copy_from_slice(new_encoded);
333 insertion_point += new_encoded.len();
334 self.encoded
335 .tail_mut()
336 .get_mut(insertion_point..insertion_point + data.len())
337 .expect("Remaining length has been checked")
338 .copy_from_slice(data);
339 insertion_point += data.len();
340
341 if let Some(next_encoded) = next_encoded {
342 self.encoded
343 .tail_mut()
344 .get_mut(insertion_point..insertion_point + next_encoded.as_ref().len())
345 .expect("Remaining length has been checked")
346 .copy_from_slice(next_encoded.as_ref());
347 } else {
348 self.latest = number;
349 }
350
351 self.end += added_len;
352
353 Ok(())
354 }
355
356 fn remove_option_at(
365 tail: &mut [u8],
366 index: usize,
367 end: usize,
368 previous_option: u16,
369 ) -> Result<isize, WriteError> {
370 use crate::{
371 option_extension::encode_extensions,
372 option_iteration::{OptItem, OptPayloadReader},
373 };
374
375 let mut opt_iter = OptPayloadReader::new_from(&tail[index..], previous_option);
376
377 let (number, data) = match opt_iter.next().ok_or(WriteError::BadEncoding)? {
379 OptItem::Option { number, data } => (number, data),
380 _ => return Err(WriteError::BadEncoding),
381 };
382
383 let next_opt = match opt_iter.next().ok_or(WriteError::BadEncoding)? {
385 OptItem::Option { number, data } => Some((number, data)),
386 OptItem::Payload(_) => None,
387 _ => return Err(WriteError::BadEncoding),
388 };
389
390 let current_encoded_len = isize::from(get_option_header_len(tail[index]));
391
392 let encoding_length_delta;
394 let next_encoded;
395
396 let len_removed = if let Some((next_number, next_data)) = next_opt {
398 let next_data_len =
399 u16::try_from(next_data.len()).map_err(|_| WriteError::BadEncoding)?;
400
401 let current_next_delta = next_number - number;
403 let current_next_encoded = encode_extensions(current_next_delta, next_data_len);
404 let current_next_encoded_len = current_next_encoded.as_ref().len() as isize;
405
406 let next_delta = next_number - previous_option;
408 let next_encoded_tmp = encode_extensions(next_delta, next_data_len);
409
410 encoding_length_delta =
413 next_encoded_tmp.as_ref().len() as isize - current_next_encoded_len;
414
415 next_encoded = Some(next_encoded_tmp);
416 current_encoded_len - encoding_length_delta + data.len() as isize
417 } else {
418 next_encoded = None;
419
420 encoding_length_delta = 0;
421 current_encoded_len + data.len() as isize
422 };
423
424 if tail.len() < (end as isize - len_removed) as usize {
426 return Err(WriteError::OutOfSpace);
427 }
428
429 if end.saturating_sub(index + current_encoded_len as usize + data.len()) != 0 {
431 let src =
433 index + current_encoded_len as usize + data.len() + encoding_length_delta as usize
434 ..end;
435 tail.copy_within(src, index + encoding_length_delta as usize);
436 }
437
438 if let Some(next_encoded) = next_encoded {
440 tail.get_mut(index..index + next_encoded.as_ref().len())
442 .expect("checked above")
443 .copy_from_slice(next_encoded.as_ref());
444 }
445
446 Ok(len_removed)
447 }
448
449 pub fn retain_options<P>(&mut self, predicate: P) -> Result<(), WriteError>
456 where
457 P: Fn(u16, &[u8]) -> bool,
458 {
459 use crate::option_iteration::{OptItem, OptPayloadReader};
460
461 if self.latest == 0 {
462 return Ok(());
463 }
464
465 let tail = self.encoded.tail_mut();
466 let mut opt_iter = OptPayloadReader::new(tail);
467 let mut previous_option = 0u16;
468 let mut opt_index = 0;
469
470 loop {
471 match opt_iter.next() {
472 Some(OptItem::Option { number, data }) => {
473 let (slice, _) = opt_iter.destruct();
474
475 if predicate(number, data) {
476 previous_option = number;
477 opt_index = tail.len() - slice.len();
478
479 opt_iter = OptPayloadReader::new_from(slice, number);
480 continue;
481 }
482
483 let len_removed =
484 Self::remove_option_at(tail, opt_index, self.end, previous_option)?;
485
486 self.end = (self.end as isize - len_removed) as usize;
487 let options_end = if let Some(payload_start) = self.payload_start {
488 let new = (payload_start as isize - len_removed) as usize;
489 self.payload_start = Some(new);
490 new - 1
491 } else {
492 self.end
493 };
494
495 if opt_index == options_end {
496 self.latest = previous_option;
497 return Ok(());
498 }
499
500 opt_iter = OptPayloadReader::new_from(&tail[opt_index..], previous_option);
501 }
502 None | Some(OptItem::Payload(_)) => return Ok(()),
503 Some(OptItem::Error(_)) => return Err(WriteError::BadEncoding),
504 }
505 }
506 }
507
508 pub fn reset(&mut self) {
514 self.latest = 0;
515 self.end = 0;
516 self.payload_start = None;
517 *self.encoded.code_mut() = 0;
520 }
521
522 pub fn untruncate(&mut self, mut added_len: usize) -> Result<(), WriteError> {
527 if self.payload_start.is_none() {
528 added_len += 1;
529 }
530
531 if self.encoded.tail().len() < self.end + added_len {
532 return Err(WriteError::OutOfSpace);
533 }
534
535 if self.payload_start.is_none() {
536 self.encoded.tail_mut()[self.end] = 0xff;
538 self.payload_start = Some(self.end + 1);
539 }
540
541 self.end += added_len;
542
543 Ok(())
544 }
545
546 pub fn finish(self) -> usize {
548 self.end
549 }
550
551 pub fn finish_and_return(self) -> (usize, EM) {
557 (self.end, self.encoded)
558 }
559}
560
561impl<EM: EncodedMessage> coap_message::ReadableMessage for GenericMessage<EM> {
562 type Code = u8;
563 type MessageOption<'b>
564 = crate::inmemory::MessageOption<'b>
565 where
566 Self: 'b;
567 type OptionsIter<'b>
568 = crate::inmemory::OptionsIter<'b>
569 where
570 Self: 'b;
571 fn code(&self) -> u8 {
572 *self.encoded.code()
573 }
574 fn payload(&self) -> &[u8] {
577 match self.payload_start {
578 None => &[],
579 Some(start) => &self.encoded.tail()[start..self.end],
580 }
581 }
582 fn options(&self) -> <Self as coap_message::ReadableMessage>::OptionsIter<'_> {
583 crate::inmemory::OptionsIter(crate::option_iteration::OptPayloadReader::new(
584 &self.encoded.tail()[..self.end],
585 ))
586 }
587}
588
589impl<EM: EncodedMessage> coap_message::WithSortedOptions for GenericMessage<EM> {}
590
591impl<EM: EncodedMessage> coap_message::MinimalWritableMessage for GenericMessage<EM> {
592 type Code = u8;
593 type OptionNumber = u16;
594 type UnionError = WriteError;
595 type AddOptionError = WriteError;
596 type SetPayloadError = WriteError;
597
598 fn set_code(&mut self, code: u8) {
599 *self.encoded.code_mut() = code;
600 }
601
602 fn add_option(&mut self, number: u16, data: &[u8]) -> Result<(), WriteError> {
603 let delta = number
604 .checked_sub(self.latest)
605 .ok_or(WriteError::OutOfSequence)?;
606 self.latest = number;
607 let encoded = crate::option_extension::encode_extensions(delta, data.len() as u16);
608 let encoded = encoded.as_ref();
609 let added_len = encoded.len() + data.len();
610
611 let option_cursor;
613 let eventual_end;
615 if let Some(payload_start) = self.payload_start {
616 option_cursor = payload_start - 1;
617 let Some(start_dropping_at) = self.encoded.tail().len().checked_sub(added_len) else {
618 return Err(WriteError::OutOfSpace);
620 };
621 if start_dropping_at < option_cursor {
622 return Err(WriteError::OutOfSpace);
624 }
625 let retained_payload_with_marker = start_dropping_at - option_cursor;
626 if retained_payload_with_marker > 1 {
628 let src = option_cursor..start_dropping_at;
631 self.encoded
632 .tail_mut()
633 .copy_within(src, option_cursor + added_len);
634
635 self.payload_start = Some(payload_start + added_len);
636 eventual_end = (self.end + added_len).clamp(0, self.encoded.tail().len());
637 } else {
638 self.payload_start = None;
639 eventual_end = self.encoded.tail().len() - retained_payload_with_marker;
641 }
642 } else {
643 option_cursor = self.end;
644 eventual_end = self.end + added_len;
645 }
646
647 self.encoded
648 .tail_mut()
649 .get_mut(option_cursor..option_cursor + encoded.len())
650 .ok_or(WriteError::OutOfSpace)?
651 .copy_from_slice(encoded);
652 let option_cursor = option_cursor + encoded.len();
653 self.encoded
654 .tail_mut()
655 .get_mut(option_cursor..option_cursor + data.len())
656 .ok_or(WriteError::OutOfSpace)?
657 .copy_from_slice(data);
658 self.end = eventual_end;
659
660 Ok(())
661 }
662
663 fn set_payload(&mut self, payload: &[u8]) -> Result<(), WriteError> {
664 if self.payload_start.is_some() {
665 return Err(WriteError::OutOfSequence);
672 }
673 if !payload.is_empty() {
674 *self
675 .encoded
676 .tail_mut()
677 .get_mut(self.end)
678 .ok_or(WriteError::OutOfSpace)? = 0xff;
679 let start = self.end + 1;
680 self.end = start + payload.len();
681 self.encoded
682 .tail_mut()
683 .get_mut(start..self.end)
684 .ok_or(WriteError::OutOfSpace)?
685 .copy_from_slice(payload);
686 self.payload_start = Some(start);
687 }
688 Ok(())
689 }
690
691 #[cfg(feature = "downcast")]
692 fn with_static_type_annotation(
693 &mut self,
694 ) -> Option<coap_message::helpers::RefMutWithStaticType<'_, Self>> {
695 Some(unsafe {
698 coap_message::helpers::RefMutWithStaticType::new(
699 self,
700 core::any::TypeId::of::<Message<'static>>(),
701 )
702 })
703 }
704
705 #[inline]
706 #[allow(refining_impl_trait_reachable)]
707 fn promote_to_mutable_writable_message(&mut self) -> Option<&mut Self> {
708 Some(self)
709 }
710}
711
712impl<EM: EncodedMessage> coap_message::MutableWritableMessage for GenericMessage<EM> {
713 fn available_space(&self) -> usize {
714 self.encoded.tail().len() - self.options_end()
715 }
716
717 fn payload_mut_with_len(&mut self, len: usize) -> Result<&mut [u8], WriteError> {
718 if len == 0 {
719 self.truncate(0)?;
722 return Ok(&mut []);
723 }
724
725 let start = match self.payload_start {
726 None => {
727 self.encoded.tail_mut()[self.end] = 0xff;
728 self.end + 1
729 }
730 Some(payload_start) => payload_start,
731 };
732 let end = start + len;
733
734 let end = end.clamp(0, self.encoded.tail().len());
735
736 self.payload_start = Some(start);
737 self.end = end;
738 self.encoded
739 .tail_mut()
740 .get_mut(start..end)
741 .ok_or(WriteError::OutOfSpace)
742 }
743
744 fn truncate(&mut self, len: usize) -> Result<(), WriteError> {
745 match (len, self.payload_start) {
746 (0, Some(payload_start)) => {
747 self.end = payload_start - 1;
748 self.payload_start = None;
749 }
750 (0, None) => {}
751 (len, Some(payload_start)) if self.end - payload_start >= len => {
752 self.end = payload_start + len;
753 }
754 _ => return Err(WriteError::OutOfSpace),
755 }
756 Ok(())
757 }
758
759 fn mutate_options<F>(&mut self, mut f: F)
760 where
761 F: FnMut(u16, &mut [u8]),
762 {
763 let optend = self.options_end();
767
768 let mut slice = &mut self.encoded.tail_mut()[..optend];
770
771 let mut option_base = 0;
772
773 while !slice.is_empty() {
774 let delta_len = slice[0];
779 slice = &mut slice[1..];
780
781 if delta_len == 0xff {
782 break;
783 }
784
785 let mut delta = u16::from(delta_len) >> 4;
786 let mut len = u16::from(delta_len) & 0x0f;
787
788 let new_len = {
789 #[allow(clippy::redundant_slicing)]
791 let mut readable = &slice[..];
793
794 crate::option_extension::take_extension(&mut delta, &mut readable)
795 .expect("Invalid encoded option in being-written message");
796 crate::option_extension::take_extension(&mut len, &mut readable)
797 .expect("Invalid encoded option in being-written message");
798
799 readable.len()
800 };
801 let trim = slice.len() - new_len;
803 slice = &mut slice[trim..];
804
805 option_base += delta;
806
807 let len = len.into();
808 f(option_base, &mut slice[..len]);
809 slice = &mut slice[len..];
810 }
811 }
812}