coap_handler/
handler.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
/// A minimal stateless testing CoAP server interface.
use coap_message::{MinimalWritableMessage, MutableWritableMessage, ReadableMessage};

pub trait Request {
    // I think this will require coap-message to `impl ReadableMessage for &T where T:
    // ReadableMessage`, but we can do that.
    fn request(&self) -> impl ReadableMessage;

    fn done(
        self,
    ) -> impl PausedOperation<ResponseMessage = Self::ResponseMessage, ResponseDone = Self::ResponseDone>;

    type ResponseMessage: MutableWritableMessage;
    type ResponseDone;
}

pub trait PausedOperation {
    type ResponseMessage: MutableWritableMessage;
    type ResponseDone;

    async fn respond(
        self,
        expected_length: usize,
    ) -> impl Response<ResponseMessage = Self::ResponseMessage, Done = Self::ResponseDone>;
}

pub trait Response {
    type Done;

    // It'd be tempting to add a lifetime to ResponseMessage, but that doesn't really give us
    // anything:
    // While we could return an arbitrarily lifetime'd impl Self::ResponseMessage in response, that
    // lifetime is still given by the caller. If an implementor needs a lifetime, it can be part of
    // the Self type and thus already in the ResponseMessage of Request, PausedOperation and
    // Response.
    // (Plus we can't carry a generic -> impl Response<for<'a> ResponsMessage<'a> =
    // Self::ResponseMessage<'a>> around, so we'd need to carry all the ResponseMessage's
    // individual associated types hoping they don't depend on that lifetime).

    type ResponseMessage: MutableWritableMessage;

    // This typically owns whatever is given out as a mutable response (but sticking with &mut so
    // it's not a use-once thing, as long as ResponseMessage does not follow a type state pattern
    // -- that can be added in parallel anyway.)

    fn response(&mut self) -> &mut Self::ResponseMessage;

    // While we have MutableWritableMessage style building, this may check whether a code was set.
    // On the long run with a type state pattern writable message, handing that back can produce
    // the same result without runtime checks.

    fn done(self) -> Self::Done;
}

/// A CoAP request handler. This gets called by a CoAP server implementation that the handler is
/// assigned to. The server processes the [.handle()][Self::handle] async method. As part of
/// building a successful response, the handler takes the passed [Request] object, reads from
/// it, turns it into a [Response] and writes into that response.
///
/// Response building is inherently fallible (the stack may not support some options), and other
/// errors can just as well occur during extraction (for example checking for unprocessed critical
/// options). Returning an error is not only an ergonomically easy step, it also allows the error
/// writer to start over fresh: There is currently no trait method in [`coap_message`] that
/// describes how that would be done, but the CoAP implementation knows the concrete type and can
/// use its methods directly.
pub trait Handler {
    type Error<M: MinimalWritableMessage>: core::fmt::Debug
        + coap_message::error::RenderableOnMinimal;

    /// Processes an incoming request and build a response.
    ///
    /// Implementations that do not have anything to await in their application logic still have at
    /// least one await point: the call to the async Request::response method.
    ///
    /// CoAP servers may be implemented with limited buffer space. It is therefore recommended that
    /// long awaits (ideally, any awaits) are run between the call to [`Request::done()`] (at
    /// which point the CoAP server can start reusing the receive buffer) and the subsequent call
    /// to [`.respond()`][PausedOperation::respond] during which the server waits for a send
    /// buffer to be ready.
    async fn handle<R: Request>(
        &mut self,
        request: R,
    ) -> Result<<R as Request>::ResponseDone, Self::Error<<R as Request>::ResponseMessage>>;
}