1#![no_std]
32
33mod builder;
34mod conversions;
35
36use coap_message::{MinimalWritableMessage, ReadableMessage};
37use coap_request::{Request, Stack};
38
39use builder::Builder;
40pub use conversions::AsUriPath;
41
42pub struct Code {
47 code: u8,
48}
49
50pub struct WithPath<S: Stack + ?Sized, Prev: Builder<S>, P: AsUriPath> {
54 previous: Prev,
55 path: P,
56 _phantom: core::marker::PhantomData<S>,
57}
58
59pub struct WithRequestCallback<S: Stack + ?Sized, Prev: Builder<S>, F>
61where
62 F: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
63{
64 previous: Prev,
65 f: F,
66 _phantom: core::marker::PhantomData<S>,
67}
68
69impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, F1>
70 WithRequestCallback<S, Prev, F1>
71where
72 F1: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
73{
74 pub fn processing_response_payload_through<O, F2>(
78 self,
79 f: F2,
80 ) -> ProcessingResponse<S, Self, O, F2>
81 where
82 F2: for<'a> FnOnce(&'a [u8]) -> O,
83 {
84 ProcessingResponse {
85 previous: self,
86 f: Some(f),
87 _phantom: Default::default(),
88 }
89 }
90}
91
92pub struct WithRequestPayloadSlice<'payload, S: Stack + ?Sized, Prev: Builder<S>> {
93 previous: Prev,
94 payload: &'payload [u8],
95 _phantom: core::marker::PhantomData<S>,
96}
97
98impl<'payload, S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>>
99 WithRequestPayloadSlice<'payload, S, Prev>
100{
101 pub fn processing_response_payload_through<O, F2>(
105 self,
106 f: F2,
107 ) -> ProcessingResponse<S, Self, O, F2>
108 where
109 F2: for<'a> FnOnce(&'a [u8]) -> O,
110 {
111 ProcessingResponse {
112 previous: self,
113 f: Some(f),
114 _phantom: Default::default(),
115 }
116 }
117}
118
119pub struct ProcessingResponse<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, O, F>
129where
130 F: for<'a> FnOnce(&'a [u8]) -> O,
131{
132 previous: Prev,
133 f: Option<F>,
136 _phantom: core::marker::PhantomData<S>,
137}
138
139macro_rules! code_macro {
140 ($l:ident, $u:ident) => {
141 #[doc=concat!("A request sending the ", stringify!($u), " code")]
142 pub fn $l() -> Self {
143 Self {
144 code: coap_numbers::code::$u,
145 }
146 }
147 };
148}
149
150impl Code {
151 code_macro!(get, GET);
152 code_macro!(post, POST);
153 code_macro!(put, PUT);
154 code_macro!(delete, DELETE);
155 code_macro!(fetch, FETCH);
156 code_macro!(patch, PATCH);
157 code_macro!(ipatch, IPATCH);
158
159 pub fn with_path<S: Stack + ?Sized, P: conversions::AsUriPath>(
161 self,
162 path: P,
163 ) -> WithPath<S, Self, P> {
164 WithPath {
165 previous: self,
166 path,
167 _phantom: Default::default(),
168 }
169 }
170}
171
172impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, P: conversions::AsUriPath>
173 WithPath<S, Prev, P>
174{
175 pub fn with_request_callback<F>(self, f: F) -> WithRequestCallback<S, Self, F>
185 where
186 F: FnMut(&'_ mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
187 {
188 WithRequestCallback {
189 previous: self,
190 f,
191 _phantom: Default::default(),
192 }
193 }
194
195 pub fn with_request_payload_slice(
196 self,
197 payload: &[u8],
198 ) -> WithRequestPayloadSlice<'_, S, Self> {
199 WithRequestPayloadSlice {
200 previous: self,
201 payload,
202 _phantom: Default::default(),
203 }
204 }
205
206 pub fn processing_response_payload_through<O, F>(
208 self,
209 f: F,
210 ) -> ProcessingResponse<S, Self, O, F>
211 where
212 F: for<'a> FnOnce(&'a [u8]) -> O,
213 {
214 ProcessingResponse {
215 previous: self,
216 f: Some(f),
217 _phantom: Default::default(),
218 }
219 }
220}
221
222impl<S: Stack + ?Sized> Request<S> for Code {
223 type Carry = ();
224 type Output = Result<(), ()>;
225 async fn build_request(
226 &mut self,
227 req: &mut S::RequestMessage<'_>,
228 ) -> Result<(), S::RequestUnionError> {
229 use coap_message::Code;
230 let code = <S::RequestMessage<'_> as MinimalWritableMessage>::Code::new(self.code)
231 .map_err(S::RequestMessage::convert_code_error)?;
232 req.set_code(code);
233 Ok(())
234 }
235 async fn process_response(&mut self, res: &S::ResponseMessage<'_>, _carry: ()) -> Self::Output {
236 let code: u8 = res.code().into();
237 use coap_numbers::code::{classify, Class, Range};
238 if !matches!(classify(code), Range::Response(Class::Success)) {
239 return Err(());
242 }
243
244 use coap_message_utils::OptionsExt;
245 res.options().ignore_elective_others().map_err(|_| ())
246 }
247}
248
249impl<S: Stack + ?Sized> Builder<S> for Code {}
250
251impl<S: Stack + ?Sized, Prev: Builder<S>, P: conversions::AsUriPath> Request<S>
252 for WithPath<S, Prev, P>
253{
254 type Carry = Prev::Carry;
255 type Output = Prev::Output;
256 async fn build_request(
257 &mut self,
258 req: &mut S::RequestMessage<'_>,
259 ) -> Result<Self::Carry, S::RequestUnionError> {
260 use coap_message::OptionNumber;
261 let carry = <_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await;
265 for p in self.path.as_uri_path() {
266 req.add_option(
267 <S::RequestMessage<'_> as MinimalWritableMessage>::OptionNumber::new(
268 coap_numbers::option::URI_PATH,
269 )
270 .map_err(S::RequestMessage::convert_option_number_error)?,
271 p.as_bytes(),
272 )
273 .map_err(S::RequestMessage::convert_add_option_error)?;
274 }
275 carry
276 }
277 async fn process_response(
278 &mut self,
279 res: &S::ResponseMessage<'_>,
280 carry: Prev::Carry,
281 ) -> Self::Output {
282 <_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await
283 }
284}
285impl<S: Stack + ?Sized, Prev: Builder<S>, P: conversions::AsUriPath> Builder<S>
286 for WithPath<S, Prev, P>
287{
288}
289
290impl<S: Stack + ?Sized, Prev: Builder<S>, F> Request<S> for WithRequestCallback<S, Prev, F>
291where
292 F: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>,
293{
294 type Carry = Prev::Carry;
295 type Output = Prev::Output;
296 async fn build_request(
297 &mut self,
298 req: &mut S::RequestMessage<'_>,
299 ) -> Result<Self::Carry, S::RequestUnionError> {
300 let carry = <_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await?;
301 (self.f)(req)?;
302 Ok(carry)
303 }
304
305 async fn process_response(
306 &mut self,
307 res: &S::ResponseMessage<'_>,
308 carry: Self::Carry,
309 ) -> Self::Output {
310 <_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await
311 }
312}
313impl<S: Stack + ?Sized, Prev: Builder<S>, F> Builder<S> for WithRequestCallback<S, Prev, F> where
314 F: FnMut(&mut S::RequestMessage<'_>) -> Result<(), S::RequestUnionError>
315{
316}
317
318impl<'payload, S: Stack + ?Sized, Prev: Builder<S>> Request<S>
319 for WithRequestPayloadSlice<'payload, S, Prev>
320{
321 type Carry = Prev::Carry;
322 type Output = Prev::Output;
323 async fn build_request(
324 &mut self,
325 req: &mut S::RequestMessage<'_>,
326 ) -> Result<Self::Carry, S::RequestUnionError> {
327 let carry = <_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await?;
328 req.set_payload(self.payload)
329 .map_err(S::RequestMessage::convert_set_payload_error)?;
330 Ok(carry)
331 }
332
333 async fn process_response(
334 &mut self,
335 res: &S::ResponseMessage<'_>,
336 carry: Self::Carry,
337 ) -> Self::Output {
338 <_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await
339 }
340}
341impl<'payload, S: Stack + ?Sized, Prev: Builder<S>> Builder<S>
342 for WithRequestPayloadSlice<'payload, S, Prev>
343{
344}
345
346impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, O, F> Request<S>
347 for ProcessingResponse<S, Prev, O, F>
348where
349 F: for<'a> FnOnce(&'a [u8]) -> O,
350{
351 type Carry = Prev::Carry;
352 type Output = Result<O, ()>;
353 async fn build_request(
354 &mut self,
355 req: &mut S::RequestMessage<'_>,
356 ) -> Result<Self::Carry, S::RequestUnionError> {
357 <_ as coap_request::Request<S>>::build_request(&mut self.previous, req).await
358 }
359
360 async fn process_response(
361 &mut self,
362 res: &S::ResponseMessage<'_>,
363 carry: Self::Carry,
364 ) -> Self::Output {
365 <_ as coap_request::Request<S>>::process_response(&mut self.previous, res, carry).await?;
366 if let Some(f) = self.f.take() {
367 Ok(f(res.payload()))
368 } else {
369 Err(())
370 }
371 }
372}
373impl<S: Stack + ?Sized, Prev: Builder<S, Output = Result<(), ()>>, O, F> Builder<S>
374 for ProcessingResponse<S, Prev, O, F>
375where
376 F: for<'a> FnOnce(&'a [u8]) -> O,
377{
378}