1
// SPDX-License-Identifier: BSD-2-Clause
2
/*
3
 * mem.rs - Memory handling helper structs and traits for the libcoap Rust Wrapper.
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
//! Code related to memory handling, especially for passing objects through FFI
11

            
12
use std::cell::{Ref, RefCell, RefMut};
13
use std::ffi::c_void;
14
use std::fmt::{Debug, Formatter};
15
use std::ops::{Deref, DerefMut};
16
use std::rc::{Rc, Weak};
17

            
18
/// Trait implemented by libcoap wrapper structs that contain an inner value that may be dropped
19
/// exclusively, i.e., that can be dropped with the additional check that there are no further
20
/// references to the inner value.
21
pub(crate) trait DropInnerExclusively {
22
    /// Consume this instance, ensuring that the inner (and potentially shared) part of the struct
23
    /// referenced by this instance is also dropped.
24
    ///
25
    /// # Panics
26
    ///
27
    /// Panics if the inner part of this struct cannot be exclusively dropped, i.e., it is still
28
    /// used by another instance.
29
    fn drop_exclusively(self);
30
}
31

            
32
/// A strong reference counted cell, created from an app data/user data pointer inside of a C
33
/// library struct.
34
///
35
/// This type is a wrapper around Rc<RefCell<D>> with some additional functions for creating from
36
/// or converting to raw pointers.
37
pub(crate) struct CoapFfiRcCell<D>(Rc<RefCell<D>>);
38

            
39
impl<D> CoapFfiRcCell<D> {
40
    /// Creates a new instance of CoapFfiRcCell, containing the provided value.
41
526
    pub fn new(value: D) -> CoapFfiRcCell<D> {
42
526
        CoapFfiRcCell(Rc::new(RefCell::new(value)))
43
526
    }
44

            
45
    /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
46
    /// into the appropriate reference type.
47
    ///
48
    /// This is done by first restoring the `Rc<RefCell<D>>` using [Rc::from_raw()], then
49
    /// cloning and creating the [CoapFfiRcCell] from it (maintaining the original reference using
50
    /// [Rc::into_raw()]).
51
    ///
52
    /// Note that for the lifetime of this [CoapFfiRcCell], the reference counter of the
53
    /// underlying [Rc] is increased by one.
54
    ///
55
    /// # Safety
56
    /// For an explanation of the purpose of this struct and where it was originally intended to be
57
    /// used, see the struct-level documentation.
58
    ///
59
    /// To safely use this function, the following invariants must be kept:
60
    /// - ptr is a valid pointer to an Rc<RefCell<D>>
61
757
    pub unsafe fn clone_raw_rc(ptr: *mut c_void) -> CoapFfiRcCell<D> {
62
757
        let orig_ref = Rc::from_raw(ptr as *const RefCell<D>);
63
757
        let new_ref = Rc::clone(&orig_ref);
64
757
        // Pointer should not have changed, so we don't need to use the returned value.
65
757
        let _ = Rc::into_raw(orig_ref);
66
757
        CoapFfiRcCell(new_ref)
67
757
    }
68

            
69
    /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
70
    /// into the appropriate reference type.
71
    ///
72
    /// This is done by first restoring the `Weak<RefCell<D>>` using [Weak::from_raw()],
73
    /// upgrading it to a `Rc<RefCell<D>>` then cloning and creating the [CoapFfiRcCell] from the
74
    /// upgraded reference (restoring the raw pointer again afterwards using [Rc::downgrade()] and
75
    /// [Weak::into_raw()]).
76
    ///
77
    /// Note that for the lifetime of this [CoapFfiRcCell], the reference counter of the underlying
78
    /// [Rc] is increased by one.
79
    ///
80
    /// # Panics
81
    /// Panics if the provided Weak reference is orphaned.
82
    ///
83
    /// # Safety
84
    /// For an explanation of the purpose of this struct and where it was originally intended to be
85
    /// used, see the struct-level documentation.
86
    ///
87
    /// To safely use this function, the following invariants must be kept:
88
    /// - ptr is a valid pointer to a `Weak<RefCell<D>>`
89
25
    pub unsafe fn clone_raw_weak(ptr: *mut c_void) -> CoapFfiRcCell<D> {
90
25
        let orig_ref = Weak::from_raw(ptr as *const RefCell<D>);
91
25
        let new_ref = Weak::upgrade(&orig_ref).expect("attempted to upgrade a weak reference that was orphaned");
92
25
        let _weakref = Weak::into_raw(orig_ref);
93
25
        CoapFfiRcCell(new_ref)
94
25
    }
95

            
96
    /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
97
    /// into the underlying `Weak<RefCell<D>>`.
98
    ///
99
    /// This is done by restoring the `Weak<RefCell<D>>` using [Weak::from_raw()],
100
    ///
101
    /// Note that unlike [CoapFfiRcCell::clone_raw_weak()], this does not clone the weak reference
102
    /// inside of the pointer and instead restores the `Weak` directly from the pointer.
103
    /// This means that dropping the `Weak` returned from this function invalidates the pointer
104
    /// provided to this function.
105
    ///
106
    /// # Panics
107
    /// Panics if the provided Weak reference is orphaned.
108
    ///
109
    /// # Safety
110
    /// For an explanation of the purpose of this struct and where it was originally intended to be
111
    /// used, see the struct-level documentation.
112
    ///
113
    /// To safely use this function, the following invariants must be kept:
114
    /// - ptr is a valid pointer to a `Weak<RefCell<D>>`
115
    /// - as soon as the returned `Weak<RefCell<D>>` is dropped, the provided pointer is treated as
116
    ///   invalid.
117
526
    pub unsafe fn raw_ptr_to_weak(ptr: *mut c_void) -> Weak<RefCell<D>> {
118
526
        Weak::from_raw(ptr as *const RefCell<D>)
119
526
    }
120

            
121
    /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
122
    /// into the underlying `Rc<RefCell<D>>`.
123
    ///
124
    /// This is done by restoring the `Rc<RefCell<D>>` using [Rc::from_raw()],
125
    ///
126
    /// Note that unlike [CoapFfiRcCell::clone_raw_rc()], this does not clone the weak reference
127
    /// inside of the pointer and instead restores the `Rc` directly from the pointer.
128
    /// This means that dropping the `Rc` returned from this function invalidates the pointer
129
    /// provided to this function and that the provided pointer must point to a valid
130
    /// `Rc<RefCell<D>>`.
131
    ///
132
    /// # Panics
133
    /// Panics if the provided Weak reference is orphaned.
134
    ///
135
    /// # Safety
136
    /// For an explanation of the purpose of this struct and where it was originally intended to be
137
    /// used, see the struct-level documentation.
138
    ///
139
    /// To safely use this function, the following invariants must be kept:
140
    /// - ptr is a valid pointer to a `Rc<RefCell<D>>`
141
    /// - as soon as the returned `Rc<RefCell<D>>` is dropped, the provided pointer is treated as
142
    ///   invalid.
143
    // Kept for consistency
144
    #[allow(unused)]
145
    pub unsafe fn raw_ptr_to_rc(ptr: *mut c_void) -> Rc<RefCell<D>> {
146
        Rc::from_raw(ptr as *const RefCell<D>)
147
    }
148

            
149
    /// Creates a raw reference, suitable for storage inside of a libcoap C library user/application
150
    /// data pointer.
151
    ///
152
    /// This function internally calls [Rc::clone()] and then [Rc::into_raw()] to create a pointer
153
    /// referring to a clone of the `Rc<RefCell<D>>` contained in this type.
154
    ///
155
    /// Note that this increases the reference count of the Rc by one.
156
    // Kept for consistency
157
    #[allow(unused)]
158
    pub fn create_raw_rc(&self) -> *mut c_void {
159
        Rc::into_raw(Rc::clone(&self.0)) as *mut c_void
160
    }
161

            
162
    /// Creates a raw reference, suitable for storage inside of a libcoap C library user/application
163
    /// data pointer.
164
    ///
165
    /// This function internally calls [Rc::downgrade()] and then [Weak::into_raw()] to create a
166
    /// pointer referring to a weak reference of the `Rc<RefCell<D>>` contained in this type.
167
    ///
168
    /// Note that this does not increase the reference count of the [Rc] by one. If you want to
169
    /// ensure that the underlying D is never cleaned up for as long as this pointer exists, you
170
    /// need to maintain this object for as least as long as the reference.
171
526
    pub fn create_raw_weak(&self) -> *mut c_void {
172
526
        Weak::into_raw(Rc::downgrade(&self.0)) as *mut c_void
173
526
    }
174

            
175
    /// Creates an immutable reference to the contained data type.
176
    ///
177
    /// # Panics
178
    /// Panics if borrowing here would violate Rusts aliasing rules.
179
1165
    pub fn borrow(&self) -> Ref<D> {
180
1165
        RefCell::borrow(&self.0)
181
1165
    }
182

            
183
    /// Creates a mutable reference to the contained data type.
184
    ///
185
    /// # Panics
186
    /// Panics if borrowing mutably here would violate Rusts aliasing rules.
187
3164
    pub fn borrow_mut(&self) -> RefMut<D> {
188
3164
        RefCell::borrow_mut(&self.0)
189
3164
    }
190
}
191

            
192
impl<D: PartialEq> PartialEq for CoapFfiRcCell<D> {
193
    fn eq(&self, other: &Self) -> bool {
194
        Rc::eq(&self.0, &other.0)
195
    }
196
}
197

            
198
impl<D: Eq + PartialEq> Eq for CoapFfiRcCell<D> {}
199

            
200
impl<D> Clone for CoapFfiRcCell<D> {
201
233
    fn clone(&self) -> Self {
202
233
        CoapFfiRcCell(self.0.clone())
203
233
    }
204
}
205

            
206
impl<D: Debug> Debug for CoapFfiRcCell<D> {
207
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
208
        f.debug_struct("CoapFfiRcCell").field("0", &self.0).finish()
209
    }
210
}
211

            
212
impl<T: Debug> DropInnerExclusively for CoapFfiRcCell<T> {
213
258
    fn drop_exclusively(self) {
214
258
        std::mem::drop(
215
258
            Rc::try_unwrap(self.0).expect("unable to unwrap instance of CoapFfiRcCell as it is still in use"),
216
258
        )
217
258
    }
218
}
219

            
220
/// A reference counted cell suitable for passing through the FFI barrier, with the additional
221
/// possibility of passing an existing reference through this barrier.
222
///
223
/// This struct is similar to [CoapFfiRcCell], but provides additional functionality for
224
/// maintaining a reference through the FFI barrier using the [lend()] function.
225
#[derive(Debug)]
226
pub(crate) struct CoapLendableFfiRcCell<T: Debug>(Rc<RefCell<T>>, Rc<RefCell<Option<*mut T>>>);
227

            
228
impl<T: Debug> CoapLendableFfiRcCell<T> {
229
    /// Creates a new [`CoapLendableFfiRcCell`] from the given value.
230
466
    pub fn new(value: T) -> CoapLendableFfiRcCell<T> {
231
466
        CoapLendableFfiRcCell(Rc::new(RefCell::new(value)), Rc::new(RefCell::new(None)))
232
466
    }
233

            
234
    /// Mutably borrows from the value in this cell.
235
    ///
236
    /// This function will first check if a reference was lent through the FFI barrier using a call
237
    /// to [lend()].
238
    /// If so, it will take that reference (and return it to the cell when the returned
239
    /// [CoapLendableFfiRef] goes out of scope).
240
    /// If not, it will borrow the value normally by calling [Rc::borrow()] on the contained value.
241
    ///
242
    /// # Panics
243
    /// Panics if the value was already mutably borrowed.
244
3877
    pub fn borrow_mut(&self) -> CoapLendableFfiRefMut<'_, T> {
245
3877
        if let Some(borrowed) = RefCell::borrow_mut(&self.1).take() {
246
            // SAFETY: The aliasing rules are ensured here by making sure that only one person may
247
            // retrieve the pointer value stored in the container at any time (as the value in the
248
            // Option is always retrieved using _take()_.
249
            // The validity of the pointer is ensured because the only way a value can be stored
250
            // here is by calling CoapLendableFfiRcCell::lend_ref_mut(), which converts a
251
            // reference into an always valid pointer.
252
489
            CoapLendableFfiRefMut::Borrowed(unsafe { borrowed.as_mut() }.unwrap(), Rc::clone(&self.1))
253
        } else {
254
3388
            CoapLendableFfiRefMut::Owned(RefCell::borrow_mut(&self.0))
255
        }
256
3877
    }
257

            
258
    /// Immutably borrows from the value in this cell.
259
    ///
260
    /// This function will first check if a reference was lent through the FFI barrier using a call
261
    /// to [lend()].
262
    /// If so, it will take that reference (and return it to the cell when the returned
263
    /// [CoapLendableFfiRef] goes out of scope).
264
    /// If not, it will borrow the value normally by calling [Rc::borrow()] on the contained value.
265
    ///
266
    /// # Panics
267
    /// Panics if the value was already mutably borrowed.
268
248
    pub fn borrow(&self) -> CoapLendableFfiRef<'_, T> {
269
248
        if let Some(borrowed) = RefCell::borrow_mut(&self.1).take() {
270
            // SAFETY: The aliasing rules are ensured here by making sure that only one person may
271
            // retrieve the pointer value stored in the container at any time (as the value in the
272
            // Option is always retrieved using _take()_.
273
            // The validity of the pointer is ensured because the only way a value can be stored
274
            // here is by calling CoapLendableFfiRcCell::lend_ref_mut(), which converts a
275
            // reference into an always valid pointer.
276
            // TODO we may want to allow multiple immutable borrows at some point(?)
277
            CoapLendableFfiRef::Borrowed(unsafe { borrowed.as_mut() }.unwrap(), Rc::clone(&self.1))
278
        } else {
279
248
            CoapLendableFfiRef::Owned(RefCell::borrow(&self.0))
280
        }
281
248
    }
282

            
283
    /// Create a raw pointer to this cell, suitable for storage in a libcoap application data
284
    /// pointer.
285
    ///
286
    /// Internally, this function creates a clone of this cell, wraps this cell in a `Box` and then
287
    /// converts this value into a pointer using [Box::into_raw].
288
    ///
289
    /// It is in the callers responsibility to free the memory associated with this `Box`, e.g., by
290
    /// calling [from_raw_box()] and then dropping the value.
291
    // Kept for consistency
292
    #[allow(unused)]
293
    pub fn create_raw_rc_box(&self) -> *mut CoapLendableFfiRcCell<T> {
294
        Box::into_raw(Box::new(CoapLendableFfiRcCell::<T>::clone(self)))
295
    }
296

            
297
    /// Create a raw pointer to this cell, suitable for storage in a libcoap application data
298
    /// pointer.
299
    ///
300
    /// Internally, this function creates a weak clone of this cell, wraps this cell in a `Box` and
301
    /// then converts this value into a pointer using [Box::into_raw].
302
    ///
303
    /// It is in the callers responsibility to free the memory associated with this `Box`, e.g., by
304
    /// calling [CoapLendableFfiWeakCell::from_raw_box()] and then dropping the value.
305
466
    pub fn create_raw_weak_box(&self) -> *mut CoapLendableFfiWeakCell<T> {
306
466
        Box::into_raw(Box::new(self.downgrade()))
307
466
    }
308

            
309
    /// Creates a new instance of this struct by cloning from a raw pointer pointing to a
310
    /// `Box<CoapLendableFfiRcCell<T>`.
311
    ///
312
    /// # Safety
313
    /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiRcCell<T>`.
314
    // Kept for consistency
315
    #[allow(unused)]
316
    pub unsafe fn clone_raw_rc_box(ptr: *mut CoapLendableFfiRcCell<T>) -> CoapLendableFfiRcCell<T> {
317
        let ref_box: Box<CoapLendableFfiRcCell<T>> = Box::from_raw(ptr);
318
        let ret_val = CoapLendableFfiRcCell::<T>::clone(ref_box.as_ref());
319
        Box::into_raw(ref_box);
320
        ret_val
321
    }
322

            
323
    /// Creates a new instance of this struct by cloning from a raw pointer pointing to a
324
    /// `Box<CoapLendableFfiWeakCell<T>`.
325
    ///
326
    /// # Panics
327
    /// Panics if the provided weak cell is orphaned.
328
    ///
329
    /// # Safety
330
    /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiWeakCell<T>`.
331
559
    pub unsafe fn clone_raw_weak_box(ptr: *mut CoapLendableFfiWeakCell<T>) -> CoapLendableFfiRcCell<T> {
332
559
        let ref_box: Box<CoapLendableFfiWeakCell<T>> = Box::from_raw(ptr);
333
559
        let ret_val = ref_box
334
559
            .upgrade()
335
559
            .expect("unable to restore CoapLendableFfiRcCell as the underlying value was already dropped");
336
559
        assert_eq!(Box::into_raw(ref_box), ptr);
337
559
        ret_val
338
559
    }
339

            
340
    /// Restores a `Box<CoapLendableFfiRcCell<T>>` from a raw pointer.
341
    ///
342
    /// Note that unlike [clone_raw_rc_box()], this function does not create a clone but directly
343
    /// restores the underlying provided box.
344
    /// As soon as the returned value is dropped, the provided pointer is therefore invalid.
345
    ///
346
    /// # Safety
347
    /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiRcCell<T>`.
348
    // Kept for consistency
349
    #[allow(unused)]
350
    pub unsafe fn from_raw_rc_box(ptr: *mut CoapLendableFfiRcCell<T>) -> Box<CoapLendableFfiRcCell<T>> {
351
        Box::from_raw(ptr)
352
    }
353

            
354
    /// Stores a mutable reference to an instance of T for later retrieval by code running on the
355
    /// other side of the FFI barrier.
356
    ///
357
    /// This function can be used to pass a previously borrowed value to other users of this cell
358
    /// through the FFI barrier _without_ intermittently releasing the borrow.
359
    ///
360
    /// The reference will be lent for as long as the returned [CoapLendableFfiRefLender<'a, T>] is
361
    /// not dropped.
362
1990
    pub fn lend_ref_mut<'a>(&self, refer: &'a mut T) -> CoapLendableFfiRefLender<'a, T> {
363
1990
        assert_eq!(
364
1990
            RefCell::as_ptr(&self.0),
365
1990
            refer as *mut T,
366
            "attempted to lend different object over CoapLendableFfiRcCell"
367
        );
368
1990
        CoapLendableFfiRefLender::new(refer, &self.1)
369
1990
    }
370

            
371
    /// Creates a weak version of this reference counted cell by downgrading its components.
372
466
    pub fn downgrade(&self) -> CoapLendableFfiWeakCell<T> {
373
466
        CoapLendableFfiWeakCell(Rc::downgrade(&self.0), Rc::downgrade(&self.1))
374
466
    }
375
}
376

            
377
impl<T: Debug> Clone for CoapLendableFfiRcCell<T> {
378
    fn clone(&self) -> Self {
379
        CoapLendableFfiRcCell(Rc::clone(&self.0), Rc::clone(&self.1))
380
    }
381
}
382

            
383
/// The weak variant of a [CoapLendableFfiRcCell].
384
#[derive(Debug)]
385
pub(crate) struct CoapLendableFfiWeakCell<T: Debug>(Weak<RefCell<T>>, Weak<RefCell<Option<*mut T>>>);
386

            
387
impl<T: Debug> Clone for CoapLendableFfiWeakCell<T> {
388
    fn clone(&self) -> Self {
389
        CoapLendableFfiWeakCell(Weak::clone(&self.0), Weak::clone(&self.1))
390
    }
391
}
392

            
393
impl<T: Debug> CoapLendableFfiWeakCell<T> {
394
    /// Attempts to upgrade this weak cell into a full [CoapLendableFfiRcCell<T>], returning None
395
    /// if the underlying value was already dropped.
396
559
    pub fn upgrade(&self) -> Option<CoapLendableFfiRcCell<T>> {
397
559
        self.0
398
559
            .upgrade()
399
559
            .zip(self.1.upgrade())
400
559
            .map(|(v0, v1)| CoapLendableFfiRcCell(v0, v1))
401
559
    }
402

            
403
    /// Restores a `Box<CoapLendableFfiWeakCell<T>>` from a raw pointer.
404
    ///
405
    /// Note that unlike [CoapLendableFfiRcCell<T>::clone_raw_weak_box()], this function does not
406
    /// create a clone but directly restores the underlying provided box.
407
    /// As soon as the returned value is dropped, the provided pointer is therefore invalid.
408
    ///
409
    /// # Safety
410
    /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiWeakCell<T>`.
411
466
    pub unsafe fn from_raw_box(ptr: *mut CoapLendableFfiWeakCell<T>) -> Box<CoapLendableFfiWeakCell<T>> {
412
466
        Box::from_raw(ptr)
413
466
    }
414
}
415

            
416
/// A token that is held by the lender of a mutable reference.
417
///
418
/// As long as this token is held, the mutable reference provided to [CoapLendableFfiRcCell] can be
419
/// borrowed by other functions owning clones of the same [CoapLendableFfiRcCell].
420
///
421
/// When this value is dropped, it will check whether the lent reference is currently used
422
/// elsewhere and panic/abort if this is the case, as this would violate the Rust aliasing rules.
423
pub(crate) struct CoapLendableFfiRefLender<'a, T> {
424
    lent_ref: &'a mut T,
425
    lent_ptr_ctr: Weak<RefCell<Option<*mut T>>>,
426
}
427

            
428
impl<'a, T> CoapLendableFfiRefLender<'a, T> {
429
    /// Create a new lender token from the given reference.
430
1990
    fn new(refer: &'a mut T, container: &Rc<RefCell<Option<*mut T>>>) -> CoapLendableFfiRefLender<'a, T> {
431
1990
        RefCell::borrow_mut(container).replace(refer as *mut T);
432
1990
        CoapLendableFfiRefLender {
433
1990
            lent_ref: refer,
434
1990
            lent_ptr_ctr: Rc::downgrade(container),
435
1990
        }
436
1990
    }
437

            
438
1990
    pub(crate) fn unlend(self) {
439
1990
        std::mem::drop(self);
440
1990
    }
441
}
442

            
443
impl<T> Drop for CoapLendableFfiRefLender<'_, T> {
444
1990
    fn drop(&mut self) {
445
1990
        if let Some(lent_ptr_ctr) = self.lent_ptr_ctr.upgrade() {
446
1990
            assert_eq!(
447
1990
                self.lent_ref as *mut T,
448
1990
                lent_ptr_ctr
449
1990
                    .take()
450
1990
                    .expect("unable to retrieve lent reference, implying that it may be in use somewhere"),
451
                "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
452
            )
453
        }
454
1990
    }
455
}
456

            
457
/// A non-mutable reference created by borrowing mutably from a [CoapFfiRcCell] using
458
/// [CoapFfiRcCell::borrow_mut()].
459
pub(crate) enum CoapLendableFfiRef<'a, T> {
460
    Owned(Ref<'a, T>),
461
    Borrowed(&'a mut T, Rc<RefCell<Option<*mut T>>>),
462
}
463

            
464
impl<T> Deref for CoapLendableFfiRef<'_, T> {
465
    type Target = T;
466

            
467
248
    fn deref(&self) -> &Self::Target {
468
248
        match self {
469
248
            CoapLendableFfiRef::Owned(v) => v.deref(),
470
            CoapLendableFfiRef::Borrowed(v, _lend_container) => v,
471
        }
472
248
    }
473
}
474

            
475
impl<T> Drop for CoapLendableFfiRef<'_, T> {
476
248
    fn drop(&mut self) {
477
248
        if let CoapLendableFfiRef::Borrowed(refer, lend_container) = self {
478
            let mut lend_container = RefCell::borrow_mut(lend_container);
479
            assert!(
480
                lend_container.is_none(),
481
                "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
482
            );
483
            assert!(
484
                lend_container.replace(*refer).is_none(),
485
                "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
486
            );
487
248
        }
488
248
    }
489
}
490

            
491
/// A mutable reference created by borrowing mutably from a [CoapFfiRcCell] using
492
/// [CoapFfiRcCell::borrow_mut()].
493
pub(crate) enum CoapLendableFfiRefMut<'a, T> {
494
    Owned(RefMut<'a, T>),
495
    Borrowed(&'a mut T, Rc<RefCell<Option<*mut T>>>),
496
}
497

            
498
impl<T> Deref for CoapLendableFfiRefMut<'_, T> {
499
    type Target = T;
500

            
501
2945
    fn deref(&self) -> &Self::Target {
502
2945
        match self {
503
2945
            CoapLendableFfiRefMut::Owned(v) => v.deref(),
504
            CoapLendableFfiRefMut::Borrowed(v, _lend_container) => v,
505
        }
506
2945
    }
507
}
508

            
509
impl<T> DerefMut for CoapLendableFfiRefMut<'_, T> {
510
3877
    fn deref_mut(&mut self) -> &mut Self::Target {
511
3877
        match self {
512
3388
            CoapLendableFfiRefMut::Owned(v) => v.deref_mut(),
513
489
            CoapLendableFfiRefMut::Borrowed(v, _lend_container) => v,
514
        }
515
3877
    }
516
}
517

            
518
impl<T> Drop for CoapLendableFfiRefMut<'_, T> {
519
3877
    fn drop(&mut self) {
520
3877
        if let CoapLendableFfiRefMut::Borrowed(refer, lend_container) = self {
521
489
            let mut lend_container = RefCell::borrow_mut(lend_container);
522
489
            assert!(
523
489
                lend_container.is_none(),
524
                "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
525
            );
526
489
            assert!(
527
489
                lend_container.replace(*refer).is_none(),
528
                "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
529
            );
530
3388
        }
531
3877
    }
532
}