libcoap_rs/mem.rs
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 * mem.rs - Memory handling helper structs and traits for the libcoap Rust wrapper.
9 */
10
11//! Code related to memory handling, especially for passing objects through FFI
12
13use std::{
14 cell::{Ref, RefCell, RefMut},
15 ffi::c_void,
16 fmt::{Debug, Formatter},
17 ops::{Deref, DerefMut},
18 rc::{Rc, Weak},
19};
20
21/// Trait implemented by libcoap wrapper structs that contain an inner value that may be dropped
22/// exclusively, i.e., that can be dropped with the additional check that there are no further
23/// references to the inner value.
24pub(crate) trait DropInnerExclusively {
25 /// Consume this instance, ensuring that the inner (and potentially shared) part of the struct
26 /// referenced by this instance is also dropped.
27 ///
28 /// # Panics
29 ///
30 /// Panics if the inner part of this struct cannot be exclusively dropped, i.e., it is still
31 /// used by another instance.
32 fn drop_exclusively(self);
33}
34
35/// A strong reference counted cell, created from an app data/user data pointer inside of a C
36/// library struct.
37///
38/// This type is a wrapper around Rc<RefCell<D>> with some additional functions for creating from
39/// or converting to raw pointers.
40pub(crate) struct CoapFfiRcCell<D>(Rc<RefCell<D>>);
41
42impl<D> CoapFfiRcCell<D> {
43 /// Creates a new instance of CoapFfiRcCell, containing the provided value.
44 pub fn new(value: D) -> CoapFfiRcCell<D> {
45 CoapFfiRcCell(Rc::new(RefCell::new(value)))
46 }
47
48 /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
49 /// into the appropriate reference type.
50 ///
51 /// This is done by first restoring the `Rc<RefCell<D>>` using [Rc::from_raw()], then
52 /// cloning and creating the [CoapFfiRcCell] from it (maintaining the original reference using
53 /// [Rc::into_raw()]).
54 ///
55 /// Note that for the lifetime of this [CoapFfiRcCell], the reference counter of the
56 /// underlying [Rc] is increased by one.
57 ///
58 /// # Safety
59 /// For an explanation of the purpose of this struct and where it was originally intended to be
60 /// used, see the struct-level documentation.
61 ///
62 /// To safely use this function, the following invariants must be kept:
63 /// - ptr is a valid pointer to an Rc<RefCell<D>>
64 pub unsafe fn clone_raw_rc(ptr: *mut c_void) -> CoapFfiRcCell<D> {
65 let orig_ref = Rc::from_raw(ptr as *const RefCell<D>);
66 let new_ref = Rc::clone(&orig_ref);
67 // Pointer should not have changed, so we don't need to use the returned value.
68 let _ = Rc::into_raw(orig_ref);
69 CoapFfiRcCell(new_ref)
70 }
71
72 /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
73 /// into the appropriate reference type.
74 ///
75 /// This is done by first restoring the `Weak<RefCell<D>>` using [Weak::from_raw()],
76 /// upgrading it to a `Rc<RefCell<D>>` then cloning and creating the [CoapFfiRcCell] from the
77 /// upgraded reference (restoring the raw pointer again afterwards using [Rc::downgrade()] and
78 /// [Weak::into_raw()]).
79 ///
80 /// Note that for the lifetime of this [CoapFfiRcCell], the reference counter of the underlying
81 /// [Rc] is increased by one.
82 ///
83 /// # Panics
84 /// Panics if the provided Weak reference is orphaned.
85 ///
86 /// # Safety
87 /// For an explanation of the purpose of this struct and where it was originally intended to be
88 /// used, see the struct-level documentation.
89 ///
90 /// To safely use this function, the following invariants must be kept:
91 /// - ptr is a valid pointer to a `Weak<RefCell<D>>`
92 pub unsafe fn clone_raw_weak(ptr: *mut c_void) -> CoapFfiRcCell<D> {
93 let orig_ref = Weak::from_raw(ptr as *const RefCell<D>);
94 let new_ref = Weak::upgrade(&orig_ref).expect("attempted to upgrade a weak reference that was orphaned");
95 let _weakref = Weak::into_raw(orig_ref);
96 CoapFfiRcCell(new_ref)
97 }
98
99 /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
100 /// into the underlying `Weak<RefCell<D>>`.
101 ///
102 /// This is done by restoring the `Weak<RefCell<D>>` using [Weak::from_raw()],
103 ///
104 /// Note that unlike [CoapFfiRcCell::clone_raw_weak()], this does not clone the weak reference
105 /// inside of the pointer and instead restores the `Weak` directly from the pointer.
106 /// This means that dropping the `Weak` returned from this function invalidates the pointer
107 /// provided to this function.
108 ///
109 /// # Panics
110 /// Panics if the provided Weak reference is orphaned.
111 ///
112 /// # Safety
113 /// For an explanation of the purpose of this struct and where it was originally intended to be
114 /// used, see the struct-level documentation.
115 ///
116 /// To safely use this function, the following invariants must be kept:
117 /// - ptr is a valid pointer to a `Weak<RefCell<D>>`
118 /// - as soon as the returned `Weak<RefCell<D>>` is dropped, the provided pointer is treated as
119 /// invalid.
120 pub unsafe fn raw_ptr_to_weak(ptr: *mut c_void) -> Weak<RefCell<D>> {
121 Weak::from_raw(ptr as *const RefCell<D>)
122 }
123
124 /// Converts from a raw user data/application data pointer inside of a libcoap C library struct
125 /// into the underlying `Rc<RefCell<D>>`.
126 ///
127 /// This is done by restoring the `Rc<RefCell<D>>` using [Rc::from_raw()],
128 ///
129 /// Note that unlike [CoapFfiRcCell::clone_raw_rc()], this does not clone the weak reference
130 /// inside of the pointer and instead restores the `Rc` directly from the pointer.
131 /// This means that dropping the `Rc` returned from this function invalidates the pointer
132 /// provided to this function and that the provided pointer must point to a valid
133 /// `Rc<RefCell<D>>`.
134 ///
135 /// # Panics
136 /// Panics if the provided Weak reference is orphaned.
137 ///
138 /// # Safety
139 /// For an explanation of the purpose of this struct and where it was originally intended to be
140 /// used, see the struct-level documentation.
141 ///
142 /// To safely use this function, the following invariants must be kept:
143 /// - ptr is a valid pointer to a `Rc<RefCell<D>>`
144 /// - as soon as the returned `Rc<RefCell<D>>` is dropped, the provided pointer is treated as
145 /// invalid.
146 // Kept for consistency
147 #[allow(unused)]
148 pub unsafe fn raw_ptr_to_rc(ptr: *mut c_void) -> Rc<RefCell<D>> {
149 Rc::from_raw(ptr as *const RefCell<D>)
150 }
151
152 /// Creates a raw reference, suitable for storage inside of a libcoap C library user/application
153 /// data pointer.
154 ///
155 /// This function internally calls [Rc::clone()] and then [Rc::into_raw()] to create a pointer
156 /// referring to a clone of the `Rc<RefCell<D>>` contained in this type.
157 ///
158 /// Note that this increases the reference count of the Rc by one.
159 // Kept for consistency
160 #[allow(unused)]
161 pub fn create_raw_rc(&self) -> *mut c_void {
162 Rc::into_raw(Rc::clone(&self.0)) as *mut c_void
163 }
164
165 /// Creates a raw reference, suitable for storage inside of a libcoap C library user/application
166 /// data pointer.
167 ///
168 /// This function internally calls [Rc::downgrade()] and then [Weak::into_raw()] to create a
169 /// pointer referring to a weak reference of the `Rc<RefCell<D>>` contained in this type.
170 ///
171 /// Note that this does not increase the reference count of the [Rc] by one. If you want to
172 /// ensure that the underlying D is never cleaned up for as long as this pointer exists, you
173 /// need to maintain this object for as least as long as the reference.
174 pub fn create_raw_weak(&self) -> *mut c_void {
175 Weak::into_raw(Rc::downgrade(&self.0)) as *mut c_void
176 }
177
178 /// Creates an immutable reference to the contained data type.
179 ///
180 /// # Panics
181 /// Panics if borrowing here would violate Rusts aliasing rules.
182 pub fn borrow(&self) -> Ref<D> {
183 RefCell::borrow(&self.0)
184 }
185
186 /// Creates a mutable reference to the contained data type.
187 ///
188 /// # Panics
189 /// Panics if borrowing mutably here would violate Rusts aliasing rules.
190 pub fn borrow_mut(&self) -> RefMut<D> {
191 RefCell::borrow_mut(&self.0)
192 }
193}
194
195impl<D: PartialEq> PartialEq for CoapFfiRcCell<D> {
196 fn eq(&self, other: &Self) -> bool {
197 Rc::eq(&self.0, &other.0)
198 }
199}
200
201impl<D: Eq + PartialEq> Eq for CoapFfiRcCell<D> {}
202
203impl<D> Clone for CoapFfiRcCell<D> {
204 fn clone(&self) -> Self {
205 CoapFfiRcCell(self.0.clone())
206 }
207}
208
209impl<D: Debug> Debug for CoapFfiRcCell<D> {
210 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
211 f.debug_struct("CoapFfiRcCell").field("0", &self.0).finish()
212 }
213}
214
215impl<T: Debug> DropInnerExclusively for CoapFfiRcCell<T> {
216 fn drop_exclusively(self) {
217 std::mem::drop(
218 Rc::try_unwrap(self.0).expect("unable to unwrap instance of CoapFfiRcCell as it is still in use"),
219 )
220 }
221}
222
223/// A reference counted cell suitable for passing through the FFI barrier, with the additional
224/// possibility of passing an existing reference through this barrier.
225///
226/// This struct is similar to [CoapFfiRcCell], but provides additional functionality for
227/// maintaining a reference through the FFI barrier using the [lend()] function.
228#[derive(Debug)]
229pub(crate) struct CoapLendableFfiRcCell<T: Debug>(Rc<RefCell<T>>, Rc<RefCell<Option<*mut T>>>);
230
231impl<T: Debug> CoapLendableFfiRcCell<T> {
232 /// Creates a new [`CoapLendableFfiRcCell`] from the given value.
233 pub fn new(value: T) -> CoapLendableFfiRcCell<T> {
234 CoapLendableFfiRcCell(Rc::new(RefCell::new(value)), Rc::new(RefCell::new(None)))
235 }
236
237 /// Mutably borrows from the value in this cell.
238 ///
239 /// This function will first check if a reference was lent through the FFI barrier using a call
240 /// to [lend()].
241 /// If so, it will take that reference (and return it to the cell when the returned
242 /// [CoapLendableFfiRef] goes out of scope).
243 /// If not, it will borrow the value normally by calling [Rc::borrow()] on the contained value.
244 ///
245 /// # Panics
246 /// Panics if the value was already mutably borrowed.
247 pub fn borrow_mut(&self) -> CoapLendableFfiRefMut<'_, T> {
248 if let Some(borrowed) = RefCell::borrow_mut(&self.1).take() {
249 // SAFETY: The aliasing rules are ensured here by making sure that only one person may
250 // retrieve the pointer value stored in the container at any time (as the value in the
251 // Option is always retrieved using _take()_.
252 // The validity of the pointer is ensured because the only way a value can be stored
253 // here is by calling CoapLendableFfiRcCell::lend_ref_mut(), which converts a
254 // reference into an always valid pointer.
255 CoapLendableFfiRefMut::Borrowed(unsafe { borrowed.as_mut() }.unwrap(), Rc::clone(&self.1))
256 } else {
257 CoapLendableFfiRefMut::Owned(RefCell::borrow_mut(&self.0))
258 }
259 }
260
261 /// Immutably borrows from the value in this cell.
262 ///
263 /// This function will first check if a reference was lent through the FFI barrier using a call
264 /// to [lend()].
265 /// If so, it will take that reference (and return it to the cell when the returned
266 /// [CoapLendableFfiRef] goes out of scope).
267 /// If not, it will borrow the value normally by calling [Rc::borrow()] on the contained value.
268 ///
269 /// # Panics
270 /// Panics if the value was already mutably borrowed.
271 pub fn borrow(&self) -> CoapLendableFfiRef<'_, T> {
272 if let Some(borrowed) = RefCell::borrow_mut(&self.1).take() {
273 // SAFETY: The aliasing rules are ensured here by making sure that only one person may
274 // retrieve the pointer value stored in the container at any time (as the value in the
275 // Option is always retrieved using _take()_.
276 // The validity of the pointer is ensured because the only way a value can be stored
277 // here is by calling CoapLendableFfiRcCell::lend_ref_mut(), which converts a
278 // reference into an always valid pointer.
279 // TODO we may want to allow multiple immutable borrows at some point(?)
280 CoapLendableFfiRef::Borrowed(unsafe { borrowed.as_mut() }.unwrap(), Rc::clone(&self.1))
281 } else {
282 CoapLendableFfiRef::Owned(RefCell::borrow(&self.0))
283 }
284 }
285
286 /// Create a raw pointer to this cell, suitable for storage in a libcoap application data
287 /// pointer.
288 ///
289 /// Internally, this function creates a clone of this cell, wraps this cell in a `Box` and then
290 /// converts this value into a pointer using [Box::into_raw].
291 ///
292 /// It is in the callers responsibility to free the memory associated with this `Box`, e.g., by
293 /// calling [from_raw_box()] and then dropping the value.
294 // Kept for consistency
295 #[allow(unused)]
296 pub fn create_raw_rc_box(&self) -> *mut CoapLendableFfiRcCell<T> {
297 Box::into_raw(Box::new(CoapLendableFfiRcCell::<T>::clone(self)))
298 }
299
300 /// Create a raw pointer to this cell, suitable for storage in a libcoap application data
301 /// pointer.
302 ///
303 /// Internally, this function creates a weak clone of this cell, wraps this cell in a `Box` and
304 /// then converts this value into a pointer using [Box::into_raw].
305 ///
306 /// It is in the callers responsibility to free the memory associated with this `Box`, e.g., by
307 /// calling [CoapLendableFfiWeakCell::from_raw_box()] and then dropping the value.
308 pub fn create_raw_weak_box(&self) -> *mut CoapLendableFfiWeakCell<T> {
309 Box::into_raw(Box::new(self.downgrade()))
310 }
311
312 /// Creates a new instance of this struct by cloning from a raw pointer pointing to a
313 /// `Box<CoapLendableFfiRcCell<T>`.
314 ///
315 /// # Safety
316 /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiRcCell<T>`.
317 // Kept for consistency
318 #[allow(unused)]
319 pub unsafe fn clone_raw_rc_box(ptr: *mut CoapLendableFfiRcCell<T>) -> CoapLendableFfiRcCell<T> {
320 let ref_box: Box<CoapLendableFfiRcCell<T>> = Box::from_raw(ptr);
321 let ret_val = CoapLendableFfiRcCell::<T>::clone(ref_box.as_ref());
322 Box::into_raw(ref_box);
323 ret_val
324 }
325
326 /// Creates a new instance of this struct by cloning from a raw pointer pointing to a
327 /// `Box<CoapLendableFfiWeakCell<T>`.
328 ///
329 /// # Panics
330 /// Panics if the provided weak cell is orphaned.
331 ///
332 /// # Safety
333 /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiWeakCell<T>`.
334 pub unsafe fn clone_raw_weak_box(ptr: *mut CoapLendableFfiWeakCell<T>) -> CoapLendableFfiRcCell<T> {
335 let ref_box: Box<CoapLendableFfiWeakCell<T>> = Box::from_raw(ptr);
336 let ret_val = ref_box
337 .upgrade()
338 .expect("unable to restore CoapLendableFfiRcCell as the underlying value was already dropped");
339 assert_eq!(Box::into_raw(ref_box), ptr);
340 ret_val
341 }
342
343 /// Restores a `Box<CoapLendableFfiRcCell<T>>` from a raw pointer.
344 ///
345 /// Note that unlike [clone_raw_rc_box()], this function does not create a clone but directly
346 /// restores the underlying provided box.
347 /// As soon as the returned value is dropped, the provided pointer is therefore invalid.
348 ///
349 /// # Safety
350 /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiRcCell<T>`.
351 // Kept for consistency
352 #[allow(unused)]
353 pub unsafe fn from_raw_rc_box(ptr: *mut CoapLendableFfiRcCell<T>) -> Box<CoapLendableFfiRcCell<T>> {
354 Box::from_raw(ptr)
355 }
356
357 /// Stores a mutable reference to an instance of T for later retrieval by code running on the
358 /// other side of the FFI barrier.
359 ///
360 /// This function can be used to pass a previously borrowed value to other users of this cell
361 /// through the FFI barrier _without_ intermittently releasing the borrow.
362 ///
363 /// The reference will be lent for as long as the returned [CoapLendableFfiRefLender<'a, T>] is
364 /// not dropped.
365 pub fn lend_ref_mut<'a>(&self, refer: &'a mut T) -> CoapLendableFfiRefLender<'a, T> {
366 assert_eq!(
367 RefCell::as_ptr(&self.0),
368 refer as *mut T,
369 "attempted to lend different object over CoapLendableFfiRcCell"
370 );
371 CoapLendableFfiRefLender::new(refer, &self.1)
372 }
373
374 /// Creates a weak version of this reference counted cell by downgrading its components.
375 pub fn downgrade(&self) -> CoapLendableFfiWeakCell<T> {
376 CoapLendableFfiWeakCell(Rc::downgrade(&self.0), Rc::downgrade(&self.1))
377 }
378}
379
380impl<T: Debug> Clone for CoapLendableFfiRcCell<T> {
381 fn clone(&self) -> Self {
382 CoapLendableFfiRcCell(Rc::clone(&self.0), Rc::clone(&self.1))
383 }
384}
385
386/// The weak variant of a [CoapLendableFfiRcCell].
387#[derive(Debug)]
388pub(crate) struct CoapLendableFfiWeakCell<T: Debug>(Weak<RefCell<T>>, Weak<RefCell<Option<*mut T>>>);
389
390impl<T: Debug> Clone for CoapLendableFfiWeakCell<T> {
391 fn clone(&self) -> Self {
392 CoapLendableFfiWeakCell(Weak::clone(&self.0), Weak::clone(&self.1))
393 }
394}
395
396impl<T: Debug> CoapLendableFfiWeakCell<T> {
397 /// Attempts to upgrade this weak cell into a full [CoapLendableFfiRcCell<T>], returning None
398 /// if the underlying value was already dropped.
399 pub fn upgrade(&self) -> Option<CoapLendableFfiRcCell<T>> {
400 self.0
401 .upgrade()
402 .zip(self.1.upgrade())
403 .map(|(v0, v1)| CoapLendableFfiRcCell(v0, v1))
404 }
405
406 /// Restores a `Box<CoapLendableFfiWeakCell<T>>` from a raw pointer.
407 ///
408 /// Note that unlike [CoapLendableFfiRcCell<T>::clone_raw_weak_box()], this function does not
409 /// create a clone but directly restores the underlying provided box.
410 /// As soon as the returned value is dropped, the provided pointer is therefore invalid.
411 ///
412 /// # Safety
413 /// The provided pointer must point to a valid instance of `Box<CoapLendableFfiWeakCell<T>`.
414 pub unsafe fn from_raw_box(ptr: *mut CoapLendableFfiWeakCell<T>) -> Box<CoapLendableFfiWeakCell<T>> {
415 Box::from_raw(ptr)
416 }
417}
418
419/// A token that is held by the lender of a mutable reference.
420///
421/// As long as this token is held, the mutable reference provided to [CoapLendableFfiRcCell] can be
422/// borrowed by other functions owning clones of the same [CoapLendableFfiRcCell].
423///
424/// When this value is dropped, it will check whether the lent reference is currently used
425/// elsewhere and panic/abort if this is the case, as this would violate the Rust aliasing rules.
426pub(crate) struct CoapLendableFfiRefLender<'a, T> {
427 lent_ref: &'a mut T,
428 lent_ptr_ctr: Weak<RefCell<Option<*mut T>>>,
429}
430
431impl<'a, T> CoapLendableFfiRefLender<'a, T> {
432 /// Create a new lender token from the given reference.
433 fn new(refer: &'a mut T, container: &Rc<RefCell<Option<*mut T>>>) -> CoapLendableFfiRefLender<'a, T> {
434 RefCell::borrow_mut(container).replace(refer as *mut T);
435 CoapLendableFfiRefLender {
436 lent_ref: refer,
437 lent_ptr_ctr: Rc::downgrade(container),
438 }
439 }
440
441 pub(crate) fn unlend(self) {
442 std::mem::drop(self);
443 }
444}
445
446impl<T> Drop for CoapLendableFfiRefLender<'_, T> {
447 fn drop(&mut self) {
448 if let Some(lent_ptr_ctr) = self.lent_ptr_ctr.upgrade() {
449 assert_eq!(
450 self.lent_ref as *mut T,
451 lent_ptr_ctr
452 .take()
453 .expect("unable to retrieve lent reference, implying that it may be in use somewhere"),
454 "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
455 )
456 }
457 }
458}
459
460/// A non-mutable reference created by borrowing mutably from a [CoapFfiRcCell] using
461/// [CoapFfiRcCell::borrow_mut()].
462pub(crate) enum CoapLendableFfiRef<'a, T> {
463 Owned(Ref<'a, T>),
464 Borrowed(&'a mut T, Rc<RefCell<Option<*mut T>>>),
465}
466
467impl<T> Deref for CoapLendableFfiRef<'_, T> {
468 type Target = T;
469
470 fn deref(&self) -> &Self::Target {
471 match self {
472 CoapLendableFfiRef::Owned(v) => v.deref(),
473 CoapLendableFfiRef::Borrowed(v, _lend_container) => v,
474 }
475 }
476}
477
478impl<T> Drop for CoapLendableFfiRef<'_, T> {
479 fn drop(&mut self) {
480 if let CoapLendableFfiRef::Borrowed(refer, lend_container) = self {
481 let mut lend_container = RefCell::borrow_mut(lend_container);
482 assert!(
483 lend_container.is_none(),
484 "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
485 );
486 assert!(
487 lend_container.replace(*refer).is_none(),
488 "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
489 );
490 }
491 }
492}
493
494/// A mutable reference created by borrowing mutably from a [CoapFfiRcCell] using
495/// [CoapFfiRcCell::borrow_mut()].
496pub(crate) enum CoapLendableFfiRefMut<'a, T> {
497 Owned(RefMut<'a, T>),
498 Borrowed(&'a mut T, Rc<RefCell<Option<*mut T>>>),
499}
500
501impl<T> Deref for CoapLendableFfiRefMut<'_, T> {
502 type Target = T;
503
504 fn deref(&self) -> &Self::Target {
505 match self {
506 CoapLendableFfiRefMut::Owned(v) => v.deref(),
507 CoapLendableFfiRefMut::Borrowed(v, _lend_container) => v,
508 }
509 }
510}
511
512impl<T> DerefMut for CoapLendableFfiRefMut<'_, T> {
513 fn deref_mut(&mut self) -> &mut Self::Target {
514 match self {
515 CoapLendableFfiRefMut::Owned(v) => v.deref_mut(),
516 CoapLendableFfiRefMut::Borrowed(v, _lend_container) => v,
517 }
518 }
519}
520
521impl<T> Drop for CoapLendableFfiRefMut<'_, T> {
522 fn drop(&mut self) {
523 if let CoapLendableFfiRefMut::Borrowed(refer, lend_container) = self {
524 let mut lend_container = RefCell::borrow_mut(lend_container);
525 assert!(
526 lend_container.is_none(),
527 "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
528 );
529 assert!(
530 lend_container.replace(*refer).is_none(),
531 "somehow, multiple references are stored in the same CoapLendableFfiRcCell"
532 );
533 }
534 }
535}