use coap_handler::Handler;
use coap_message::{MessageOption, MutableWritableMessage, ReadableMessage};
use coap_numbers::option;
use crate::forking_helpers::{ForkingRecord, PrefixedRecord};
use crate::helpers::{MaskingUriUpToPath, MaskingUriUpToPathN};
use crate::{wkc, wkc_implementation, NeverFound};
trait IterOrderByBackport: Iterator {
fn cmp_by<I, F>(mut self, other: I, mut cmp: F) -> core::cmp::Ordering
where
Self: Sized,
I: IntoIterator,
F: FnMut(Self::Item, I::Item) -> core::cmp::Ordering,
{
let mut other = other.into_iter();
loop {
let x = match self.next() {
None => {
if other.next().is_none() {
return core::cmp::Ordering::Equal;
} else {
return core::cmp::Ordering::Less;
}
}
Some(val) => val,
};
let y = match other.next() {
None => return core::cmp::Ordering::Greater,
Some(val) => val,
};
match cmp(x, y) {
core::cmp::Ordering::Equal => (),
non_eq => return non_eq,
}
}
}
}
impl<T: Iterator> IterOrderByBackport for T {}
pub fn new_dispatcher() -> impl Handler + wkc::Reporting {
wkc::NotReporting::new(NeverFound {})
}
pub trait HandlerBuilder<'a, OldRD>
where
Self: Handler + Sized,
{
fn at<H>(self, path: &'a [&'a str], handler: H) -> ForkingHandler<'a, H, Self>
where
H: Handler + Sized,
{
ForkingHandler {
h1: handler,
h2: self,
h1_condition: path,
}
}
fn at_with_attributes<H>(
self,
path: &'a [&'a str],
attributes: &'a [wkc::Attribute],
handler: H,
) -> ForkingHandler<'a, wkc::ConstantSingleRecordReport<'a, H>, Self>
where
H: Handler + Sized,
{
ForkingHandler {
h1: wkc::ConstantSingleRecordReport::new(handler, attributes),
h2: self,
h1_condition: path,
}
}
fn below<H>(self, path: &'a [&'a str], handler: H) -> ForkingTreeHandler<'a, H, Self> {
ForkingTreeHandler {
h1: handler,
h2: self,
h1_condition: path,
}
}
}
impl<'a, OldRD, OldH> HandlerBuilder<'a, OldRD> for OldH
where
Self: Handler<RequestData = OldRD> + Sized,
{
}
pub trait ReportingHandlerBuilder<'a, OldRD>: HandlerBuilder<'a, OldRD> + wkc::Reporting {
fn with_wkc(self) -> wkc_implementation::WellKnownCore<Self> {
wkc_implementation::WellKnownCore::new(self)
}
}
impl<'a, OldRD, OldH> ReportingHandlerBuilder<'a, OldRD> for OldH
where
OldH: Handler<RequestData = OldRD> + wkc::Reporting,
{
}
pub struct ForkingHandler<'a, H1, H2> {
h1: H1,
h2: H2,
h1_condition: &'a [&'a str],
}
pub enum ForkingRequestData<RD1, RD2> {
First(RD1),
Second(RD2),
}
impl<'a, RD1, H1, RD2, H2> Handler for ForkingHandler<'a, H1, H2>
where
H1: Handler<RequestData = RD1>,
H2: Handler<RequestData = RD2>,
{
type RequestData = ForkingRequestData<RD1, RD2>;
fn extract_request_data(&mut self, request: &impl ReadableMessage) -> Self::RequestData {
let expected_path = self.h1_condition.iter().map(|s| s.as_bytes());
let actual_path = request.options().filter(|o| o.number() == option::URI_PATH);
if IterOrderByBackport::cmp_by(expected_path, actual_path, |e, a| e.cmp(a.value()))
== core::cmp::Ordering::Equal
{
let masked = MaskingUriUpToPath(request);
ForkingRequestData::First(self.h1.extract_request_data(&masked))
} else {
ForkingRequestData::Second(self.h2.extract_request_data(request))
}
}
fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
match request {
ForkingRequestData::First(r) => self.h1.estimate_length(r),
ForkingRequestData::Second(r) => self.h2.estimate_length(r),
}
}
fn build_response(
&mut self,
response: &mut impl MutableWritableMessage,
request: Self::RequestData,
) {
match request {
ForkingRequestData::First(r) => self.h1.build_response(response, r),
ForkingRequestData::Second(r) => self.h2.build_response(response, r),
}
}
}
impl<'a, RD1, H1, RD2, H2> wkc::Reporting for ForkingHandler<'a, H1, H2>
where
H1: Handler<RequestData = RD1> + wkc::Reporting,
H2: Handler<RequestData = RD2> + wkc::Reporting,
{
type Record<'b> = ForkingRecord<PrefixedRecord<'b, H1::Record<'b>>, H2::Record<'b>>
where
Self: 'b,
;
type Reporter<'b> = core::iter::Chain<
core::iter::Map<H2::Reporter<'b>, fn(H2::Record<'b>) -> Self::Record<'b>>,
core::iter::Map<
core::iter::Zip<H1::Reporter<'b>, core::iter::Repeat<&'b [&'b str]>>,
fn((H1::Record<'b>, &'b [&'b str])) -> Self::Record<'b>,
>,
>
where
Self: 'b,
;
fn report(&self) -> Self::Reporter<'_> {
fn first<'c, H1R, H2R>(
prefixed_prefix: (H1R, &'c [&'c str]),
) -> ForkingRecord<PrefixedRecord<'c, H1R>, H2R> {
let (prefixed, prefix) = prefixed_prefix;
ForkingRecord::First(PrefixedRecord { prefix, prefixed })
}
self.h2
.report()
.map(ForkingRecord::Second as fn(_) -> _)
.chain(
self.h1
.report()
.zip(core::iter::repeat(self.h1_condition))
.map(first as fn(_) -> _),
)
}
}
pub struct ForkingTreeHandler<'a, H1, H2> {
h1: H1,
h2: H2,
h1_condition: &'a [&'a str],
}
impl<'a, RD1, H1, RD2, H2> Handler for ForkingTreeHandler<'a, H1, H2>
where
H1: Handler<RequestData = RD1>,
H2: Handler<RequestData = RD2>,
{
type RequestData = ForkingRequestData<RD1, RD2>;
fn extract_request_data(&mut self, request: &impl ReadableMessage) -> Self::RequestData {
let expected_path = self.h1_condition.iter().map(|s| s.as_bytes());
let actual_path = request
.options()
.filter(|o| o.number() == option::URI_PATH)
.take(self.h1_condition.len());
if IterOrderByBackport::cmp_by(expected_path, actual_path, |e, a| e.cmp(a.value()))
== core::cmp::Ordering::Equal
{
let masked = MaskingUriUpToPathN::new(request, self.h1_condition.len());
ForkingRequestData::First(self.h1.extract_request_data(&masked))
} else {
ForkingRequestData::Second(self.h2.extract_request_data(request))
}
}
fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
match request {
ForkingRequestData::First(r) => self.h1.estimate_length(r),
ForkingRequestData::Second(r) => self.h2.estimate_length(r),
}
}
fn build_response(
&mut self,
response: &mut impl MutableWritableMessage,
request: Self::RequestData,
) {
match request {
ForkingRequestData::First(r) => self.h1.build_response(response, r),
ForkingRequestData::Second(r) => self.h2.build_response(response, r),
}
}
}
impl<'a, RD1, H1, RD2, H2> wkc::Reporting for ForkingTreeHandler<'a, H1, H2>
where
H1: Handler<RequestData = RD1> + wkc::Reporting,
H2: Handler<RequestData = RD2> + wkc::Reporting,
{
type Record<'b> = ForkingRecord<PrefixedRecord<'b, H1::Record<'b>>, H2::Record<'b>>
where
Self: 'b,
;
#[cfg(feature = "nontrivial_option_processing")]
type Reporter<'b> = impl Iterator<Item = Self::Record<'b>>
where
Self: 'b,
;
#[cfg(feature = "nontrivial_option_processing")]
fn report(&self) -> Self::Reporter<'_> {
self.h2
.report()
.map(ForkingRecord::Second as fn(_) -> _)
.chain(self.h1.report().map(|f| {
ForkingRecord::First(PrefixedRecord {
prefix: self.h1_condition,
prefixed: f,
})
}))
}
#[cfg(not(feature = "nontrivial_option_processing"))]
type Reporter<'b> = core::iter::Chain<
core::iter::Map<H2::Reporter<'b>, fn(H2::Record<'b>) -> Self::Record<'b>>,
core::iter::Map<
core::iter::Zip<H1::Reporter<'b>, core::iter::Repeat<&'b [&'b str]>>,
fn((H1::Record<'b>, &'b [&'b str])) -> Self::Record<'b>,
>,
>
where
Self: 'b,
;
#[cfg(not(feature = "nontrivial_option_processing"))]
fn report(&self) -> Self::Reporter<'_> {
fn first<'c, H1R, H2R>(
prefixed_prefix: (H1R, &'c [&'c str]),
) -> ForkingRecord<PrefixedRecord<'c, H1R>, H2R> {
let (prefixed, prefix) = prefixed_prefix;
ForkingRecord::First(PrefixedRecord { prefix, prefixed })
}
self.h2
.report()
.map(ForkingRecord::Second as fn(_) -> _)
.chain(
self.h1
.report()
.zip(core::iter::repeat(self.h1_condition))
.map(first as fn(_) -> _),
)
}
}