blob: 9038f4e0eab2c52d199eee018de35cd54bee8000 [file] [log] [blame]
use crate::string::CxxString;
use core::ffi::c_void;
use core::fmt::Display;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
/// Binding to C++ `std::weak_ptr<T>`.
///
/// The typical way to construct a WeakPtr from Rust is by [downgrading] from a
/// SharedPtr.
///
/// [downgrading]: crate::SharedPtr::downgrade
#[repr(C)]
pub struct WeakPtr<T>
where
T: WeakPtrTarget,
{
repr: [*mut c_void; 2],
ty: PhantomData<T>,
}
impl<T> WeakPtr<T>
where
T: WeakPtrTarget,
{
/// Makes a new WeakPtr wrapping a null pointer.
///
/// Matches the behavior of default-constructing a std::weak\_ptr.
pub fn null() -> Self {
let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
let new = weak_ptr.as_mut_ptr().cast();
unsafe {
T::__null(new);
weak_ptr.assume_init()
}
}
}
unsafe impl<T> Send for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
unsafe impl<T> Sync for WeakPtr<T> where T: Send + Sync + WeakPtrTarget {}
impl<T> Clone for WeakPtr<T>
where
T: WeakPtrTarget,
{
fn clone(&self) -> Self {
let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
let new = weak_ptr.as_mut_ptr().cast();
let this = self as *const Self as *mut c_void;
unsafe {
T::__clone(this, new);
weak_ptr.assume_init()
}
}
}
impl<T> Drop for WeakPtr<T>
where
T: WeakPtrTarget,
{
fn drop(&mut self) {
let this = self as *mut Self as *mut c_void;
unsafe { T::__drop(this) }
}
}
// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
pub unsafe trait WeakPtrTarget {
#[doc(hidden)]
const __NAME: &'static dyn Display;
#[doc(hidden)]
unsafe fn __null(new: *mut c_void);
#[doc(hidden)]
unsafe fn __clone(this: *const c_void, new: *mut c_void);
#[doc(hidden)]
unsafe fn __downgrade(shared: *const c_void, new: *mut c_void);
#[doc(hidden)]
unsafe fn __drop(this: *mut c_void);
}
macro_rules! impl_weak_ptr_target {
($segment:expr, $name:expr, $ty:ty) => {
unsafe impl WeakPtrTarget for $ty {
const __NAME: &'static dyn Display = &$name;
unsafe fn __null(new: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$null")]
fn __null(new: *mut c_void);
}
}
__null(new);
}
unsafe fn __clone(this: *const c_void, new: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$clone")]
fn __clone(this: *const c_void, new: *mut c_void);
}
}
__clone(this, new);
}
unsafe fn __downgrade(shared: *const c_void, weak: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$downgrade")]
fn __downgrade(shared: *const c_void, weak: *mut c_void);
}
}
__downgrade(shared, weak);
}
unsafe fn __drop(this: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$weak_ptr$", $segment, "$drop")]
fn __drop(this: *mut c_void);
}
}
__drop(this);
}
}
};
}
macro_rules! impl_weak_ptr_target_for_primitive {
($ty:ident) => {
impl_weak_ptr_target!(stringify!($ty), stringify!($ty), $ty);
};
}
impl_weak_ptr_target_for_primitive!(bool);
impl_weak_ptr_target_for_primitive!(u8);
impl_weak_ptr_target_for_primitive!(u16);
impl_weak_ptr_target_for_primitive!(u32);
impl_weak_ptr_target_for_primitive!(u64);
impl_weak_ptr_target_for_primitive!(usize);
impl_weak_ptr_target_for_primitive!(i8);
impl_weak_ptr_target_for_primitive!(i16);
impl_weak_ptr_target_for_primitive!(i32);
impl_weak_ptr_target_for_primitive!(i64);
impl_weak_ptr_target_for_primitive!(isize);
impl_weak_ptr_target_for_primitive!(f32);
impl_weak_ptr_target_for_primitive!(f64);
impl_weak_ptr_target!("string", "CxxString", CxxString);