1
// SPDX-License-Identifier: BSD-2-Clause
2
/*
3
 * resource.rs - Types relating to CoAP resource management.
4
 * This file is part of the libcoap-rs crate, see the README and LICENSE files for
5
 * more information and terms of use.
6
 * Copyright © 2021-2023 The NAMIB Project Developers, all rights reserved.
7
 * See the README as well as the LICENSE file for more information.
8
 */
9

            
10
//! Resource and resource handler descriptions
11

            
12
use std::{
13
    any::Any,
14
    cell::Ref,
15
    cell::RefMut,
16
    fmt::{Debug, Formatter},
17
    marker::PhantomData,
18
};
19

            
20
use libc::c_int;
21

            
22
use libcoap_sys::{
23
    coap_delete_resource, coap_new_str_const, coap_pdu_t, coap_register_request_handler, COAP_RESOURCE_FLAGS_NOTIFY_CON,
24
    COAP_RESOURCE_FLAGS_NOTIFY_NON, COAP_RESOURCE_FLAGS_RELEASE_URI, coap_resource_get_uri_path, coap_resource_get_userdata,
25
    coap_resource_init, coap_resource_notify_observers, coap_resource_set_get_observable, coap_resource_set_mode, coap_resource_set_userdata, coap_resource_t,
26
    coap_send_rst, coap_session_t, coap_string_t,
27
};
28

            
29
use crate::{error::MessageConversionError, message::CoapMessage, protocol::CoapRequestCode};
30
use crate::context::ensure_coap_started;
31
use crate::mem::{CoapFfiRcCell, DropInnerExclusively};
32
use crate::message::CoapMessageCommon;
33
use crate::message::request::CoapRequest;
34
use crate::message::response::CoapResponse;
35
use crate::protocol::CoapMessageCode;
36
use crate::protocol::CoapMessageType;
37
use crate::session::CoapServerSession;
38
use crate::session::CoapSessionCommon;
39

            
40
// Trait aliases are experimental
41
//trait CoapMethodHandlerFn<D> = FnMut(&D, &mut CoapSession, &CoapRequestMessage, &mut CoapResponseMessage);
42

            
43
// Some macro wizardry to statically wrap request handlers.
44
/// Create a CoapRequestHandler using the provided function.
45
///
46
/// This macro cannot be used if the intended handler function does not have a 'static lifetime,
47
/// i.e. if the handler function is a closure.
48
/// In these cases, use [CoapRequestHandler::new()] instead.
49
#[macro_export]
50
macro_rules! resource_handler {
51
    ($f:ident, $t:path) => {{
52
        #[allow(clippy::unnecessary_mut_passed)] // We don't know whether the function needs a mutable reference or not.
53
25
        unsafe extern "C" fn _coap_method_handler_wrapper<D: Any + ?Sized + Debug>(
54
25
            resource: *mut coap_resource_t,
55
25
            session: *mut coap_session_t,
56
25
            incoming_pdu: *const coap_pdu_t,
57
25
            query: *const coap_string_t,
58
25
            response_pdu: *mut coap_pdu_t,
59
25
        ) {
60
25
            let handler_data =
61
25
                prepare_resource_handler_data::<$t>(resource, session, incoming_pdu, query, response_pdu);
62
25
            if let Ok((mut resource, mut session, incoming_pdu, outgoing_pdu)) = handler_data {
63
25
                ($f::<D>)(&mut resource, &mut session, &incoming_pdu, outgoing_pdu)
64
            }
65
25
        }
66
        unsafe { CoapRequestHandler::<$t>::from_raw_handler(_coap_method_handler_wrapper::<$t>) }
67
    }};
68
}
69

            
70
/// Converts the raw parameters provided to a request handler into the appropriate wrapped types.
71
///
72
/// If an error occurs while parsing the resource data, this function will send an RST message to the
73
/// client and return a [MessageConversionError].
74
///
75
/// This function is not intended for public use, the only reason it is public is that the
76
/// [resource_handler!] macro requires this function.
77
///
78
/// # Safety
79
/// The provided pointers must all be valid and point to the appropriate data structures.
80
#[inline]
81
#[doc(hidden)]
82
25
pub unsafe fn prepare_resource_handler_data<'a, D: Any + ?Sized + Debug>(
83
25
    raw_resource: *mut coap_resource_t,
84
25
    raw_session: *mut coap_session_t,
85
25
    raw_incoming_pdu: *const coap_pdu_t,
86
25
    _raw_query: *const coap_string_t,
87
25
    raw_response_pdu: *mut coap_pdu_t,
88
25
) -> Result<(CoapResource<D>, CoapServerSession<'a>, CoapRequest, CoapResponse), MessageConversionError> {
89
25
    let resource_tmp = CoapFfiRcCell::clone_raw_weak(coap_resource_get_userdata(raw_resource));
90
25
    let resource = CoapResource::from(resource_tmp);
91
25
    let session = CoapServerSession::from_raw(raw_session);
92
25
    let request = CoapMessage::from_raw_pdu(raw_incoming_pdu).and_then(|v| CoapRequest::from_message(v, &session));
93
25
    let response = CoapMessage::from_raw_pdu(raw_response_pdu).and_then(CoapResponse::from_message);
94
25
    match (request, response) {
95
25
        (Ok(request), Ok(response)) => Ok((resource, session, request, response)),
96
        (v1, v2) => {
97
            coap_send_rst(raw_session, raw_incoming_pdu);
98
            Err(v1.and(v2).err().unwrap())
99
        },
100
    }
101
25
}
102

            
103
/// Trait with functions relating to [CoapResource]s with an unknown data type.
104
pub trait UntypedCoapResource: Any + Debug {
105
    /// Returns the uri_path this resource responds to.
106
    fn uri_path(&self) -> &str;
107
    /// Provides a reference to this resource as an [Any] trait object.
108
    ///
109
    /// You can use the resulting [Any] reference to downcast the resource to its appropriate
110
    /// concrete type (if you wish to e.g. change the application data).
111
    ///
112
    /// If you use unstable Rust, you can use trait upcasting instead (`[value] as Any`).
113
    fn as_any(&self) -> &dyn Any;
114
    /// Attempts to regain exclusive ownership of the inner resource in order to drop it.
115
    ///
116
    /// This function is used by the [CoapContext](crate::context::CoapContext) on cleanup to
117
    /// reclaim resources before dropping the context itself. *You should not use this function*.
118
    ///
119
    /// # Panics
120
    /// Panics if the inner resource instance associated with this resource cannot be exclusively
121
    /// dropped, i.e. because the underlying [Rc] is used elsewhere.
122
    #[doc(hidden)]
123
    fn drop_inner_exclusive(self: Box<Self>);
124
    /// Returns the raw resource associated with this CoapResource.
125
    ///
126
    /// # Safety
127
    /// You must not do anything with this resource that could interfere with this instance.
128
    /// Most notably, you must not...
129
    /// - ...free the returned value using [coap_delete_resource](libcoap_sys::coap_delete_resource)
130
    /// - ...associate the raw resource with a CoAP context, because if the context is dropped, so
131
    ///   will the resource.
132
    /// - ...modify the application-specific data.
133
    unsafe fn raw_resource(&mut self) -> *mut coap_resource_t;
134
}
135

            
136
/// Representation of a CoapResource that can be requested from a server.
137
#[derive(Debug)]
138
pub struct CoapResource<D: Any + ?Sized + Debug> {
139
    inner: CoapFfiRcCell<CoapResourceInner<D>>,
140
}
141

            
142
/// Container for resource handlers for various CoAP methods.
143
#[derive(Debug)]
144
struct CoapResourceHandlers<D: Any + ?Sized + Debug> {
145
    get: Option<CoapRequestHandler<D>>,
146
    put: Option<CoapRequestHandler<D>>,
147
    delete: Option<CoapRequestHandler<D>>,
148
    post: Option<CoapRequestHandler<D>>,
149
    fetch: Option<CoapRequestHandler<D>>,
150
    ipatch: Option<CoapRequestHandler<D>>,
151
    patch: Option<CoapRequestHandler<D>>,
152
}
153

            
154
impl<D: Any + ?Sized + Debug> Default for CoapResourceHandlers<D> {
155
25
    fn default() -> Self {
156
25
        CoapResourceHandlers {
157
25
            get: None,
158
25
            put: None,
159
25
            delete: None,
160
25
            post: None,
161
25
            fetch: None,
162
25
            ipatch: None,
163
25
            patch: None,
164
25
        }
165
25
    }
166
}
167

            
168
impl<D: Any + ?Sized + Debug> CoapResourceHandlers<D> {
169
    #[inline]
170
25
    fn handler(&self, code: CoapRequestCode) -> Option<&CoapRequestHandler<D>> {
171
25
        match code {
172
25
            CoapRequestCode::Get => self.get.as_ref(),
173
            CoapRequestCode::Put => self.put.as_ref(),
174
            CoapRequestCode::Delete => self.delete.as_ref(),
175
            CoapRequestCode::Post => self.post.as_ref(),
176
            CoapRequestCode::Fetch => self.fetch.as_ref(),
177
            CoapRequestCode::IPatch => self.ipatch.as_ref(),
178
            CoapRequestCode::Patch => self.patch.as_ref(),
179
        }
180
25
    }
181

            
182
    #[inline]
183
    // Clippy complains about this being unused, but I'd like to keep it for consistency.
184
    #[allow(unused)]
185
    fn handler_mut(&mut self, code: CoapRequestCode) -> Option<&mut CoapRequestHandler<D>> {
186
        match code {
187
            CoapRequestCode::Get => self.get.as_mut(),
188
            CoapRequestCode::Put => self.put.as_mut(),
189
            CoapRequestCode::Delete => self.delete.as_mut(),
190
            CoapRequestCode::Post => self.post.as_mut(),
191
            CoapRequestCode::Fetch => self.fetch.as_mut(),
192
            CoapRequestCode::IPatch => self.ipatch.as_mut(),
193
            CoapRequestCode::Patch => self.patch.as_mut(),
194
        }
195
    }
196

            
197
    // Kept for consistency
198
    #[allow(unused)]
199
    #[inline]
200
    fn handler_ref(&self, code: CoapRequestCode) -> &Option<CoapRequestHandler<D>> {
201
        match code {
202
            CoapRequestCode::Get => &self.get,
203
            CoapRequestCode::Put => &self.put,
204
            CoapRequestCode::Delete => &self.delete,
205
            CoapRequestCode::Post => &self.post,
206
            CoapRequestCode::Fetch => &self.fetch,
207
            CoapRequestCode::IPatch => &self.ipatch,
208
            CoapRequestCode::Patch => &self.patch,
209
        }
210
    }
211

            
212
    #[inline]
213
75
    fn handler_ref_mut(&mut self, code: CoapRequestCode) -> &mut Option<CoapRequestHandler<D>> {
214
75
        match code {
215
75
            CoapRequestCode::Get => &mut self.get,
216
            CoapRequestCode::Put => &mut self.put,
217
            CoapRequestCode::Delete => &mut self.delete,
218
            CoapRequestCode::Post => &mut self.post,
219
            CoapRequestCode::Fetch => &mut self.fetch,
220
            CoapRequestCode::IPatch => &mut self.ipatch,
221
            CoapRequestCode::Patch => &mut self.patch,
222
        }
223
75
    }
224
}
225

            
226
/// Inner part of a [CoapResource], which is referenced inside the raw resource and might be
227
/// referenced multiple times, e.g. outside and inside of a resource handler.
228
#[derive(Debug)]
229
pub(crate) struct CoapResourceInner<D: Any + ?Sized + Debug> {
230
    raw_resource: *mut coap_resource_t,
231
    user_data: Box<D>,
232
    handlers: CoapResourceHandlers<D>,
233
}
234

            
235
impl<D: Any + ?Sized + Debug> CoapResource<D> {
236
    /// Creates a new CoapResource for the given `uri_path`.
237
    ///
238
    /// Handlers that are associated with this resource have to be able to take a reference to the
239
    /// provided `user_data` value as their first value.
240
    ///
241
    /// The `notify_con` parameter specifies whether observe notifications originating from this
242
    /// resource are sent as confirmable or non-confirmable.
243
25
    pub fn new<C: Into<Box<D>>>(uri_path: &str, user_data: C, notify_con: bool) -> CoapResource<D> {
244
25
        ensure_coap_started();
245
25
        let inner = unsafe {
246
25
            let uri_path = coap_new_str_const(uri_path.as_ptr(), uri_path.len());
247
25
            let raw_resource = coap_resource_init(
248
25
                uri_path,
249
25
                (COAP_RESOURCE_FLAGS_RELEASE_URI
250
25
                    | if notify_con {
251
                        COAP_RESOURCE_FLAGS_NOTIFY_CON
252
                    } else {
253
25
                        COAP_RESOURCE_FLAGS_NOTIFY_NON
254
                    }) as i32,
255
            );
256
25
            let inner = CoapFfiRcCell::new(CoapResourceInner {
257
25
                raw_resource,
258
25
                user_data: user_data.into(),
259
25
                handlers: CoapResourceHandlers::default(),
260
25
            });
261
25
            coap_resource_set_userdata(raw_resource, inner.create_raw_weak());
262
25
            inner
263
25
        };
264
25
        Self::from(inner)
265
25
    }
266

            
267
    /// Notify any observers about changes to this resource.
268
    pub fn notify_observers(&self) -> bool {
269
        // SAFETY: Resource is valid as long as CoapResourceInner exists, query is currently unused.
270
        unsafe { coap_resource_notify_observers(self.inner.borrow_mut().raw_resource, std::ptr::null_mut()) != 0 }
271
    }
272

            
273
    /// Sets whether this resource can be observed by clients according to
274
    /// [RFC 7641](https://datatracker.ietf.org/doc/html/rfc7641).
275
    pub fn set_get_observable(&self, observable: bool) {
276
        // SAFETY: Resource is valid as long as CoapResourceInner exists, query is currently unused.
277
        unsafe { coap_resource_set_get_observable(self.inner.borrow_mut().raw_resource, observable as c_int) }
278
    }
279

            
280
    /// Sets whether observe notifications for this resource should be sent as confirmable or
281
    /// non-confirmable CoAP messages.
282
    pub fn set_observe_notify_confirmable(&self, confirmable: bool) {
283
        // SAFETY: Resource is valid as long as CoapResourceInner exists, query is currently unused.
284
        unsafe { coap_resource_set_mode(self.inner.borrow_mut().raw_resource, confirmable as c_int) }
285
    }
286

            
287
    /// Returns the user data associated with this resource.
288
    pub fn user_data(&self) -> Ref<D> {
289
        Ref::map(self.inner.borrow(), |v| v.user_data.as_ref())
290
    }
291

            
292
    /// Mutably returns the user data associated with this resource.
293
25
    pub fn user_data_mut(&self) -> RefMut<D> {
294
25
        RefMut::map(self.inner.borrow_mut(), |v| v.user_data.as_mut())
295
25
    }
296

            
297
    /// Restores a resource from its raw [coap_resource_t](libcoap_sys::coap_resource_t).
298
    ///
299
    /// # Safety
300
    /// The supplied pointer must point to a valid [coap_resource_t](libcoap_sys::coap_resource_t)
301
    /// instance that has a `Rc<RefCell<CoapResourceInner<D>>>` as its user data.
302
    pub unsafe fn restore_from_raw(raw_resource: *mut coap_resource_t) -> CoapResource<D> {
303
        let resource_tmp = CoapFfiRcCell::clone_raw_weak(coap_resource_get_userdata(raw_resource));
304
        CoapResource::from(resource_tmp)
305
    }
306

            
307
    /// Sets the handler function for a given method code.
308
25
    pub fn set_method_handler<H: Into<CoapRequestHandler<D>>>(&self, code: CoapRequestCode, handler: Option<H>) {
309
25
        let mut inner = self.inner.borrow_mut();
310
25
        *inner.handlers.handler_ref_mut(code) = handler.map(|v| v.into());
311
25
        unsafe {
312
25
            coap_register_request_handler(
313
25
                inner.raw_resource,
314
25
                code.to_raw_request(),
315
25
                inner.handlers.handler(code).map(|h| h.raw_handler),
316
25
            );
317
25
        }
318
25
    }
319

            
320
25
    fn call_dynamic_handler(
321
25
        &self,
322
25
        session: &mut CoapServerSession,
323
25
        req_message: &CoapRequest,
324
25
        mut rsp_message: CoapResponse,
325
25
    ) {
326
25
        let mut inner = self.inner.borrow_mut();
327
25
        let req_code = match req_message.code() {
328
25
            CoapMessageCode::Request(req_code) => req_code,
329
            _ => {
330
                rsp_message.set_type_(CoapMessageType::Rst);
331
                // TODO some better error handling
332
                session.send(rsp_message).expect("error while sending RST packet");
333
                return;
334
            },
335
        };
336

            
337
        // Take handler function out of resource handler so that we no longer need the inner borrow
338
        // (otherwise, we couldn't call any resource functions in the handler).
339
25
        let mut handler_fn = inner
340
25
            .handlers
341
25
            .handler_ref_mut(req_code)
342
25
            .take()
343
25
            .expect("attempted to call dynamic handler for method that has no handler set");
344
25
        std::mem::drop(inner);
345
25

            
346
25
        (handler_fn
347
25
            .dynamic_handler_function
348
25
            .as_mut()
349
25
            .expect("attempted to call dynamic handler for method that has no dynamic handler set"))(
350
25
            self,
351
25
            session,
352
25
            req_message,
353
25
            rsp_message,
354
25
        );
355
25

            
356
25
        // Put the handler function back into the resource, unless the handler was replaced.
357
25
        self.inner
358
25
            .borrow_mut()
359
25
            .handlers
360
25
            .handler_ref_mut(req_code)
361
25
            .get_or_insert(handler_fn);
362
25
    }
363
}
364

            
365
impl<D: Any + ?Sized + Debug> UntypedCoapResource for CoapResource<D> {
366
    fn uri_path(&self) -> &str {
367
        unsafe {
368
            let raw_path = coap_resource_get_uri_path(self.inner.borrow().raw_resource);
369
            return std::str::from_utf8_unchecked(std::slice::from_raw_parts((*raw_path).s, (*raw_path).length));
370
        }
371
    }
372

            
373
    fn as_any(&self) -> &dyn Any {
374
        self as &(dyn Any)
375
    }
376

            
377
25
    fn drop_inner_exclusive(self: Box<Self>) {
378
25
        self.inner.drop_exclusively();
379
25
    }
380

            
381
25
    unsafe fn raw_resource(&mut self) -> *mut coap_resource_t {
382
25
        self.inner.borrow_mut().raw_resource
383
25
    }
384
}
385

            
386
#[doc(hidden)]
387
impl<D: Any + ?Sized + Debug> From<CoapFfiRcCell<CoapResourceInner<D>>> for CoapResource<D> {
388
50
    fn from(raw_cell: CoapFfiRcCell<CoapResourceInner<D>>) -> Self {
389
50
        CoapResource { inner: raw_cell }
390
50
    }
391
}
392

            
393
impl<D: Any + ?Sized + Debug> Drop for CoapResourceInner<D> {
394
25
    fn drop(&mut self) {
395
25
        // SAFETY: We set the user data on creation of the inner resource, so it cannot be invalid.
396
25
        std::mem::drop(unsafe {
397
25
            CoapFfiRcCell::<CoapResourceInner<D>>::raw_ptr_to_weak(coap_resource_get_userdata(self.raw_resource))
398
25
        });
399
25
        // SAFETY: First argument is ignored, second argument is guaranteed to exist while the inner
400
25
        // resource exists.
401
25
        unsafe { coap_delete_resource(std::ptr::null_mut(), self.raw_resource) };
402
25
    }
403
}
404

            
405
/// A handler for CoAP requests on a resource.
406
///
407
/// This handler can be associated with a [CoapResource] in order to be called when a request for
408
/// the associated resource and the provided method arrives. The handler is then able to generate
409
/// and send a response to the request accordingly.
410
///
411
/// # Creating a CoapRequestHandler
412
/// There are multiple ways to create a [CoapRequestHandler]:
413
/// - Using the [resource_handler!] macro: Preferred for handlers with a static lifetime (i.e.,
414
///   function pointers, not closures).
415
/// - Using [CoapRequestHandler::new]: Preferred for closures if you don't need access to the
416
///   [CoapResource] itself (but can be used for function pointers as well).
417
/// - Using [CoapRequestHandler::new_resource_ref]: Preferred for closures if you need access to
418
///   the [CoapResource] itself (but can be used for function pointers as well).
419
///
420
/// For method 2, the provided handler has to be a `FnMut(&mut D, &mut CoapServerSession, &CoapRequest, CoapResponse)`,
421
/// while for the other two methods, the handler has to be a `FnMut(&CoapResource<D>, &mut CoapServerSession, &CoapRequest, CoapResponse)`,
422
/// with the following arguments:
423
/// - Either the associated [CoapResource] or the user data depending on the type of handler.
424
///   Getting the user data directly without the associated resource has the advantage that it is
425
///   easy to pass a method as a handler, while getting the [CoapResource] gives you the option to
426
///   manipulate the resource (you can still get the user data from the resource using
427
///   [CoapResource::user_data].
428
/// - The server-side session with the peer this request was received from. You may want to store or
429
///   retrieve additional information about the peer using [CoapSessionCommon::set_app_data()] and
430
///   [CoapSessionCommon::app_data()].
431
/// - The incoming [CoapRequest] received from the client.
432
/// - A prepared [CoapResponse] instance that is already set to the correct token value to be
433
///   treated as a response to the request by the client.
434
// We'll allow the complex type as trait aliases are experimental and we'll probably want to use
435
// those instead of aliasing the entire type including wrappers.
436
#[allow(clippy::type_complexity)]
437
pub struct CoapRequestHandler<D: Any + ?Sized + Debug> {
438
    raw_handler: unsafe extern "C" fn(
439
        resource: *mut coap_resource_t,
440
        session: *mut coap_session_t,
441
        incoming_pdu: *const coap_pdu_t,
442
        query: *const coap_string_t,
443
        response_pdu: *mut coap_pdu_t,
444
    ),
445
    dynamic_handler_function:
446
        Option<Box<dyn FnMut(&CoapResource<D>, &mut CoapServerSession, &CoapRequest, CoapResponse)>>,
447
    __handler_data_type: PhantomData<D>,
448
}
449

            
450
impl<D: 'static + ?Sized + Debug> CoapRequestHandler<D> {
451
    /// Creates a new CoapResourceHandler with the given function as the handler function to call.
452
25
    pub fn new<F: 'static + FnMut(&mut D, &mut CoapServerSession, &CoapRequest, CoapResponse)>(
453
25
        mut handler: F,
454
25
    ) -> CoapRequestHandler<D> {
455
25
        CoapRequestHandler::new_resource_ref(move |resource, session, request, response| {
456
25
            handler(&mut *resource.user_data_mut(), session, request, response)
457
25
        })
458
25
    }
459

            
460
    /// Creates a new CoapResourceHandler with the given function as the handler function to call.
461
    ///
462
    /// In contrast to [CoapRequestHandler::new], the handler for this function is not provided with
463
    /// a direct reference to the user data, but instead with a reference to the associated
464
    /// `CoapResource`. This way, you can perform actions on the resource directly (e.g., notify
465
    /// observers).
466
25
    pub fn new_resource_ref<
467
25
        F: 'static + FnMut(&CoapResource<D>, &mut CoapServerSession, &CoapRequest, CoapResponse),
468
25
    >(
469
25
        handler: F,
470
25
    ) -> CoapRequestHandler<D> {
471
25
        let mut wrapped_handler = resource_handler!(coap_resource_handler_dynamic_wrapper, D);
472
25
        wrapped_handler.dynamic_handler_function = Some(Box::new(handler));
473
25
        wrapped_handler
474
25
    }
475

            
476
    /// Creates a new request handler using the given raw handler function.
477
    ///
478
    /// The handler function provided here is called directly by libcoap.
479
    ///
480
    /// # Safety
481
    /// The handler function must not modify the user data value inside of the provided raw resource
482
    /// in a way that would break normal handler functions. Also, neither the resource nor the
483
    /// session may be freed by calling `coap_delete_resource` or `coap_session_release`.
484
    // We'll allow the complex type as trait aliases are experimental and we'll probably want to use
485
    // those instead of aliasing the entire type including wrappers.
486
    #[allow(clippy::type_complexity)]
487
25
    pub unsafe fn from_raw_handler(
488
25
        raw_handler: unsafe extern "C" fn(
489
25
            resource: *mut coap_resource_t,
490
25
            session: *mut coap_session_t,
491
25
            incoming_pdu: *const coap_pdu_t,
492
25
            query: *const coap_string_t,
493
25
            response_pdu: *mut coap_pdu_t,
494
25
        ),
495
25
    ) -> CoapRequestHandler<D> {
496
25
        ensure_coap_started();
497
25
        let handler_fn: Option<Box<dyn FnMut(&CoapResource<D>, &mut CoapServerSession, &CoapRequest, CoapResponse)>> =
498
25
            None;
499
25
        CoapRequestHandler {
500
25
            raw_handler,
501
25
            dynamic_handler_function: handler_fn,
502
25
            __handler_data_type: PhantomData,
503
25
        }
504
25
    }
505
}
506

            
507
impl<D: 'static + ?Sized + Debug> Debug for CoapRequestHandler<D> {
508
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
509
        f.debug_struct("CoapRequestHandler").finish()
510
    }
511
}
512

            
513
25
fn coap_resource_handler_dynamic_wrapper<D: Any + ?Sized + Debug>(
514
25
    resource: &CoapResource<D>,
515
25
    session: &mut CoapServerSession,
516
25
    req_message: &CoapRequest,
517
25
    rsp_message: CoapResponse,
518
25
) {
519
25
    resource.call_dynamic_handler(session, req_message, rsp_message);
520
25
}