coap-handler 0.2.1

Interface to CoAP handlers
Documentation
//! Traits to implement a .well-known/core resource easily
//!
//! This tries to be future-proof for building also CoRAL responses, without going out of its way
//! for that.

/// A property an advertised resource can have many of.
///
/// This corresponds to target attributes in Link Format, and also to properties in CoRAL without
/// being very final yet.
///
/// This is a single type with static string out-references, but likely to be generalized later
/// into a trait (but right now it's insufficiently known what it'll need to produce).
#[non_exhaustive]
#[derive(Copy, Clone)]
pub enum Attribute {
    Observable,
    Interface(&'static str),
    ResourceType(&'static str),
    Title(&'static str),
    Ct(u16), // Single only -- array could be added in an own option
    Sz(usize),
    /// An arbitrary value rendered verbatim into an Link Format document (between `;` or `,`
    /// depending on its position).
    ///
    /// It is preferred to emit attributes explicitly: This both supports any non-RFC6690 outputs
    /// that can work from that more easily, and dynamic data.
    Other(&'static str),
}

impl Attribute {
    /// Serializes the attribute into RFC6690 Link Format.
    ///
    /// Any attribute that can be serialized (currently and expectedly: all) produces a single
    /// semicolon (`;`) followed by some key and possibly an equals sign (`=`) and a (possibly
    /// quoted) value.
    pub fn write_link_format(&self, w: &mut impl core::fmt::Write) -> core::fmt::Result {
        match self {
            Attribute::Observable => write!(w, ";obs")?,
            Attribute::ResourceType(s) => write!(w, ";rt=\"{s}\"")?,
            Attribute::Interface(s) => write!(w, ";if=\"{s}\"")?,
            Attribute::Title(s) => write!(w, ";title=\"{s}\"")?,
            Attribute::Ct(s) => write!(w, ";ct={s}")?,
            Attribute::Sz(s) => write!(w, ";sz={s}")?,
            Attribute::Other(s) => write!(w, ";{s}")?,
        }
        Ok(())
    }
}

/// A entry produced by Reporting, corresponding to a single link in a Link Format file.
pub trait Record {
    type PathElement: AsRef<str>;
    type PathElements: Iterator<Item = Self::PathElement>;
    type Attributes: Iterator<Item = Attribute>;

    /// List of path segments (equivalent to Uri-Path option values) leading to the indicated
    /// resoruce
    fn path(&self) -> Self::PathElements;

    /// Link relation (or None to default to the implicit "hosts")
    ///
    /// Note that the allowed character set is limited compared to full UTF-8 strings.
    fn rel(&self) -> Option<&str>;

    /// Target attributes of the link
    fn attributes(&self) -> Self::Attributes;
}

/// Indicates that this resource can produce output for a .well-known/core resource.
///
/// Several trivial implementations ([NotReporting] for resources that should not show in
/// .well-known/core, [ConstantSingleRecordReport] for resources with one static record) are
/// available that cover most scenarios in which a custom [Handler](crate::Handler) is implemented.
///
/// [NotReporting]: https://docs.rs/coap-handler-implementations/0.3.5/coap_handler_implementations/wkc/struct.NotReporting.html
/// [ConstantSingleRecordReport]: https://docs.rs/coap-handler-implementations/0.3.5/coap_handler_implementations/wkc/struct.ConstantSingleRecordReport.html
pub trait Reporting {
    type Record<'res>: Record
    where
        Self: 'res;
    type Reporter<'res>: Iterator<Item = Self::Record<'res>>
    where
        Self: 'res;

    fn report(&self) -> Self::Reporter<'_>;

    /// Writes additional lines into an output RFC6690 Link Format document
    ///
    /// This output is appended to any records produced.
    ///
    /// The `is_first` argument assists both parties in coordination of the `,` delimiter: Unless
    /// `is_first=true`, this writer needs to prefix its output with a `,` (comma) character, and
    /// if it produces any output, it sets `*is_first=false`.
    #[inline]
    #[allow(unused_variables, reason = "Names are part of user interface")]
    fn write_extra_link_format(
        &self,
        writer: &mut impl core::fmt::Write,
        is_first: &mut bool,
    ) -> core::fmt::Result {
        Ok(())
    }
}