diff --git a/Cargo.lock b/Cargo.lock index 9fd78c5c..c3b69caf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1032,7 +1032,7 @@ dependencies = [ [[package]] name = "toad-msg" -version = "0.8.13" +version = "0.9.0" dependencies = [ "arrayvec", "blake2", diff --git a/toad-msg/src/msg/id.rs b/toad-msg/src/msg/id.rs index 5fe8d6fe..12bede37 100644 --- a/toad-msg/src/msg/id.rs +++ b/toad-msg/src/msg/id.rs @@ -2,6 +2,8 @@ use toad_common::Cursor; use super::MessageParseError; use crate::from_bytes::TryConsumeBytes; +#[allow(unused_imports)] +use crate::Token; /// # Message ID /// diff --git a/toad-msg/src/msg/mod.rs b/toad-msg/src/msg/mod.rs index 1c259c94..3065987e 100644 --- a/toad-msg/src/msg/mod.rs +++ b/toad-msg/src/msg/mod.rs @@ -1,6 +1,9 @@ use toad_common::{AppendCopy, Array, Cursor, GetSize}; use toad_macros::rfc_7252_doc; +#[allow(unused_imports)] +use crate::TryIntoBytes; + /// Message Code pub mod code; @@ -249,7 +252,7 @@ impl + AppendCopy, Options: OptionMap> /// Get the value(s) of an option by number /// - /// This just invokes [`Map::get`] on [`Message.opts`]. + /// This just invokes [`toad_common::Map::get`] on [`Message.opts`]. pub fn get(&self, n: OptNumber) -> Option<&Options::OptValues> { self.opts.get(&n) } diff --git a/toad-msg/src/msg/opt/known.rs b/toad-msg/src/msg/opt/known.rs new file mode 100644 index 00000000..18d05231 --- /dev/null +++ b/toad-msg/src/msg/opt/known.rs @@ -0,0 +1,57 @@ +/// Content-Format values +pub mod content_format; + +macro_rules! opt { + (rfc7252($section:literal) $name:ident = $n:literal) => { + #[doc = ::toad_macros::rfc_7252_doc!($section)] + #[allow(clippy::zero_prefixed_literal)] + pub const $name: crate::OptNumber = crate::OptNumber($n); + }; + (#[doc = $doc:expr] $name:ident = $n:literal) => { + #[doc = $doc] + #[allow(clippy::zero_prefixed_literal)] + pub const $name: crate::OptNumber = crate::OptNumber($n); + }; +} + +pub(crate) use opt; + +/// Non-repeatable options +pub mod no_repeat { + use super::opt; + + opt!(rfc7252("5.10.1") HOST = 3); + opt!(rfc7252("5.10.8.2") IF_NONE_MATCH = 5); + opt!(#[doc = "See [`HOST`]"] + PORT = 7); + opt!(#[doc = "See [`HOST`]"] + PATH = 11); + opt!(rfc7252("5.10.3") CONTENT_FORMAT = 12); + opt!(rfc7252("5.10.5") MAX_AGE = 14); + opt!(rfc7252("5.10.4") ACCEPT = 17); + opt!(rfc7252("5.10.2") PROXY_URI = 35); + opt!(#[doc = "See [`PROXY_URI`]"] + PROXY_SCHEME = 39); + opt!(rfc7252("5.10.9") SIZE1 = 60); +} + +/// Repeatable options +pub mod repeat { + use super::opt; + + opt!(rfc7252("5.10.8.1") IF_MATCH = 1); + opt!(rfc7252("5.10.7") LOCATION_PATH = 8); + opt!(#[doc = "See [`super::no_repeat::HOST`]"] + QUERY = 11); + opt!(#[doc = "See [`LOCATION_PATH`]"] + LOCATION_QUERY = 20); + opt!(#[doc = concat!( + toad_macros::rfc_7252_doc!("5.10.6"), + "\n
ETag as a Request Option\n\n", + toad_macros::rfc_7252_doc!("5.10.6.2"), + "\n
ETag as a Response Option\n\n", + toad_macros::rfc_7252_doc!("5.10.6.1"), + "
" + )] + ETAG = 4); +} diff --git a/toad-msg/src/msg/opt/known/content_format.rs b/toad-msg/src/msg/opt/known/content_format.rs new file mode 100644 index 00000000..dce37990 --- /dev/null +++ b/toad-msg/src/msg/opt/known/content_format.rs @@ -0,0 +1,51 @@ +/// Content-Format +#[non_exhaustive] +#[derive(Debug, Clone, Copy)] +pub enum ContentFormat { + /// `text/plain; charset=utf-8` + Text, + /// `application/link-format` + LinkFormat, + /// `application/xml` + Xml, + /// `application/octet-stream` + OctetStream, + /// `application/exi` + Exi, + /// `application/json` + Json, + /// Another content format + Other(u16), +} + +impl ContentFormat { + /// Convert this content format to the CoAP byte value + pub fn bytes(&self) -> [u8; 2] { + u16::from(self).to_be_bytes() + } +} + +impl<'a> From<&'a ContentFormat> for u16 { + fn from(f: &'a ContentFormat) -> Self { + use ContentFormat::*; + match *f { + | Text => 0, + | LinkFormat => 40, + | Xml => 41, + | OctetStream => 42, + | Exi => 47, + | Json => 50, + | Other(n) => n, + } + } +} + +impl<'a> IntoIterator for &'a ContentFormat { + type Item = u8; + + type IntoIter = <[u8; 2] as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.bytes().into_iter() + } +} diff --git a/toad-msg/src/msg/opt/mod.rs b/toad-msg/src/msg/opt/mod.rs index be51d438..2f22c9a8 100644 --- a/toad-msg/src/msg/opt/mod.rs +++ b/toad-msg/src/msg/opt/mod.rs @@ -14,7 +14,11 @@ use crate::from_bytes::*; pub mod parse_error; pub use parse_error::*; -/// Implementor of [`IterOpts`] +/// Well-known options +pub mod known; +pub use known::*; + +/// An iterator over owned [`Opt`]s #[derive(Debug, Clone)] pub struct OptIter where M: OptionMap @@ -25,7 +29,7 @@ pub struct OptIter __p: PhantomData, } -/// Implementor of [`IterOptRefs`] +/// An iterator over [`OptRef`]s #[derive(Debug, Clone)] pub struct OptRefIter<'a, M, I> where M: OptionMap @@ -365,14 +369,14 @@ pub enum WhenOptionUnsupportedByProxy { #[doc = rfc_7252_doc!("5.4.2")] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum WhenOptionChanges { - /// If this option is [safe to forward](`ProxySafe::ForwardWhenUnknown`), + /// If this option is [safe to forward](`WhenOptionUnsupportedByProxy::Forward`), /// but unknown to a proxy, it should be included in the proxy's /// cache key for this message. /// /// Corresponds to the option being not "NoCacheKey" /// in strict CoAP terms ResponseChanges, - /// If this option is [safe to forward](`ProxySafe::ForwardWhenUnknown`), + /// If this option is [safe to forward](`WhenOptionUnsupportedByProxy::Forward`), /// but unknown to a proxy, it should not be included in the proxy's /// cache key for this message, and different values for this option /// should yield the cached response. diff --git a/toad-msg/src/msg/parse_error.rs b/toad-msg/src/msg/parse_error.rs index 9ca06d7c..2955ed3a 100644 --- a/toad-msg/src/msg/parse_error.rs +++ b/toad-msg/src/msg/parse_error.rs @@ -1,3 +1,6 @@ +#[allow(unused_imports)] +use crate::Type; + /// Errors encounterable while parsing a message from bytes #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)] pub enum MessageParseError {