/* 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::>()` == `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(ptr: *const T) -> Self { Self(ptr as u64) } pub fn as_pointer(&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; // https://mozilla.github.io/uniffi-rs/latest/internals/object_references.html (self.0 & 1) == 1 } /// # Safety /// The raw value must be a valid handle as described above. pub unsafe fn from_raw(raw: u64) -> Option { 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(arc: Arc) -> 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(self) -> Arc { 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(self) -> Arc { self.clone_arc_handle::(); 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(&self) -> Self { Arc::increment_strong_count(self.as_pointer::()); // 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) } }