openthread/ot/otbox.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
/// A box for owning pointers to opaque types vended from the OpenThread API.
///
/// May be abbreviated as an [`OtBox`](crate::OtBox) to avoid confusion with [`std::boxed::Box`].
///
/// Internally, an [`ot::Box`](crate::ot::Box) contains the raw pointer to the underlying
/// OpenThread object. Externally, the box appears to contain an instance
/// of a type implementing [`ot::Boxable`](crate::ot::Boxable). References to the
/// [`ot::Boxable`](crate::ot::Boxable) type are created from the underlying pointer as needed.
///
/// When an [`ot::Box`](crate::ot::Box) goes out of scope, the underlying object is finalized
/// according to the OpenThread API for that type, via
/// [`ot::Boxable::finalize`](crate::ot::Boxable::finalize).
///
/// The underlying pointer may be taken from the box without finalization
/// by calling [`ot::Box::take_ot_ptr`](crate::ot::Box::take_ot_ptr), which consumes the
/// [`ot::Box`](crate::ot::Box) and returns the pointer.
///
/// ## Safety ##
///
/// In general, the safety of this entire approach is dependent on the
/// following assumptions on the language itself:
///
/// 1. **Casting from pointers to references**: Transmuting a `*mut Self::OtType` to a `&Self` is
/// not itself undefined behavior assuming the pointer pointed to a valid object.
/// 2. **Casting from references to pointers**: Transmuting a `&Self` that was previously created
/// by assumption 1 back into a `*mut Self::OtType` will *always* yield the original pointer
/// value.
/// 3. **Behavior of Static Dispatch**: Traits implemented on `Self` and called via static
/// dispatch will have `&self` references that obey assumption #2.
/// 4. **No Spooky Stuff**: No weird pointer/reference manipulation happens behind the scenes,
/// like the spooky stuff C++ does.
#[repr(transparent)]
pub struct Box<T: Boxable>(*mut T::OtType, PhantomData<T>);
// SAFETY: Boxed values are owned values, so box itself can be considered `Send`/`Sync`
// as long as the contained type is considered `Send`/`Sync`.
unsafe impl<T: Boxable + Send> Send for Box<T> {}
unsafe impl<T: Boxable + Sync> Sync for Box<T> {}
impl<T: Boxable + crate::ot::InstanceInterface> crate::ot::InstanceInterface for Box<T> {}
impl<T: Boxable + std::fmt::Debug> std::fmt::Debug for Box<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("OtBox").field(self.as_ref()).finish()
}
}
impl<T: Boxable> Box<T> {
/// Takes ownership of an OpenThread object by wrapping it in an `OtBox` instance.
/// Unless subsequently removed by a call to [`take_ot_ptr()`], the pointed-to
/// object will be finalized when the box goes out of scope.
///
/// ## Safety ##
///
/// This method is unsafe because it is effectively a deferred call
/// to [`Boxable::ref_from_ot_ptr`], which is also unsafe. When calling,
/// care must be taken to ensure the following is true:
///
/// 1. The given pointer points to a valid instance of `T::OtType`.
/// 2. The caller has logical ownership of the object being pointed to.
pub unsafe fn from_ot_ptr(ptr: *mut T::OtType) -> Option<Self> {
if ptr.is_null() {
None
} else {
Some(Box(ptr, Default::default()))
}
}
/// Releases ownership of the contained OpenThread object, returning it's pointer.
pub fn take_ot_ptr(self) -> *mut T::OtType {
let ret = self.0;
std::mem::forget(self);
ret
}
}
impl<T: Boxable> AsRef<T> for Box<T> {
fn as_ref(&self) -> &T {
// SAFETY: `ref_from_ot_ptr` has two safety requirements on the pointer.
// The pointer ultimatly comes from `ot::Box::from_ot_ptr`, which
// has a superset of those requirements. Thus, the requirements
// for this call are met.
unsafe { T::ref_from_ot_ptr(self.0).unwrap() }
}
}
impl<T: Boxable> AsMut<T> for Box<T> {
fn as_mut(&mut self) -> &mut T {
// SAFETY: `mut_from_ot_ptr` has two safety requirements on the pointer.
// The pointer ultimatly comes from `ot::Box::from_ot_ptr`, which
// has a superset of those requirements. Thus, the requirements
// for this call are met.
unsafe { T::mut_from_ot_ptr(self.0).unwrap() }
}
}
impl<T: Boxable> Drop for Box<T> {
fn drop(&mut self) {
// SAFETY: The single safety requirement on `Boxable::finalize` is that it only
// be called from `Drop::drop`, which is this method.
unsafe { self.as_mut().finalize() }
}
}
impl<T: Boxable> Deref for Box<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<T: Boxable> DerefMut for Box<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut()
}
}
/// Trait for OpenThread Rust types for which an owned opaque instance is kept in a [`ot::Box<>`].
///
/// ## Safety ##
///
/// The safety of implementing this trait is dependent on the following assumptions:
///
/// 1. The type `Self` is never instantiated or passed by value. It must only ever
/// used by reference (`&Self` or `&mut Self`).
/// 2. No member of `Self` is ever accessed directly or exposed publicly.
///
/// Because of the above restrictions, `Self` is usually a zero-sized type.
pub unsafe trait Boxable: Sized {
/// The underlying implementation-opaque OpenThread type used by the standard C-API.
type OtType: Sized;
/// Finalizes or frees the underlying OpenThread object.
///
/// This method should only be called by the `Drop::drop` method on [`ot::Box`](crate::ot::Box).
/// It should not be called directly. This is usually the only method that
/// needs to be implemented from this trait: the default implementations of
/// the other methods is sufficient.
///
/// ## Safety ##
///
/// This method is considered unsafe to call directly because it invalidates
/// the underlying OpenThread object. This method should only ever be called
/// from a single place: `Drop::drop()` on `ot::Box`.
unsafe fn finalize(&mut self);
/// Creates a reference to a safe wrapper object from an OpenThread pointer.
///
/// ## Safety ##
///
/// This method is unsafe because it allows you to cast an arbitrary
/// pointer to a reference. When calling, care must be taken to ensure
/// the following is true:
///
/// 1. The given pointer points to a valid instance of `Self::OtType` for the
/// given lifetime.
unsafe fn ref_from_ot_ptr<'a>(ptr: *mut Self::OtType) -> Option<&'a Self> {
if ptr.is_null() {
None
} else {
Some(&*(ptr as *const Self))
}
}
/// Creates a reference to a safe wrapper object from an OpenThread const pointer.
///
/// ## Safety ##
///
/// This method is unsafe because it allows you to cast an arbitrary
/// pointer to a reference. When calling, care must be taken to ensure
/// the following is true:
///
/// 1. The given pointer points to a valid instance of `Self::OtType` for the
/// given lifetime.
unsafe fn ref_from_ot_const_ptr<'a>(ptr: *const Self::OtType) -> Option<&'a Self> {
if ptr.is_null() {
None
} else {
Some(&*(ptr as *const Self))
}
}
/// Creates a mutable reference to a safe wrapper object from an OpenThread pointer.
///
/// ## Safety ##
///
/// This method is unsafe because it allows you to cast an arbitrary
/// pointer to a reference. When calling, care must be taken to ensure
/// the following is true:
///
/// 1. The given pointer points to a valid instance of `Self::OtType`.
/// 2. The given pointer is not `NULL`.
unsafe fn mut_from_ot_ptr<'a>(ptr: *mut Self::OtType) -> Option<&'a mut Self> {
if ptr.is_null() {
None
} else {
Some(&mut *(ptr as *mut Self))
}
}
/// Returns the underlying OpenThread pointer for this object.
/// The default implementation simply casts the reference to a pointer.
fn as_ot_ptr(&self) -> *mut Self::OtType {
(self as *const Self) as *mut Self::OtType
}
}