coap_handler_implementations/
typed_resource.rs1use crate::Error;
6use crate::helpers::block2_write_with_cf;
7use coap_handler::Handler;
8use coap_message::{
9 Code as _, MessageOption, MinimalWritableMessage, MutableWritableMessage, ReadableMessage,
10};
11use coap_message_utils::{OptionsExt, option_value::Block2RequestData};
12use coap_numbers::{code, option};
13use core::marker::PhantomData;
14
15use serde::Serialize;
16
17pub struct Empty;
22
23pub trait TypeRenderable {
29 type Get;
31 type Post;
35 type Put;
37
38 fn get(&mut self) -> Result<Self::Get, u8> {
39 Err(code::METHOD_NOT_ALLOWED)
40 }
41 fn post(&mut self, _representation: &Self::Post) -> u8 {
42 code::METHOD_NOT_ALLOWED
43 }
44 fn put(&mut self, _representation: &Self::Put) -> u8 {
45 code::METHOD_NOT_ALLOWED
46 }
47 fn delete(&mut self) -> u8 {
48 code::METHOD_NOT_ALLOWED
49 }
50}
51
52mod sealed {
55 pub trait TypeSerializer {
56 const CF: Option<u16>;
57 }
58
59 pub struct SerdeCBORSerialization;
60 pub struct MiniCBORSerialization0_19;
61 pub struct MiniCBORSerialization0_24;
62 pub struct MiniCBORSerialization0_26;
63 pub struct MiniCBORSerialization1;
64}
65use sealed::*;
66
67impl TypeSerializer for SerdeCBORSerialization {
68 const CF: Option<u16> = coap_numbers::content_format::from_str("application/cbor");
69}
70
71pub struct TypeHandler<H, S: TypeSerializer = SerdeCBORSerialization>
83where
84 H: TypeRenderable,
85{
86 handler: H,
87 _phantom: PhantomData<S>,
88}
89
90impl<H, S> TypeHandler<H, S>
91where
92 H: TypeRenderable,
93 S: TypeSerializer,
94{
95 fn check_get_options(request: &impl ReadableMessage) -> Result<Block2RequestData, Error> {
96 let mut block2 = None;
97
98 request
99 .options()
100 .take_block2(&mut block2)
101 .filter(|o| {
102 if o.number() == option::ACCEPT {
103 if let Some(cf) = S::CF {
104 o.value_uint() != Some(cf)
106 } else {
107 true
110 }
111 } else {
112 true
113 }
114 })
115 .ignore_elective_others()?;
116
117 Ok(block2.unwrap_or_default())
118 }
119
120 fn check_delete_options(request: &impl ReadableMessage) -> Result<(), Error> {
121 request.options().ignore_elective_others()
122 }
123
124 fn check_postput_options(request: &impl ReadableMessage) -> Result<(), Error> {
125 let mut cf = Ok(());
126
127 request
128 .options()
129 .filter(|o| {
130 if o.number() == option::CONTENT_FORMAT
131 && (S::CF.is_none() || o.value_uint() != S::CF)
132 {
133 cf = Err(Error::bad_option(option::CONTENT_FORMAT));
134 }
135 true
137 })
138 .ignore_elective_others()?;
139
140 cf
141 }
142}
143
144impl<H> TypeHandler<H, SerdeCBORSerialization>
145where
146 H: TypeRenderable,
147 H::Get: for<'de> serde::Serialize,
148 H::Post: for<'de> serde::Deserialize<'de>,
149 H::Put: for<'de> serde::Deserialize<'de>,
150{
151 pub fn new(handler: H) -> Self {
153 TypeHandler {
154 handler,
155 _phantom: PhantomData,
156 }
157 }
158}
159
160pub struct TypeRequestData(TypeRequestDataE);
162
163enum TypeRequestDataE {
164 Get(Block2RequestData), Done(u8), }
167use self::TypeRequestDataE::{Done, Get};
168
169impl<H> Handler for TypeHandler<H, SerdeCBORSerialization>
173where
174 H: TypeRenderable,
175 H::Get: for<'de> serde::Serialize,
176 H::Post: for<'de> serde::Deserialize<'de>,
177 H::Put: for<'de> serde::Deserialize<'de>,
178{
179 type RequestData = TypeRequestData;
180 type ExtractRequestError = Error;
181 type BuildResponseError<M: MinimalWritableMessage> = M::UnionError;
182
183 fn extract_request_data<M: ReadableMessage>(
184 &mut self,
185 request: &M,
186 ) -> Result<Self::RequestData, Error> {
187 Ok(TypeRequestData(match request.code().into() {
188 code::DELETE => {
189 Self::check_delete_options(request)?;
190 Done(self.handler.delete())
191 }
192 code::GET => Get(Self::check_get_options(request)?),
193 code::POST => {
194 Self::check_postput_options(request)?;
195
196 let parsed: H::Post =
199 serde_cbor::de::from_slice_with_scratch(request.payload(), &mut [])
200 .map_err(|_| Error::bad_request())?;
201 Done(self.handler.post(&parsed))
202 }
203 code::PUT => {
204 Self::check_postput_options(request)?;
205
206 let parsed: H::Put =
207 serde_cbor::de::from_slice_with_scratch(request.payload(), &mut [])
208 .map_err(|_| Error::bad_request())?;
209 Done(self.handler.put(&parsed))
210 }
211 _ => Done(code::METHOD_NOT_ALLOWED),
212 }))
213 }
214
215 fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
216 match &request.0 {
217 Done(_) => 4,
218 Get(block) => (block.size() + 25).into(), }
220 }
221
222 fn build_response<M: MutableWritableMessage>(
223 &mut self,
224 response: &mut M,
225 request: Self::RequestData,
226 ) -> Result<(), Self::BuildResponseError<M>> {
227 match request.0 {
228 Done(r) => response.set_code(M::Code::new(r)?),
229 Get(block2) => {
230 let repr = self.handler.get();
231 match repr {
232 Err(e) => response.set_code(M::Code::new(e)?),
233 Ok(repr) => {
234 response.set_code(M::Code::new(code::CONTENT)?);
235 match block2_write_with_cf(
236 block2,
237 response,
238 |win| repr.serialize(&mut serde_cbor::ser::Serializer::new(win)),
239 SerdeCBORSerialization::CF,
240 ) {
241 Ok(()) => (),
242 Err(_) => {
243 response.set_code(M::Code::new(code::INTERNAL_SERVER_ERROR)?);
245 }
246 }
247 }
248 }
249 }
250 };
251 Ok(())
252 }
253}
254
255trait ToTypedResourceError {
256 fn into_general_error(self, total_len: usize) -> Error;
257}
258
259macro_rules! for_each_minicbor {
260 ($minicbor:ident, $mcstype:ident) => {
261 impl<'b, C> $minicbor::decode::Decode<'b, C> for Empty {
262 fn decode(
263 _d: &mut $minicbor::decode::Decoder<'b>,
264 _ctx: &mut C,
265 ) -> Result<Self, $minicbor::decode::Error> {
266 Err($minicbor::decode::Error::message("No element expected").at(0))
267 }
268
269 fn nil() -> Option<Self> {
270 Some(Empty)
271 }
272 }
273
274 impl<H> Handler for TypeHandler<H, $mcstype>
275 where
276 H: TypeRenderable,
277 H::Get: for<'de> $minicbor::Encode<()>,
278 H::Post: for<'de> $minicbor::Decode<'de, ()>,
279 H::Put: for<'de> $minicbor::Decode<'de, ()>,
280 {
281 type RequestData = TypeRequestData;
282 type ExtractRequestError = Error;
283 type BuildResponseError<M: MinimalWritableMessage> = M::UnionError;
284
285 fn extract_request_data<M: ReadableMessage>(
286 &mut self,
287 request: &M,
288 ) -> Result<Self::RequestData, Error> {
289 Ok(TypeRequestData(match request.code().into() {
290 code::DELETE => {
291 Self::check_delete_options(request)?;
292 Done(self.handler.delete())
293 }
294 code::GET => Get(Self::check_get_options(request)?),
295 code::POST => {
296 use $minicbor::decode::Decode;
297 Self::check_postput_options(request)?;
298
299 let payload = request.payload();
300 match (payload, H::Post::nil()) {
301 (b"", Some(nil)) => Done(self.handler.post(&nil)),
302 (payload, _) => {
303 let parsed: H::Post =
304 $minicbor::decode(payload).map_err(|deserialize_error| {
305 deserialize_error.into_general_error(payload.len())
306 })?;
307 Done(self.handler.post(&parsed))
308 }
309 }
310 }
311 code::PUT => {
312 Self::check_postput_options(request)?;
313
314 let payload = request.payload();
315
316 let parsed: H::Put =
317 $minicbor::decode(payload).map_err(|deserialize_error| {
318 deserialize_error.into_general_error(payload.len())
319 })?;
320 Done(self.handler.put(&parsed))
321 }
322 _ => Done(code::METHOD_NOT_ALLOWED),
323 }))
324 }
325
326 fn estimate_length(&mut self, request: &Self::RequestData) -> usize {
327 match &request.0 {
328 Done(_) => 4,
329 Get(block) => (block.size() + 25).into(), }
331 }
332
333 fn build_response<M: MutableWritableMessage>(
334 &mut self,
335 response: &mut M,
336 request: Self::RequestData,
337 ) -> Result<(), Self::BuildResponseError<M>> {
338 match request.0 {
339 Done(r) => response.set_code(M::Code::new(r)?),
340 Get(block2) => {
341 let repr = self.handler.get();
342 match repr {
343 Err(e) => response.set_code(M::Code::new(e)?),
344 Ok(repr) => {
345 response.set_code(M::Code::new(code::CONTENT)?);
346 match block2_write_with_cf(
347 block2,
348 response,
349 |win| $minicbor::encode(&repr, win),
350 $mcstype::CF,
351 ) {
352 Ok(()) => (),
353 Err(_) => {
354 response
356 .set_code(M::Code::new(code::INTERNAL_SERVER_ERROR)?);
357 }
358 }
359 }
360 }
361 }
362 };
363 Ok(())
364 }
365 }
366
367 impl TypeSerializer for $mcstype {
368 const CF: Option<u16> = coap_numbers::content_format::from_str("application/cbor");
369 }
370 };
371}
372
373for_each_minicbor!(minicbor_0_19, MiniCBORSerialization0_19);
374for_each_minicbor!(minicbor_0_24, MiniCBORSerialization0_24);
375for_each_minicbor!(minicbor_0_26, MiniCBORSerialization0_26);
376for_each_minicbor!(minicbor_1, MiniCBORSerialization1);
377
378impl<H> TypeHandler<H, MiniCBORSerialization0_19>
379where
380 H: TypeRenderable,
381 H::Get: for<'de> minicbor_0_19::Encode<()>,
382 H::Post: for<'de> minicbor_0_19::Decode<'de, ()>,
383 H::Put: for<'de> minicbor_0_19::Decode<'de, ()>,
384{
385 pub fn new_minicbor(handler: H) -> Self {
387 TypeHandler {
388 handler,
389 _phantom: PhantomData,
390 }
391 }
392}
393
394impl<H> TypeHandler<H, MiniCBORSerialization0_24>
395where
396 H: TypeRenderable,
397 H::Get: for<'de> minicbor_0_24::Encode<()>,
398 H::Post: for<'de> minicbor_0_24::Decode<'de, ()>,
399 H::Put: for<'de> minicbor_0_24::Decode<'de, ()>,
400{
401 pub fn new_minicbor_0_24(handler: H) -> Self {
403 TypeHandler {
404 handler,
405 _phantom: PhantomData,
406 }
407 }
408}
409
410impl<H> TypeHandler<H, MiniCBORSerialization0_26>
411where
412 H: TypeRenderable,
413 H::Get: for<'de> minicbor_0_26::Encode<()>,
414 H::Post: for<'de> minicbor_0_26::Decode<'de, ()>,
415 H::Put: for<'de> minicbor_0_26::Decode<'de, ()>,
416{
417 pub fn new_minicbor_0_26(handler: H) -> Self {
419 TypeHandler {
420 handler,
421 _phantom: PhantomData,
422 }
423 }
424}
425
426impl<H> TypeHandler<H, MiniCBORSerialization1>
427where
428 H: TypeRenderable,
429 H::Get: for<'de> minicbor_1::Encode<()>,
430 H::Post: for<'de> minicbor_1::Decode<'de, ()>,
431 H::Put: for<'de> minicbor_1::Decode<'de, ()>,
432{
433 pub fn new_minicbor_1(handler: H) -> Self {
435 TypeHandler {
436 handler,
437 _phantom: PhantomData,
438 }
439 }
440}
441
442impl ToTypedResourceError for minicbor_0_19::decode::Error {
443 fn into_general_error(self, total_len: usize) -> Error {
444 let mut error = Error::bad_request();
445 if self.is_end_of_input() {
447 error = Error::bad_request_with_rbep(total_len);
448 };
449 if self.is_type_mismatch() {
450 error = error.with_title("Type mismatch")
451 }
452 error
453 }
454}
455
456macro_rules! minicbor_24plus_error {
457 ($minicbor:ident) => {
458 impl ToTypedResourceError for $minicbor::decode::Error {
459 fn into_general_error(self, total_len: usize) -> Error {
460 let mut error = Error::bad_request();
461 if let Some(position) = self.position() {
462 error = Error::bad_request_with_rbep(position);
463 }
464 if self.is_end_of_input() {
465 error = Error::bad_request_with_rbep(total_len);
468 };
469 if self.is_type_mismatch() {
470 error = error.with_title("Type mismatch")
471 }
472 error
473 }
474 }
475 };
476}
477
478minicbor_24plus_error!(minicbor_0_24);
479minicbor_24plus_error!(minicbor_0_26);
480minicbor_24plus_error!(minicbor_1);