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}