coap_handler/
core_implementations.rs

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