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