coap_request/
lib.rs

1//! The `coap-request` crate defines an interface provided by a CoAP client stack towards
2//! applications that can send requests through it.
3//!
4//! It is the client side equivalent of the [coap-handler] crate.
5//!
6//! [coap-handler]: https://docs.rs/coap-handler/
7//!
8//! ## Usability
9//!
10//! This crate provides a very low-level and generic interface, which is not ideal for every-day
11//! "GET me the plain text content of coap://example.com/foo" style requests. The crate
12//! [coap-request-implementations] will fill the gap, just as [coap-handler-implementations] does
13//! for [coap-handler].
14//!
15//! [coap-request-implementations]: https://docs.rs/coap-request-implementations/
16//! [coap-handler-implementations]: https://docs.rs/coap-handler-implementations/
17//!
18//! ## Caveats
19//!
20//! There boundary of responsibilities for respecting protocol level requirements is not clearly
21//! established yet. For example, it is unclear how the application learns special option encoding
22//! rules it needs to follow given the transport, or whether other operations on the same stack
23//! have concluded their operations w/rt Request-Tag processing.
24//!
25//! It is unclear yet whether the async functions should be Send or not (or whether distinct traits
26//! are needed to cater for both cases).
27#![no_std]
28
29use core::future::Future;
30
31use coap_message::{MinimalWritableMessage, ReadableMessage};
32
33/// Interface describing a CoAP request a client wants to send
34///
35/// This interface requires describes the request itself, and is passed to the stack in
36/// [Stack::request].
37///
38/// Where possible, implementers should keep the [build_request] and [process_response] async
39/// functions short, ideally not having any await points at all. The interface is defined to allow
40/// slow interfaces to read into the buffer already allocated by the stack without blocking the
41/// remaining operations of the stack.
42// Placing the type generic on the trait level instead of on the function level. Gotta see if this
43// makes anything easier.
44pub trait Request<S: Stack + ?Sized> {
45    type Output;
46    type Carry;
47
48    /// Build the request message
49    ///
50    /// The stack may run this multiple times if it requires retransmissions. This function may
51    /// produce different results, and the response handler must be prepared to process the
52    /// response to any of the requests.
53    fn build_request(
54        &mut self,
55        request: &mut S::RequestMessage<'_>,
56    ) -> impl Future<Output = Self::Carry>;
57
58    /// Process the response message
59    ///
60    /// The stack calls this once, with any of the Carry produced by [build_request] (which as
61    /// pointed out there does not indicate whether it was precisely *that* Carry's request that
62    /// is being responded to).
63    fn process_response(
64        &mut self,
65        response: &S::ResponseMessage<'_>,
66        carry: Self::Carry,
67    ) -> impl Future<Output = Self::Output>;
68}
69
70/// The CoAP stack provided by a CoAP library
71///
72/// Acting on this requires an exclusive reference `&mut self`. Stacks that support multiple
73/// concurrent requests can allow cloning the stack, or implement this on a shared reference
74/// `&self`.
75///
76/// In its current form, this takes no "remote address" argument, nor arguments that indicate
77/// whether the request should be sent reliably. It is ecpected that stacks provide a builder like
78/// this:
79///
80/// ```ignore
81/// let wkc = stack
82///     .to("coap://example.com".parse().unwrap())
83///     .reliably()
84///     .request(GetWellKnownCore)
85///     .await
86/// ```
87pub trait Stack {
88    /// Type of message the client will write its request into
89    type RequestMessage<'a>: MinimalWritableMessage
90    where
91        Self: 'a;
92    /// Type of message the client will read the response from
93    type ResponseMessage<'a>: ReadableMessage
94    where
95        Self: 'a;
96    /// Error indicating an error at some point below the CoAP request-reponse mechanism
97    ///
98    /// This can for example be a failure to establish a connection, or an invalid message from the
99    /// peer. Few transports may use an infallible type here: While they may do ample checks at
100    /// `.to()` time (eg. already starting a connection), any protocol error may wind up here. (A
101    /// notable exception is a Rust typed CoAP loopback device).
102    type TransportError: core::fmt::Debug;
103
104    fn request<Req: Request<Self>>(
105        &mut self,
106        request: Req,
107    ) -> impl Future<Output = Result<Req::Output, Self::TransportError>>;
108}