Support shared_ptr of primitives

This commit is contained in:
David Tolnay 2020-12-10 19:26:02 -08:00
parent 1cde514d94
commit 5b16340b67
No known key found for this signature in database
GPG Key ID: F9BA143B95FF6D82
2 changed files with 119 additions and 0 deletions

View File

@ -331,6 +331,15 @@ Error &Error::operator=(Error &&other) noexcept {
const char *Error::what() const noexcept { return this->msg; }
namespace {
template <typename T>
union MaybeUninit {
T value;
MaybeUninit() {}
~MaybeUninit() {}
};
} // namespace
} // namespace cxxbridge1
} // namespace rust
@ -443,6 +452,34 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
return cxxbridge1$rust_vec$##RUST_TYPE##$stride(); \
}
#define SHARED_PTR_OPS(RUST_TYPE, CXX_TYPE) \
static_assert(sizeof(std::shared_ptr<CXX_TYPE>) == 2 * sizeof(void *), ""); \
static_assert(alignof(std::shared_ptr<CXX_TYPE>) == alignof(void *), ""); \
void cxxbridge1$std$shared_ptr$##RUST_TYPE##$null( \
std::shared_ptr<CXX_TYPE> *ptr) noexcept { \
new (ptr) std::shared_ptr<CXX_TYPE>(); \
} \
CXX_TYPE *cxxbridge1$std$shared_ptr$##RUST_TYPE##$uninit( \
std::shared_ptr<CXX_TYPE> *ptr) noexcept { \
CXX_TYPE *uninit = \
reinterpret_cast<CXX_TYPE *>(new rust::MaybeUninit<CXX_TYPE>); \
new (ptr) std::shared_ptr<CXX_TYPE>(uninit); \
return uninit; \
} \
void cxxbridge1$std$shared_ptr$##RUST_TYPE##$clone( \
const std::shared_ptr<CXX_TYPE> &self, \
std::shared_ptr<CXX_TYPE> *ptr) noexcept { \
new (ptr) std::shared_ptr<CXX_TYPE>(self); \
} \
const CXX_TYPE *cxxbridge1$std$shared_ptr$##RUST_TYPE##$get( \
const std::shared_ptr<CXX_TYPE> &self) noexcept { \
return self.get(); \
} \
void cxxbridge1$std$shared_ptr$##RUST_TYPE##$drop( \
const std::shared_ptr<CXX_TYPE> *self) noexcept { \
self->~shared_ptr(); \
}
// Usize and isize are the same type as one of the below.
#define FOR_EACH_NUMERIC(MACRO) \
MACRO(u8, uint8_t) \
@ -468,9 +505,16 @@ static_assert(sizeof(std::string) <= kMaxExpectedWordsInString * sizeof(void *),
MACRO(char, char) \
MACRO(string, rust::String)
#define FOR_EACH_SHARED_PTR(MACRO) \
FOR_EACH_NUMERIC(MACRO) \
MACRO(usize, size_t) \
MACRO(isize, rust::isize) \
MACRO(string, std::string)
extern "C" {
FOR_EACH_STD_VECTOR(STD_VECTOR_OPS)
FOR_EACH_RUST_VEC(RUST_VEC_EXTERNS)
FOR_EACH_SHARED_PTR(SHARED_PTR_OPS)
} // extern "C"
namespace rust {

View File

@ -1,3 +1,4 @@
use crate::cxx_string::CxxString;
use crate::kind::Trivial;
use crate::ExternType;
use core::ffi::c_void;
@ -189,3 +190,77 @@ pub unsafe trait SharedPtrTarget {
#[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 {
const __NAME: &'static dyn Display = &$name;
unsafe fn __null(new: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$null")]
fn __null(new: *mut c_void);
}
}
__null(new);
}
unsafe fn __new(value: Self, new: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$uninit")]
fn __uninit(new: *mut c_void) -> *mut c_void;
}
}
__uninit(new).cast::<$ty>().write(value);
}
unsafe fn __clone(this: *const c_void, new: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$clone")]
fn __clone(this: *const c_void, new: *mut c_void);
}
}
__clone(this, new);
}
unsafe fn __get(this: *const c_void) -> *const Self {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$get")]
fn __get(this: *const c_void) -> *const c_void;
}
}
__get(this).cast()
}
unsafe fn __drop(this: *mut c_void) {
extern "C" {
attr! {
#[link_name = concat!("cxxbridge1$std$shared_ptr$", $segment, "$drop")]
fn __drop(this: *mut c_void);
}
}
__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!(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);