coap_message

Trait MinimalWritableMessage

Source
pub trait MinimalWritableMessage {
    type Code: Code;
    type OptionNumber: OptionNumber;
    type AddOptionError: RenderableOnMinimal + Debug;
    type SetPayloadError: RenderableOnMinimal + Debug;
    type UnionError: RenderableOnMinimal + Debug + From<Self::AddOptionError> + From<Self::SetPayloadError> + From<<Self::Code as Code>::Error> + From<<Self::OptionNumber as OptionNumber>::Error>;

    // Required methods
    fn set_code(&mut self, code: Self::Code);
    fn add_option(
        &mut self,
        number: Self::OptionNumber,
        value: &[u8],
    ) -> Result<(), Self::AddOptionError>;
    fn set_payload(&mut self, data: &[u8]) -> Result<(), Self::SetPayloadError>;

    // Provided methods
    fn set_from_message<M>(&mut self, msg: &M) -> Result<(), Self::UnionError>
       where M: ReadableMessage + WithSortedOptions { ... }
    fn add_option_str(
        &mut self,
        number: Self::OptionNumber,
        value: &str,
    ) -> Result<(), Self::AddOptionError> { ... }
    fn add_option_uint<U: Unsigned + ToBytes>(
        &mut self,
        number: Self::OptionNumber,
        value: U,
    ) -> Result<(), Self::AddOptionError> { ... }
    fn with_static_type_annotation(
        &mut self,
    ) -> Option<RefMutWithStaticType<'_, Self>> { ... }
    fn promote_to_mutable_writable_message(
        &mut self,
    ) -> Option<&mut (impl MinimalWritableMessage<Code = Self::Code, OptionNumber = Self::OptionNumber, AddOptionError = Self::AddOptionError, SetPayloadError = Self::SetPayloadError, UnionError = Self::UnionError> + MutableWritableMessage)> { ... }
    fn convert_code_error(e: <Self::Code as Code>::Error) -> Self::UnionError { ... }
    fn convert_option_number_error(
        e: <Self::OptionNumber as OptionNumber>::Error,
    ) -> Self::UnionError { ... }
    fn convert_add_option_error(e: Self::AddOptionError) -> Self::UnionError { ... }
    fn convert_set_payload_error(e: Self::SetPayloadError) -> Self::UnionError { ... }
}
Expand description

A message that can be written to, creating a CoAP request or response.

This is the bare minimum a message type needs to provide to generic applications. It is up to the user to ensure this valid sequence of operations:

  • Exactly one call to set_code
  • Any number of calls to add_option, with monotonically increasing option numbers
  • Zero or one call to set_payload

Steps that can reasonably fail at runtime are fallible – for example, a payload to be set may simply not fit within the message size. Adding options in the wrong sequence is also an expected source, eg. when code paths are triggered that were not tested in that combination.

Other errors violating the call sequence, such as failure to call set_code, or adding an option after the payload has been set, may be implemented in a panic. (When occurring in a fallible operation, the implementation may also choose to report an error instead).

Failed operations may be retried (eg. with shorter values); the failed attempt must not have an effect on the message.

Implementations may tolerate erroneous call sequences as long as they can produce messages that are likely to match the caller’s expectations – no need to keep track of usage errors just to produce correct errors. Users may wrap messages in dedicated checkers for more strictness.

Required Associated Types§

Source

type Code: Code

Source

type OptionNumber: OptionNumber

Source

type AddOptionError: RenderableOnMinimal + Debug

Error returned when an option can not be added (eg. for lack of space, or because an option of a higher number or even the payload was already set)

Source

type SetPayloadError: RenderableOnMinimal + Debug

Error returned when setting the payload (eg. for lack of space, or when a message of that type does not take a payload)

Source

type UnionError: RenderableOnMinimal + Debug + From<Self::AddOptionError> + From<Self::SetPayloadError> + From<<Self::Code as Code>::Error> + From<<Self::OptionNumber as OptionNumber>::Error>

Error type into which either of the other errors, as well as the errors for conversion of the Code and OptionNumber, can be .into()ed.

For many implementations it can make sense to use a single error type for all of those, in which case the From bounds are trivially fulfilled.

Required Methods§

Source

fn set_code(&mut self, code: Self::Code)

Set the CoAP code of the message (in a request, that is the request method)

Source

fn add_option( &mut self, number: Self::OptionNumber, value: &[u8], ) -> Result<(), Self::AddOptionError>

Add an option to the message

Calls to this method need to happen in ascending numeric sequence.

The option number is pre-encoded in the Self::OptionNumber type. The value is provided in its serialized form. Under the aspect of option value formats, this adds opaque options (but may just as well be used for adding options in another format when they are pre-encoded).

Source

fn set_payload(&mut self, data: &[u8]) -> Result<(), Self::SetPayloadError>

Set the payload to the message

This must be called only once.

Provided Methods§

Source

fn set_from_message<M>(&mut self, msg: &M) -> Result<(), Self::UnionError>

Copy code, options and payload in from a readable message

Source

fn add_option_str( &mut self, number: Self::OptionNumber, value: &str, ) -> Result<(), Self::AddOptionError>

Shortcut for add_option(self, number, value.as_bytes()).

Implementations with type checked options can provide more efficient implementations (ie. ones that don’t need to UTF-8-check when they feed the resulting bytes back into a string field), but must still accept string options via the generic add_option() method.

Source

fn add_option_uint<U: Unsigned + ToBytes>( &mut self, number: Self::OptionNumber, value: U, ) -> Result<(), Self::AddOptionError>

Shortcut for add_option on a buffer containing the uint encoded value

Implementations with type checked options can provide more efficient implementations (ie. ones that don’t need to decode the uint when reading it into a uint field), but must still accept integer options via the generic add_option() method.

Source

fn with_static_type_annotation( &mut self, ) -> Option<RefMutWithStaticType<'_, Self>>

Type ID of Self or a ’static version of Self

This is not useful on its own, and the provided implementation merely returns None.

It can be used by concrete implementations of MinimalWritableMessage that then provide a way to downcast a &mut impl MinimalWritableMessage into a a &mut Self. This is only possible for types that are either 'static or covariant over their lifetimes. It is up to the implementations to implement that safely.

Using such downcasts is not generally recommended: It breaks the portability that using coap-message affords. It may still be useful in two kinds of cases:

  • When an implementation specific tool is used deeply within a CoAP handler after using generic middleware. Beware that middleware generally does not make any semver promises on the types it forwards – while it may send on the outermost impl MinimalWritableMessage type as-is to its inner handlers, it may just as well wrap them arbitrarily.

  • While exploring the evolution of this crate’s traits, these provide an easy hatch.

Source

fn promote_to_mutable_writable_message( &mut self, ) -> Option<&mut (impl MinimalWritableMessage<Code = Self::Code, OptionNumber = Self::OptionNumber, AddOptionError = Self::AddOptionError, SetPayloadError = Self::SetPayloadError, UnionError = Self::UnionError> + MutableWritableMessage)>

Tries to obtain a MutableWritableMessage from self.

This is used where a tool writing to a message might perform better (use fewer local resources) or can provide a higher quality representation if the advanced writability features are present.

§Implementation guidance

If possible, the typical implementation is Some(self). It is recommended to #[inline] it (so that the branches for a None case are not even emitted).

It makes a lot of sense to specify the return value as Option<&mut Self>. An #[allow(refining_impl_trait_reachable)] acknowledges that this constrains the implementation’s future development, but given that the return type will also implement MinimalWritableMessage as part of the trait hierarchy, chances are that that will always be the return type in any given library.

§Future development

As soon as trait methods can be const, this one should be. With that, it would be an option to simplify the Handler interface to take a MinimalWritableMessage, and for the handlers that need it to const { message.promote_to_mutable_writable_message().expect("Handler XY needs mutable messages") } for compile time errors on non-matching handlers.

It was considered whether using a Result<impl MutableWritableMessage<...>, impl Any> would bring any benefits. Given that there is no way known to the author to create a const panic based on whether or not a type is inhabited, let’s wait for const trait methods (which will bring an API change anyway), and rely on inlining and dead code elimination for the time being.

Source

fn convert_code_error(e: <Self::Code as Code>::Error) -> Self::UnionError

Auxiliary function for converting Self::Code::Error

This should really not be needed, but serves well in allowing coap-request-imlementations to convert errors found during writing into their RequestUnionError that can be returned.

Source

fn convert_option_number_error( e: <Self::OptionNumber as OptionNumber>::Error, ) -> Self::UnionError

Auxiliary function for converting Self::OptionNumber::Error

This should really not be needed, but serves well in allowing coap-request-imlementations to convert errors found during writing into their RequestUnionError that can be returned.

Source

fn convert_add_option_error(e: Self::AddOptionError) -> Self::UnionError

Auxiliary function for converting Self::AddOptionError

This should really not be needed, but serves well in allowing coap-request-imlementations to convert errors found during writing into their RequestUnionError that can be returned.

Source

fn convert_set_payload_error(e: Self::SetPayloadError) -> Self::UnionError

Auxiliary function for converting Self::SetPayloadError

This should really not be needed, but serves well in allowing coap-request-imlementations to convert errors found during writing into their RequestUnionError that can be returned.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§