use crate::helpers::Block2RequestData;
use coap_message::MessageOption;
use coap_numbers::option;
#[derive(Debug)]
pub struct CriticalOptionsRemain(());
pub trait OptionsExt<O: MessageOption>: Iterator<Item = O> {
type IgnoredUriHost: Iterator<Item = O> + Sized;
fn ignore_uri_host(self) -> Self::IgnoredUriHost;
type IgnoredUriQuery: Iterator<Item = O> + Sized;
fn ignore_uri_query(self) -> Self::IgnoredUriQuery;
fn ignore_elective_others(self) -> Result<(), CriticalOptionsRemain>;
type WithoutBlock2<'a>: Iterator<Item = O>;
fn take_block2(self, out: &mut Option<Block2RequestData>) -> Self::WithoutBlock2<'_>;
type WithoutUriPath<'a, F: FnMut(&str)>: Iterator<Item = O>;
fn take_uri_path<'a, F: FnMut(&str)>(self, f: F) -> Self::WithoutUriPath<'a, F>;
}
#[cfg(not(feature = "nontrivial_option_processing"))]
mod aux {
use super::*;
pub struct BlockPusher<'a, O: MessageOption, I: Iterator<Item = O>> {
pub(super) instream: I,
pub(super) out: &'a mut Option<Block2RequestData>,
}
impl<'a, O: MessageOption, I: Iterator<Item = O>> Iterator for BlockPusher<'a, O, I> {
type Item = O;
fn next(&mut self) -> Option<O> {
while let Some(o) = self.instream.next() {
if matches!(o.number(), option::BLOCK2) && self.out.is_none() {
if let Ok(o) = Block2RequestData::from_option(&o) {
*self.out = Some(o);
continue;
}
}
return Some(o);
}
None
}
}
pub struct UriPusher<O: MessageOption, I: Iterator<Item = O>, F: FnMut(&str)> {
pub(super) instream: I,
pub(super) f: F,
}
impl<O: MessageOption, I: Iterator<Item = O>, F: FnMut(&str)> Iterator for UriPusher<O, I, F> {
type Item = O;
fn next(&mut self) -> Option<O> {
while let Some(o) = self.instream.next() {
if o.number() == option::URI_PATH {
if let Ok(s) = core::str::from_utf8(o.value()) {
(self.f)(s);
continue;
}
}
return Some(o);
}
None
}
}
}
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)
}
type IgnoredUriQuery = core::iter::Filter<Self, fn(&O) -> bool>;
fn ignore_uri_query(self) -> Self::IgnoredUriQuery {
fn keep_option<O: MessageOption>(o: &O) -> bool {
o.number() != option::URI_QUERY
}
self.filter(keep_option)
}
fn ignore_elective_others(mut self) -> Result<(), CriticalOptionsRemain> {
match self.find(|o| option::get_criticality(o.number()) == option::Criticality::Critical) {
Some(_) => Err(CriticalOptionsRemain(())),
None => Ok(()),
}
}
#[cfg(not(feature = "nontrivial_option_processing"))]
type WithoutBlock2<'a> = aux::BlockPusher<'a, O, Self>;
#[cfg(not(feature = "nontrivial_option_processing"))]
fn take_block2(self, out: &mut Option<Block2RequestData>) -> Self::WithoutBlock2<'_> {
aux::BlockPusher {
instream: self,
out,
}
}
#[cfg(feature = "nontrivial_option_processing")]
type WithoutBlock2<'a> = impl Iterator<Item = O>;
#[cfg(feature = "nontrivial_option_processing")]
fn take_block2(self, out: &mut Option<Block2RequestData>) -> Self::WithoutBlock2<'_> {
self.filter(move |o| {
if matches!(o.number(), option::BLOCK2) && out.is_none() {
if let Ok(o) = Block2RequestData::from_option(o) {
*out = Some(o);
return false;
}
}
true
})
}
#[cfg(not(feature = "nontrivial_option_processing"))]
type WithoutUriPath<'a, F: FnMut(&str)> = aux::UriPusher<O, Self, F>;
#[cfg(not(feature = "nontrivial_option_processing"))]
fn take_uri_path<'a, F: FnMut(&str)>(self, f: F) -> Self::WithoutUriPath<'a, F> {
aux::UriPusher { instream: self, f }
}
#[cfg(feature = "nontrivial_option_processing")]
type WithoutUriPath<'a, F: FnMut(&str)> = impl Iterator<Item = O>;
#[cfg(feature = "nontrivial_option_processing")]
fn take_uri_path<'a, F: FnMut(&str)>(self, mut f: F) -> Self::WithoutUriPath<'a, F> {
self.filter(move |o| {
if o.number() == option::URI_PATH {
if let Ok(s) = core::str::from_utf8(o.value()) {
f(s);
return false;
}
}
true
})
}
}