Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::{fmt, sync::Arc};
/// Object handle
///
/// Handles opaque `u64` values used to pass objects across the FFI, both for objects implemented in
/// Rust and ones implemented in the foreign language.
///
/// Rust handles are generated by leaking a raw pointer
/// Foreign handles are generated with a handle map that only generates odd values.
/// For all currently supported architectures and hopefully any ones we add in the future:
/// * 0 is an invalid value.
/// * The lowest bit will always be set for foreign handles and never set for Rust ones (since the
/// leaked pointer will be aligned to `size_of::<Arc<T>>()` == `size_of::<*const T>()`).
///
/// Rust handles are mainly managed is through the [crate::HandleAlloc] trait.
#[derive(Clone, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct Handle(u64);
impl Handle {
pub fn from_pointer<T>(ptr: *const T) -> Self {
Self(ptr as u64)
}
pub fn as_pointer<T>(&self) -> *const T {
self.0 as *const T
}
/// Was this handle generated by the foreign side of the FFI?
pub fn is_foreign(&self) -> bool {
// Foreign handles have the lowest bit set.
// We know that Rust handles will never have this set, since the pointers that they're cast from have alignment > 1;
(self.0 & 1) == 1
}
/// # Safety
/// The raw value must be a valid handle as described above.
pub unsafe fn from_raw(raw: u64) -> Option<Self> {
if raw == 0 {
None
} else {
Some(Self(raw))
}
}
pub fn from_raw_unchecked(raw: u64) -> Self {
Self(raw)
}
pub fn as_raw(&self) -> u64 {
self.0
}
/// Create a handle from an Arc
pub fn from_arc<T>(arc: Arc<T>) -> Self {
Self::from_pointer(Arc::into_raw(arc))
}
/// Re-create an Arc from a handle
///
/// # Safety
///
/// * The handle must have been created from `Handle::from_arc`.
/// * The handle must only be used once
pub unsafe fn into_arc<T>(self) -> Arc<T> {
Arc::from_raw(self.as_pointer())
}
/// Re-create an Arc from a borrowed handle
///
/// "borrowed" means a handle sent from the other side of the FFI without cloning it first.
/// Be very careful with using this, since it's easy to introduce races.
/// The one scenario this is currently used for is futures, since we can guarantee that the
/// foreign side will not drop the future while in the middle of polling/cancelling it.
///
/// # Safety
///
/// * The handle must have been created from `Handle::from_arc`.
/// * There must be no possibility for the handle to be dropped before the function the
/// borrowed handle is passed to returns.
pub unsafe fn into_arc_borrowed<T>(self) -> Arc<T> {
self.clone_arc_handle::<T>();
Arc::from_raw(self.as_pointer())
}
/// Clone a handle for an Arc
///
/// # Safety
///
/// The handle must have been created from `Handle::from_arc`.
pub unsafe fn clone_arc_handle<T>(&self) -> Self {
Arc::increment_strong_count(self.as_pointer::<T>());
// This is safe because we just incremented the refcount.
Self(self.0)
}
}
impl fmt::Debug for Handle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Handle(0x{:x})", self.0)
}
}