use crate::extern_type::ExternType;
use crate::fmt::display;
use crate::kind::Trivial;
use crate::string::CxxString;
use crate::unique_ptr::{UniquePtr, UniquePtrTarget};
use crate::weak_ptr::{WeakPtr, WeakPtrTarget};
use core::cmp::Ordering;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::Deref;
use core::pin::Pin;
use core::ptr;
#[repr(C)]
pub struct SharedPtr<T>
where
T: SharedPtrTarget,
{
repr: [MaybeUninit<*mut c_void>; 2],
ty: PhantomData<T>,
}
impl<T> SharedPtr<T>
where
T: SharedPtrTarget,
{
pub fn null() -> Self {
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
let new = shared_ptr.as_mut_ptr().cast();
unsafe {
T::__null(new);
shared_ptr.assume_init()
}
}
pub fn new(value: T) -> Self
where
T: ExternType<Kind = Trivial>,
{
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
let new = shared_ptr.as_mut_ptr().cast();
unsafe {
T::__new(value, new);
shared_ptr.assume_init()
}
}
#[track_caller]
pub unsafe fn from_raw(raw: *mut T) -> Self {
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
let new = shared_ptr.as_mut_ptr().cast();
unsafe {
T::__raw(new, raw);
shared_ptr.assume_init()
}
}
pub fn is_null(&self) -> bool {
let this = ptr::from_ref::<Self>(self).cast::<c_void>();
let ptr = unsafe { T::__get(this) };
ptr.is_null()
}
pub fn as_ref(&self) -> Option<&T> {
let ptr = self.as_ptr();
unsafe { ptr.as_ref() }
}
pub unsafe fn pin_mut_unchecked(&mut self) -> Pin<&mut T> {
let ptr = self.as_mut_ptr();
match unsafe { ptr.as_mut() } {
Some(target) => unsafe { Pin::new_unchecked(target) },
None => panic!(
"called pin_mut_unchecked on a null SharedPtr<{}>",
display(T::__typename),
),
}
}
pub fn as_ptr(&self) -> *const T {
let this = ptr::from_ref::<Self>(self).cast::<c_void>();
unsafe { T::__get(this) }
}
pub fn as_mut_ptr(&self) -> *mut T {
self.as_ptr().cast_mut()
}
pub fn downgrade(&self) -> WeakPtr<T>
where
T: WeakPtrTarget,
{
let this = ptr::from_ref::<Self>(self).cast::<c_void>();
let mut weak_ptr = MaybeUninit::<WeakPtr<T>>::uninit();
let new = weak_ptr.as_mut_ptr().cast();
unsafe {
T::__downgrade(this, new);
weak_ptr.assume_init()
}
}
}
unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
impl<T> Clone for SharedPtr<T>
where
T: SharedPtrTarget,
{
fn clone(&self) -> Self {
let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
let new = shared_ptr.as_mut_ptr().cast();
let this = ptr::from_ref::<Self>(self).cast::<c_void>();
unsafe {
T::__clone(this, new);
shared_ptr.assume_init()
}
}
}
impl<T> Unpin for SharedPtr<T> where T: SharedPtrTarget {}
impl<T> Drop for SharedPtr<T>
where
T: SharedPtrTarget,
{
fn drop(&mut self) {
let this = ptr::from_mut::<Self>(self).cast::<c_void>();
unsafe { T::__drop(this) }
}
}
impl<T> Deref for SharedPtr<T>
where
T: SharedPtrTarget,
{
type Target = T;
fn deref(&self) -> &Self::Target {
match self.as_ref() {
Some(target) => target,
None => panic!(
"called deref on a null SharedPtr<{}>",
display(T::__typename),
),
}
}
}
impl<T> Debug for SharedPtr<T>
where
T: Debug + SharedPtrTarget,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self.as_ref() {
None => formatter.write_str("nullptr"),
Some(value) => Debug::fmt(value, formatter),
}
}
}
impl<T> Display for SharedPtr<T>
where
T: Display + SharedPtrTarget,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self.as_ref() {
None => formatter.write_str("nullptr"),
Some(value) => Display::fmt(value, formatter),
}
}
}
impl<T> PartialEq for SharedPtr<T>
where
T: PartialEq + SharedPtrTarget,
{
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl<T> Eq for SharedPtr<T> where T: Eq + SharedPtrTarget {}
impl<T> PartialOrd for SharedPtr<T>
where
T: PartialOrd + SharedPtrTarget,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
PartialOrd::partial_cmp(&self.as_ref(), &other.as_ref())
}
}
impl<T> Ord for SharedPtr<T>
where
T: Ord + SharedPtrTarget,
{
fn cmp(&self, other: &Self) -> Ordering {
Ord::cmp(&self.as_ref(), &other.as_ref())
}
}
impl<T> Hash for SharedPtr<T>
where
T: Hash + SharedPtrTarget,
{
fn hash<H>(&self, hasher: &mut H)
where
H: Hasher,
{
self.as_ref().hash(hasher);
}
}
impl<T> From<UniquePtr<T>> for SharedPtr<T>
where
T: UniquePtrTarget + SharedPtrTarget,
{
fn from(unique: UniquePtr<T>) -> Self {
unsafe { SharedPtr::from_raw(UniquePtr::into_raw(unique)) }
}
}
pub unsafe trait SharedPtrTarget {
#[doc(hidden)]
fn __typename(f: &mut fmt::Formatter) -> fmt::Result;
#[doc(hidden)]
unsafe fn __null(new: *mut c_void);
#[doc(hidden)]
unsafe fn __new(value: Self, new: *mut c_void)
where
Self: Sized,
{
let _ = value;
let _ = new;
unreachable!()
}
#[doc(hidden)]
unsafe fn __raw(new: *mut c_void, raw: *mut Self);
#[doc(hidden)]
unsafe fn __clone(this: *const c_void, new: *mut c_void);
#[doc(hidden)]
unsafe fn __get(this: *const c_void) -> *const Self;
#[doc(hidden)]
unsafe fn __drop(this: *mut c_void);
}
macro_rules! impl_shared_ptr_target {
($segment:expr, $name:expr, $ty:ty) => {
unsafe impl SharedPtrTarget for $ty {
fn __typename(f: &mut fmt::Formatter) -> fmt::Result {
f.write_str($name)
}
unsafe fn __null(new: *mut c_void) {
extern "C" {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
fn __null(new: *mut c_void);
}
unsafe { __null(new) }
}
unsafe fn __new(value: Self, new: *mut c_void) {
extern "C" {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
fn __uninit(new: *mut c_void) -> *mut c_void;
}
unsafe { __uninit(new).cast::<$ty>().write(value) }
}
unsafe fn __raw(new: *mut c_void, raw: *mut Self) {
extern "C" {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$raw")]
fn __raw(new: *mut c_void, raw: *mut c_void);
}
unsafe { __raw(new, raw.cast::<c_void>()) }
}
unsafe fn __clone(this: *const c_void, new: *mut c_void) {
extern "C" {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
fn __clone(this: *const c_void, new: *mut c_void);
}
unsafe { __clone(this, new) }
}
unsafe fn __get(this: *const c_void) -> *const Self {
extern "C" {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
fn __get(this: *const c_void) -> *const c_void;
}
unsafe { __get(this) }.cast()
}
unsafe fn __drop(this: *mut c_void) {
extern "C" {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
fn __drop(this: *mut c_void);
}
unsafe { __drop(this) }
}
}
};
}
macro_rules! impl_shared_ptr_target_for_primitive {
($ty:ident) => {
impl_shared_ptr_target!(stringify!($ty), stringify!($ty), $ty);
};
}
impl_shared_ptr_target_for_primitive!(bool);
impl_shared_ptr_target_for_primitive!(u8);
impl_shared_ptr_target_for_primitive!(u16);
impl_shared_ptr_target_for_primitive!(u32);
impl_shared_ptr_target_for_primitive!(u64);
impl_shared_ptr_target_for_primitive!(usize);
impl_shared_ptr_target_for_primitive!(i8);
impl_shared_ptr_target_for_primitive!(i16);
impl_shared_ptr_target_for_primitive!(i32);
impl_shared_ptr_target_for_primitive!(i64);
impl_shared_ptr_target_for_primitive!(isize);
impl_shared_ptr_target_for_primitive!(f32);
impl_shared_ptr_target_for_primitive!(f64);
impl_shared_ptr_target!("string", "CxxString", CxxString);