1
// SPDX-License-Identifier: BSD-2-Clause
2
/*
3
 * Copyright © The libcoap-rs Contributors, all rights reserved.
4
 * This file is part of the libcoap-rs project, see the README file for
5
 * general information on this project and the NOTICE.md and LICENSE files
6
 * for information regarding copyright ownership and terms of use.
7
 *
8
 * resource.rs - Types relating to CoAP resource management.
9
 */
10

            
11
//! Resource and resource handler descriptions
12

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

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

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

            
37
// Trait aliases are experimental
38
//trait CoapMethodHandlerFn<D> = FnMut(&D, &mut CoapSession, &CoapRequestMessage, &mut CoapResponseMessage);
39

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
370
    fn as_any(&self) -> &dyn Any {
371
        self as &(dyn Any)
372
    }
373

            
374
25
    fn drop_inner_exclusive(self: Box<Self>) {
375
25
        self.inner.drop_exclusively();
376
25
    }
377

            
378
25
    unsafe fn raw_resource(&mut self) -> *mut coap_resource_t {
379
25
        self.inner.borrow_mut().raw_resource
380
25
    }
381
}
382

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

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

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

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

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

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

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

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