coap_message/message.rs
1/// Iteration item for option values
2///
3/// This is the trait of items produced by [`ReadableMessage::options()`].
4///
5/// An implementation needs to allow the user to get the value as a memory slice. This is trivial
6/// for messages that are stored in serialized form; there this can be a fat pointer.
7/// Implementations that store options semantically (eg. as a `struct Block { n: usize, m: bool,
8/// szx: u8 }`) will typically make their MessageOption large enough to contain serialized options,
9/// or heap-allocate for them.
10pub trait MessageOption {
11 /// Numeric option number
12 ///
13 /// See [OptionNumber](crate::OptionNumber) on how to interpret them.
14 fn number(&self) -> u16;
15 /// Obtain the option's raw value
16 ///
17 /// This can be used directly for options with opaque value semantics; for other semantics, see
18 /// the [value_str]() and [value_uint]() helper methods.
19 #[doc(alias = "opaque")]
20 fn value(&self) -> &[u8];
21
22 /// Obtain the option's value as a text string, or None if the option contains invalid UTF-8.
23 ///
24 /// Implementations can override this to reduce the string checking overhead if they already
25 /// have the value as a string internally.
26 #[doc(alias = "string")]
27 fn value_str(&self) -> Option<&str> {
28 core::str::from_utf8(self.value()).ok()
29 }
30
31 /// Obtain the option's value as a number following the `uint` [value
32 /// format](https://tools.ietf.org/html/rfc7252#section-3.2), or None if the option is too
33 /// long for the requested number size.
34 ///
35 /// Implementations can override this to reduce conversion overhead if they already have a
36 /// numeric value internally as soon as U's type is replaced with an equally capable public num
37 /// trait.
38 #[doc(alias = "uint")]
39 fn value_uint<U>(&self) -> Option<U>
40 where
41 U: num_traits::sign::Unsigned + num_traits::ops::bytes::FromBytes,
42 U::Bytes: Sized + Default,
43 {
44 let mut bufarray: U::Bytes = Default::default();
45 let buf = bufarray.as_mut();
46 let buflen = buf.len();
47 let val = self.value();
48 if val.len() > buflen {
49 return None;
50 }
51 buf[buflen - val.len()..].copy_from_slice(val);
52 Some(U::from_be_bytes(&bufarray))
53 }
54}
55
56/// Marker trait that indicates that ReadableMessage::options are produced in ascending
57/// sequence.
58///
59/// This can be set on most CoAP message backends. Examples of backends where it is not implemented
60/// are single-pass reads over in-place decrypted OSCORE messages.
61pub trait WithSortedOptions: ReadableMessage {}
62
63/// A CoAP message whose code, options and payload can be read
64pub trait ReadableMessage {
65 /// See [`Self::code()`]
66 type Code: crate::numbers::Code;
67 /// Type of an individual option, indicating its option number and value
68 type MessageOption<'a>: MessageOption
69 where
70 Self: 'a;
71 /// See [`Self::options()`]
72 type OptionsIter<'a>: Iterator<Item = Self::MessageOption<'a>>
73 where
74 Self: 'a;
75
76 /// Get the code (request method or response code) of the message
77 ///
78 /// See [Code](crate::Code) for its details.
79 fn code(&self) -> Self::Code;
80
81 /// Produce all options in arbitrary order as an iterator
82 ///
83 /// They are sorted if the [`WithSortedOptions`] is implemented as well; implementers should
84 /// set that trait whenever they can.
85 fn options(&self) -> Self::OptionsIter<'_>;
86
87 /// Get the payload set in the message
88 ///
89 /// This is necessarily empty for messages of some codes.
90 fn payload(&self) -> &[u8];
91
92 /// Type ID of Self or a 'static version of Self
93 ///
94 /// This is not useful on its own, and the provided implementation merely returns None.
95 ///
96 /// It can be used by concrete implementations of ReadableMessage that then provide a way to
97 /// downcast a `&impl ReadableMessage` into a a `&Self`. This is only possible for types that
98 /// are either `'static` or covariant over their lifetimes. It is up to the implementations to
99 /// implement that safely.
100 ///
101 /// Using such downcasts is not generally recommended: It breaks the portability that
102 /// using coap-message affords. It may still be useful in two kinds of cases:
103 ///
104 /// * When an implementation specific tool is used deeply within a CoAP handler after using
105 /// generic middleware. Beware that middleware generally does not make any semver promises on
106 /// the types it forwards -- while it may send on the outermost `impl ReadableMessage` type
107 /// as-is to its inner handlers, it may just as well wrap them arbitrarily.
108 ///
109 /// * While exploring the evolution of this crate's traits, these provide an easy hatch.
110 fn with_static_type_annotation(&self) -> Option<crate::helpers::RefWithStaticType<'_, Self>> {
111 None
112 }
113}
114
115// It would be nice to have more type state in here (for headers, last option number and whether
116// payload has been set); this is a first step that can easily wrap jnet and maybe gcoap. Taking
117// the next step is likely to happen soon, given that jnet coap has already moved to type state.
118/// A message that can be written to, creating a CoAP request or response.
119///
120/// This is the bare minimum a message type needs to provide to generic applications. It is up to
121/// the user to ensure this valid sequence of operations:
122///
123/// * Exactly one call to `set_code`
124/// * Any number of calls to `add_option`, with monotonically increasing option numbers
125/// * Zero or one call to `set_payload`
126///
127/// Steps that can reasonably fail at runtime are fallible -- for example, a payload to be set may
128/// simply not fit within the message size. Adding options in the wrong sequence is also an
129/// expected source, eg. when code paths are triggered that were not tested in that combination.
130///
131/// Other errors violating the call sequence, such as failure to call `set_code`, or adding an
132/// option after the payload has been set, may be implemented in a panic. (When occurring in a
133/// fallible operation, the implementation may also choose to report an error instead).
134///
135/// Failed operations may be retried (eg. with shorter values); the failed attempt must not have an
136/// effect on the message.
137///
138/// Implementations may tolerate erroneous call sequences as long as they can produce messages that
139/// are likely to match the caller's expectations -- no need to keep track of usage errors just to
140/// produce correct errors. Users may wrap messages in dedicated checkers for more strictness.
141pub trait MinimalWritableMessage {
142 /// See [`Self::set_code()`]
143 type Code: crate::numbers::Code;
144 /// See [`Self::add_option()`]
145 type OptionNumber: crate::numbers::OptionNumber;
146
147 /// Error returned when an option can not be added (eg. for lack of space, or because an option
148 /// of a higher number or even the payload was already set)
149 type AddOptionError: crate::error::RenderableOnMinimal + core::fmt::Debug;
150 /// Error returned when setting the payload (eg. for lack of space, or when a message of that
151 /// type does not take a payload)
152 type SetPayloadError: crate::error::RenderableOnMinimal + core::fmt::Debug;
153 /// Error type into which either of the other errors, as well as the errors for conversion of
154 /// the `Code` and `OptionNumber`, can be `.into()`ed.
155 ///
156 /// For many implementations it can make sense to use a single error type for all of those, in
157 /// which case the From bounds are trivially fulfilled.
158 type UnionError: crate::error::RenderableOnMinimal
159 + core::fmt::Debug
160 + From<Self::AddOptionError>
161 + From<Self::SetPayloadError>
162 + From<<Self::Code as crate::numbers::Code>::Error>
163 + From<<Self::OptionNumber as crate::numbers::OptionNumber>::Error>;
164
165 /// Set the CoAP code of the message (in a request, that is the request method)
166 fn set_code(&mut self, code: Self::Code);
167
168 /// Add an option to the message
169 ///
170 /// Calls to this method need to happen in ascending numeric sequence.
171 ///
172 /// The option number is pre-encoded in the [Self::OptionNumber] type. The value is provided in
173 /// its serialized form. Under the aspect of [option value
174 /// formats](https://tools.ietf.org/html/rfc7252#section-3.2), this adds opaque options (but
175 /// may just as well be used for adding options in another format when they are pre-encoded).
176 fn add_option(
177 &mut self,
178 number: Self::OptionNumber,
179 value: &[u8],
180 ) -> Result<(), Self::AddOptionError>;
181
182 /// Set the payload to the message
183 ///
184 /// This must be called only once.
185 fn set_payload(&mut self, data: &[u8]) -> Result<(), Self::SetPayloadError>;
186
187 /// Copy code, options and payload in from a readable message
188 // While this was originally intended for overriding for better optimization, that can only be
189 // done with specialization, which will likely require a breaking change.
190 fn set_from_message<M>(&mut self, msg: &M) -> Result<(), Self::UnionError>
191 where
192 M: ReadableMessage + WithSortedOptions,
193 {
194 use crate::numbers::{Code, OptionNumber};
195
196 self.set_code(Self::Code::new(msg.code().into())?);
197
198 for opt in msg.options() {
199 self.add_option(Self::OptionNumber::new(opt.number())?, opt.value())?;
200 }
201 self.set_payload(msg.payload())?;
202 Ok(())
203 }
204
205 /// Shortcut for `add_option(self, number, value.as_bytes())`.
206 ///
207 /// Implementations with type checked options can provide more efficient implementations (ie.
208 /// ones that don't need to UTF-8-check when they feed the resulting bytes back into a string
209 /// field), but must still accept string options via the generic
210 /// [`add_option()`](Self::add_option) method.
211 fn add_option_str(
212 &mut self,
213 number: Self::OptionNumber,
214 value: &str,
215 ) -> Result<(), Self::AddOptionError> {
216 self.add_option(number, value.as_bytes())
217 }
218
219 /// Shortcut for `add_option` on a buffer containing the uint encoded value
220 ///
221 /// Implementations with type checked options can provide more efficient implementations (ie.
222 /// ones that don't need to decode the uint when reading it into a uint field), but must still
223 /// accept integer options via the generic [`add_option()`](Self::add_option) method.
224 fn add_option_uint<U: num_traits::sign::Unsigned + num_traits::ops::bytes::ToBytes>(
225 &mut self,
226 number: Self::OptionNumber,
227 value: U,
228 ) -> Result<(), Self::AddOptionError> {
229 let value = value.to_be_bytes();
230 let mut value = value.as_ref();
231 while let Some(&0) = value.first() {
232 value = &value[1..];
233 }
234 self.add_option(number, value)
235 }
236
237 /// Type ID of Self or a 'static version of Self
238 ///
239 /// This is not useful on its own, and the provided implementation merely returns None.
240 ///
241 /// It can be used by concrete implementations of MinimalWritableMessage that then provide a
242 /// way to downcast a `&mut impl MinimalWritableMessage` into a a `&mut Self`. This is only
243 /// possible for types that are either `'static` or covariant over their lifetimes. It is up to
244 /// the implementations to implement that safely.
245 ///
246 /// Using such downcasts is not generally recommended: It breaks the portability that
247 /// using coap-message affords. It may still be useful in two kinds of cases:
248 ///
249 /// * When an implementation specific tool is used deeply within a CoAP handler after using
250 /// generic middleware. Beware that middleware generally does not make any semver promises on
251 /// the types it forwards -- while it may send on the outermost `impl MinimalWritableMessage`
252 /// type as-is to its inner handlers, it may just as well wrap them arbitrarily.
253 ///
254 /// * While exploring the evolution of this crate's traits, these provide an easy hatch.
255 fn with_static_type_annotation(
256 &mut self,
257 ) -> Option<crate::helpers::RefMutWithStaticType<'_, Self>> {
258 None
259 }
260
261 /// Tries to obtain a [MutableWritableMessage] from self.
262 ///
263 /// This is used where a tool writing to a message might perform better (use fewer local
264 /// resources) or can provide a higher quality representation if the advanced writability
265 /// features are present.
266 ///
267 /// ## Implementation guidance
268 ///
269 /// If possible, the typical implementation is `Some(self)`. It is recommended to `#[inline]`
270 /// it (so that the branches for a None case are not even emitted).
271 ///
272 /// It makes a lot of sense to specify the return value as `Option<&mut Self>`. An
273 /// `#[allow(refining_impl_trait_reachable)]` acknowledges that this constrains the
274 /// implementation's future development, but given that the return type will also implement
275 /// `MinimalWritableMessage` as part of the trait hierarchy, chances are that that will always
276 /// be the return type in any given library.
277 ///
278 /// ## Future development
279 ///
280 /// As soon as trait methods can be const, this one should be. With that, it would be an option
281 /// to simplify the Handler interface to take a MinimalWritableMessage, and for the handlers
282 /// that need it to `const { message.promote_to_mutable_writable_message().expect("Handler XY
283 /// needs mutable messages") }` for compile time errors on non-matching handlers.
284 ///
285 /// It was considered whether using a `Result<impl MutableWritableMessage<...>, impl Any>`
286 /// would bring any benefits. Given that there is no way known to the author to create a const
287 /// panic based on whether or not a type is inhabited, let's wait for const trait methods
288 /// (which will bring an API change anyway), and rely on inlining and dead code elimination for
289 /// the time being.
290 #[inline]
291 #[allow(
292 clippy::type_complexity,
293 // reason = "can't avoid complexity when forwarding" // commented due to MSRV
294 )]
295 fn promote_to_mutable_writable_message(
296 &mut self,
297 ) -> Option<
298 &mut impl MutableWritableMessage<
299 Code = Self::Code,
300 OptionNumber = Self::OptionNumber,
301 AddOptionError = Self::AddOptionError,
302 SetPayloadError = Self::SetPayloadError,
303 UnionError = Self::UnionError,
304 >,
305 > {
306 None::<
307 &mut ImpossibleMessage<
308 Self::Code,
309 Self::OptionNumber,
310 Self::AddOptionError,
311 Self::SetPayloadError,
312 Self::UnionError,
313 >,
314 >
315 }
316
317 /// Auxiliary function for converting `Self::Code::Error`
318 ///
319 /// This should really not be needed, but serves well in allowing coap-request-imlementations
320 /// to convert errors found during writing into their RequestUnionError that can be returned.
321 fn convert_code_error(e: <Self::Code as crate::numbers::Code>::Error) -> Self::UnionError {
322 Self::UnionError::from(e)
323 }
324 /// Auxiliary function for converting `Self::OptionNumber::Error`
325 ///
326 /// This should really not be needed, but serves well in allowing coap-request-imlementations
327 /// to convert errors found during writing into their RequestUnionError that can be returned.
328 fn convert_option_number_error(
329 e: <Self::OptionNumber as crate::numbers::OptionNumber>::Error,
330 ) -> Self::UnionError {
331 Self::UnionError::from(e)
332 }
333 /// Auxiliary function for converting [`Self::AddOptionError`]
334 ///
335 /// This should really not be needed, but serves well in allowing coap-request-imlementations
336 /// to convert errors found during writing into their RequestUnionError that can be returned.
337 fn convert_add_option_error(e: Self::AddOptionError) -> Self::UnionError {
338 Self::UnionError::from(e)
339 }
340 /// Auxiliary function for converting [`Self::SetPayloadError`]
341 ///
342 /// This should really not be needed, but serves well in allowing coap-request-imlementations
343 /// to convert errors found during writing into their RequestUnionError that can be returned.
344 fn convert_set_payload_error(e: Self::SetPayloadError) -> Self::UnionError {
345 Self::UnionError::from(e)
346 }
347}
348
349/// A message that allows later manipulation of a once set payload, and later truncation.
350///
351/// This is a bit of an unsorted bag that needs further cleanup (FIXME) -- most of this is
352/// motivated by block-wise and write-in-place. Might need a bit of reshape, possibly following the
353/// [Rust RFC 2884](https://github.com/rust-lang/rfcs/pull/2884).
354///
355/// The available_space is mainly needed for applications that want to use up the last byte by not
356/// zero-padding the Block2 option to its szx=0 equivalent.
357///
358/// Can that be efficiently be replaced with something like this, and can it be optimized down to
359/// the hand-written counting-of-option-bytes that's involved in the use of available_space?
360///
361/// ```ignore
362/// let mut m = allocated_message;
363/// for szx in 6..0 {
364/// snap = m.snapshot();
365/// m.add_option(BLOCK2, ...);
366/// m.add_option(..., ...);
367///
368/// if let Ok(_) = m.write_payload(|p| {
369/// if (p.len() < 1 << (4 + szx)) {
370/// return Err(());
371/// }
372///
373/// let written = write_block(...);
374///
375/// Ok(written)
376/// }) {
377/// break;
378/// } else {
379/// m = m.revert_to(snap);
380/// }
381/// } else {
382/// panic!("Allocated space doesn't even suffice for 16 byte payload");
383/// }
384/// ```
385///
386pub trait MutableWritableMessage: MinimalWritableMessage {
387 /// Number of bytes available for additional options, payload marker and payload
388 fn available_space(&self) -> usize;
389
390 /// Memory-map `len` bytes of the payload for writing
391 ///
392 /// If a payload has been set previously, that payload will be available in the slice; in that
393 /// case, the caller must make sure to not exceed its length.
394 ///
395 /// If no payload has been set previously, and the requested length exceeds the available
396 /// buffer space, the longest possible payload should be mapped.
397 fn payload_mut_with_len(&mut self, len: usize) -> Result<&mut [u8], Self::SetPayloadError>;
398
399 /// Truncate an already-set payload to the given length; that payload must have been written to
400 /// before using [`MinimalWritableMessage::set_payload`], or with a suitable [`MutableWritableMessage::payload_mut_with_len`] call.
401 fn truncate(&mut self, len: usize) -> Result<(), Self::SetPayloadError>;
402
403 /// Apply a callback to all options in sequence
404 ///
405 /// This is a possibly inefficient but generic way achieve "allocate first, set when done"
406 /// pattern typically found for options like ETag.
407 fn mutate_options<F>(&mut self, callback: F)
408 where
409 F: FnMut(Self::OptionNumber, &mut [u8]);
410}
411
412/// Uninhabited type to satisfy the type constraints of the default None implementation of
413/// `.promote_to_mutable_writable_message`.
414///
415/// That's a *lot* of text just to say "it can't happen anyway".
416struct ImpossibleMessage<Code, OptionNumber, AddOptionError, SetPayloadError, UnionError> {
417 _phantom: core::marker::PhantomData<(
418 Code,
419 OptionNumber,
420 AddOptionError,
421 SetPayloadError,
422 UnionError,
423 )>,
424 _never: core::convert::Infallible,
425}
426
427impl<
428 Code: TryFrom<u8> + crate::numbers::Code + Into<u8>,
429 OptionNumber: TryFrom<u16> + crate::numbers::OptionNumber + Into<u16>,
430 AddOptionError: core::fmt::Debug + crate::error::RenderableOnMinimal,
431 SetPayloadError: core::fmt::Debug + crate::error::RenderableOnMinimal,
432 UnionError: core::fmt::Debug
433 + crate::error::RenderableOnMinimal
434 + core::convert::From<AddOptionError>
435 + core::convert::From<SetPayloadError>
436 + From<<Code as crate::numbers::Code>::Error>
437 + From<<OptionNumber as crate::numbers::OptionNumber>::Error>,
438 > MinimalWritableMessage
439 for ImpossibleMessage<Code, OptionNumber, AddOptionError, SetPayloadError, UnionError>
440{
441 type Code = Code;
442 type OptionNumber = OptionNumber;
443
444 type AddOptionError = AddOptionError;
445 type SetPayloadError = SetPayloadError;
446 type UnionError = UnionError;
447
448 fn set_code(&mut self, _code: Self::Code) {
449 match self._never {}
450 }
451
452 fn add_option(
453 &mut self,
454 _number: Self::OptionNumber,
455 _value: &[u8],
456 ) -> Result<(), Self::AddOptionError> {
457 match self._never {}
458 }
459
460 fn set_payload(&mut self, _data: &[u8]) -> Result<(), Self::SetPayloadError> {
461 match self._never {}
462 }
463}
464impl<
465 Code: TryFrom<u8> + crate::numbers::Code + Into<u8>,
466 OptionNumber: TryFrom<u16> + crate::numbers::OptionNumber + Into<u16>,
467 AddOptionError: core::fmt::Debug + crate::error::RenderableOnMinimal,
468 SetPayloadError: core::fmt::Debug + crate::error::RenderableOnMinimal,
469 UnionError: core::fmt::Debug
470 + crate::error::RenderableOnMinimal
471 + core::convert::From<AddOptionError>
472 + core::convert::From<SetPayloadError>
473 + From<<Code as crate::numbers::Code>::Error>
474 + From<<OptionNumber as crate::numbers::OptionNumber>::Error>,
475 > MutableWritableMessage
476 for ImpossibleMessage<Code, OptionNumber, AddOptionError, SetPayloadError, UnionError>
477{
478 fn available_space(&self) -> usize {
479 match self._never {}
480 }
481
482 fn payload_mut_with_len(&mut self, _len: usize) -> Result<&mut [u8], Self::SetPayloadError> {
483 match self._never {}
484 }
485
486 fn truncate(&mut self, _len: usize) -> Result<(), Self::SetPayloadError> {
487 match self._never {}
488 }
489
490 fn mutate_options<F>(&mut self, _callback: F)
491 where
492 F: FnMut(Self::OptionNumber, &mut [u8]),
493 {
494 match self._never {}
495 }
496}
497
498/// Marker trait that relaxes [MinimalWritableMessage]'s sequence requirements.
499///
500/// This indicates that the sequence of calling [`set_code()`](MinimalWritableMessage::set_code),
501/// [`add_option()`](MinimalWritableMessage::add_option) and
502/// [`set_payload()`](MinimalWritableMessage::set_payload) is not fixed. The sequence of calls only
503/// has meaning in that later `set_code()` and `set_payload()` calls override earlier ones, and
504/// that `add_option()` on the same option number are stored in their sequence of addition.
505// FIXME: Look into whether there's any implementation where it'd make sense to only have some of
506// the relaxation but not all (eg. all options must be out, then comes the code).
507pub trait SeekWritableMessage {
508 // FIXME: Provide a more generic set_from_message that does not demand
509 // WithSortedOptions. It can even have just the same code.
510}