use std::convert::TryFrom;
#[derive(Debug)]
pub struct CriticalOptionsRemain { }
use coap_numbers::option;
use coap_message::MessageOption;
pub trait OptionsExt<O: MessageOption>: Iterator<Item=O> {
type IgnoredUriHost: Iterator<Item=O> + Sized;
fn ignore_uri_host(self) -> Self::IgnoredUriHost;
fn ignore_elective_others(self) -> Result<(), CriticalOptionsRemain>;
}
impl<T, O> OptionsExt<O> for T
where
T: Iterator<Item=O>,
O: MessageOption,
{
type IgnoredUriHost = core::iter::Filter<Self, fn(&O) -> bool>;
fn ignore_uri_host(self) -> Self::IgnoredUriHost {
fn keep_option<O: MessageOption>(o: &O) -> bool {
o.number() != option::URI_HOST
}
self.filter(keep_option)
}
fn ignore_elective_others(self) -> Result<(), CriticalOptionsRemain> {
match self
.filter(|o| option::get_criticality(o.number()) == option::Criticality::Critical)
.next()
{
Some(_) => Err(CriticalOptionsRemain { }),
None => Ok(())
}
}
}
pub fn process_uri_path<I, O, F>(iter: I, mut f: F) -> impl Iterator<Item=O>
where
O: MessageOption,
I: Iterator<Item=O>,
F: FnMut(&str),
{
iter.filter(move |o| {
if o.number() == option::URI_PATH {
if let Ok(s) = core::str::from_utf8(o.value()) {
f(s);
return false;
}
}
true
})
}
use coap_message::MinimalWritableMessage;
use coap_message::{OptionNumber, FromOtherOption};
pub trait OptionFeed<O: OptionNumber> {
fn apply_to_message<M: MinimalWritableMessage>(&mut self, message: &mut M) -> Result<(), <<M as MinimalWritableMessage>::OptionNumber as TryFrom<u16>>::Error> {
while self.next_option().is_some() {
self.apply_single_option(message)?;
}
Ok(())
}
fn apply_to_message_limited<M: MinimalWritableMessage>(&mut self, message: &mut M, maxopt: u16) -> Result<(), <<M as MinimalWritableMessage>::OptionNumber as TryFrom<u16>>::Error> {
while self.next_option().map(|next| next <= maxopt) == Some(true) {
self.apply_single_option(message)?;
}
Ok(())
}
fn apply_single_option<M: MinimalWritableMessage>(&mut self, message: &mut M) -> Result<(), <M::OptionNumber as FromOtherOption<O>>::Error>;
fn next_option(&self) -> Option<u16>;
}
use core::marker::PhantomData;
pub struct OptionFeedBuilder<O: OptionNumber, F: OptionFeed<O>>(F, PhantomData<O>);
impl<O: OptionNumber> OptionFeedBuilder<O, NoOptions> {
pub fn new() -> Self {
OptionFeedBuilder(NoOptions, PhantomData)
}
}
impl<O: OptionNumber + Clone, F: OptionFeed<O>> OptionFeedBuilder<O, F> {
pub fn add_option<D: AsRef<[u8]>>(self, number: O, value: D) -> OptionFeedBuilder<O, impl OptionFeed<O>> {
OptionFeedBuilder(Zipper(self.0, OpaqueOption::new(number, value), PhantomData), PhantomData)
}
pub fn add_option_uint<Ux: coap_message::numtraits::Ux>(self, number: O, value: Ux) -> OptionFeedBuilder<O, impl OptionFeed<O>> {
OptionFeedBuilder(Zipper(self.0, UintOption::new(number, value), PhantomData), PhantomData)
}
pub fn finish(self) -> F {
self.0
}
}
pub struct NoOptions;
impl<O: OptionNumber> OptionFeed<O> for NoOptions {
fn apply_single_option<M: MinimalWritableMessage>(&mut self, _message: &mut M) -> Result<(), <M::OptionNumber as FromOtherOption<O>>::Error> {
panic!("Called despite None as next_option")
}
fn next_option(&self) -> Option<u16> {
None
}
}
struct OpaqueOption<O: OptionNumber + Clone, D: AsRef<[u8]>>(Option<(O, D)>);
impl<O: OptionNumber + Clone, D: AsRef<[u8]>> OpaqueOption<O, D> {
fn new(number: O, value: D) -> Self {
OpaqueOption(Some((number, value)))
}
}
impl<O: OptionNumber + Clone, D: AsRef<[u8]>> OptionFeed<O> for OpaqueOption<O, D> {
fn apply_single_option<M: MinimalWritableMessage>(&mut self, message: &mut M) -> Result<(), <M::OptionNumber as FromOtherOption<O>>::Error> {
let (num, val) = self.0.take().expect("Feed exhausted");
let num = M::OptionNumber::convert_from_other(num)?;
message.add_option(num, val.as_ref());
Ok(())
}
fn next_option(&self) -> Option<u16> {
self.0.as_ref().map(|s| s.0.clone().into())
}
}
struct UintOption<O: OptionNumber + Clone, Ux: coap_message::numtraits::Ux>(Option<(O, Ux)>);
impl<O: OptionNumber + Clone, Ux: coap_message::numtraits::Ux> UintOption<O, Ux> {
fn new(number: O, value: Ux) -> Self {
UintOption(Some((number, value)))
}
}
impl<O: OptionNumber + Clone, Ux: coap_message::numtraits::Ux> OptionFeed<O> for UintOption<O, Ux> {
fn apply_single_option<M: MinimalWritableMessage>(&mut self, message: &mut M) -> Result<(), <M::OptionNumber as FromOtherOption<O>>::Error> {
let (num, val) = self.0.take().expect("Feed exhausted");
let num = M::OptionNumber::convert_from_other(num)?;
message.add_option_uint(num, val);
Ok(())
}
fn next_option(&self) -> Option<u16> {
self.0.as_ref().map(|s| s.0.clone().into())
}
}
pub struct Zipper<O: OptionNumber, F1: OptionFeed<O>, F2: OptionFeed<O>>(F1, F2, PhantomData<O>);
impl<O: OptionNumber, F1: OptionFeed<O>, F2: OptionFeed<O>> OptionFeed<O> for Zipper<O, F1, F2> {
fn apply_single_option<M: MinimalWritableMessage>(&mut self, message: &mut M) -> Result<(), <M::OptionNumber as FromOtherOption<O>>::Error> {
match (self.0.next_option(), self.1.next_option()) {
(None, None) => panic!("Out of options"),
(None, Some(_)) => self.1.apply_single_option(message)?,
(Some(_), None) => self.0.apply_single_option(message)?,
(Some(x), Some(y)) if x == y => {
self.0.apply_single_option(message)?;
self.1.apply_single_option(message)?;
}
(Some(x), Some(y)) if x < y => self.0.apply_single_option(message)?,
(Some(_), Some(_)) => self.1.apply_single_option(message)?,
}
Ok(())
}
fn next_option(&self) -> Option<u16> {
match (self.0.next_option(), self.1.next_option()) {
(None, None) => None,
(None, Some(y)) => Some(y),
(Some(x), None) => Some(x),
(Some(x), Some(y)) if x <= y => Some(x),
(Some(_), Some(y)) => Some(y),
}
}
}