coap_handler/core_implementations.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
//! This module provides implementations of [Handler]
use crate::{Handler, Reporting};
use coap_message::{MinimalWritableMessage, MutableWritableMessage, ReadableMessage};
use coap_numbers::code;
/// An easy way to have resources that may or may not be there in a tree, considering that Handler
/// is not object safe and thus, `if let Some(x) { all = all.at(...) }` won't work.
///
/// This returns 4.04 Not Found if the inner handler is absent, and otherwise forwards request and
/// response building.
impl<H> Handler for Option<H>
where
H: Handler,
{
type RequestData = Option<H::RequestData>;
// FIXME: One of those should become a wrapper, so we don't need to unwrap() in the error
// handler. (The way it's written right now it'd be in the ExtractRequestError, but wrapping
// the error to go NOT_FOUND there might be more intuitive).
type ExtractRequestError = H::ExtractRequestError;
type BuildResponseError<M: MinimalWritableMessage> = H::BuildResponseError<M>;
fn extract_request_data<M: ReadableMessage>(
&mut self,
request: &M,
) -> Result<Self::RequestData, Self::ExtractRequestError> {
match self {
None => Ok(None),
Some(h) => Ok(Some(h.extract_request_data(request)?)),
}
}
fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
match (self, request) {
(Some(h), Some(r)) => h.estimate_length(r),
_ => 1,
}
}
fn build_response<M: MutableWritableMessage>(
&mut self,
response: &mut M,
request: Self::RequestData,
) -> Result<(), H::BuildResponseError<M>> {
// Not using the match-2-tuple pattern of above b/c of
// "error[E0009]: cannot bind by-move and by-ref in the same pattern"
if let Some(h) = self {
if let Some(r) = request {
return h.build_response(response, r);
}
}
use coap_message::Code;
response.set_code(M::Code::new(code::NOT_FOUND).unwrap());
Ok(())
}
}
impl<H> Reporting for Option<H>
where
H: Reporting,
{
type Record<'res> = H::Record<'res>
where
Self: 'res;
type Reporter<'res> = OptionReporter<'res, H>
where
Self: 'res;
fn report(&self) -> Self::Reporter<'_> {
// This could be as simple as
//
// self.into_iter().map(|h| H::report(h)).into_iter().flatten()
//
// with TAIT; haven't managed without without introducing this helper:
OptionReporter::<H>(self.as_ref().map(|h| h.report()))
}
}
/// Helper type for the [Reporting] implementation on Option
pub struct OptionReporter<'res, H: Reporting + 'res>(Option<H::Reporter<'res>>);
impl<'res, H: Reporting + 'res> Iterator for OptionReporter<'res, H> {
type Item = H::Record<'res>;
fn next(&mut self) -> Option<H::Record<'res>> {
self.0.as_mut().and_then(|s| s.next())
}
}