From 9bffb93783035dcdc073d562fc23d5f33f913751 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 2 Jan 2021 02:15:21 -0800 Subject: [PATCH 1/3] Preserve &[T]'s Rust representation in rust::Slice --- include/cxx.h | 42 ++++++++++++++++++++++++--------------- src/cxx.cc | 16 +++++++++++++++ src/rust_slice.rs | 27 +++++++++++++------------ src/symbols/mod.rs | 1 + src/symbols/rust_slice.rs | 22 ++++++++++++++++++++ 5 files changed, 79 insertions(+), 29 deletions(-) create mode 100644 src/symbols/rust_slice.rs diff --git a/include/cxx.h b/include/cxx.h index 03f719fdd..a81fc2130 100644 --- a/include/cxx.h +++ b/include/cxx.h @@ -180,10 +180,9 @@ class Slice final void swap(Slice &) noexcept; private: - // Not necessarily ABI compatible with &[T]. Codegen will translate to - // cxx::rust_slice::RustSlice which matches this layout. - void *ptr; - std::size_t len; + void *ptr() const noexcept; + + std::array repr; }; template @@ -489,37 +488,42 @@ constexpr unsafe_bitcopy_t unsafe_bitcopy{}; #ifndef CXXBRIDGE1_RUST_SLICE #define CXXBRIDGE1_RUST_SLICE template -Slice::Slice() noexcept - : ptr(reinterpret_cast(align_of())), len(0) {} +Slice::Slice() noexcept { + void sliceInit(void *, const void *, std::size_t) noexcept; + sliceInit(this, reinterpret_cast(align_of()), 0); +} template -Slice::Slice(T *s, std::size_t count) noexcept - : ptr(const_cast::type *>(s)), len(count) {} +Slice::Slice(T *s, std::size_t count) noexcept { + void sliceInit(void *, const void *, std::size_t) noexcept; + sliceInit(this, const_cast::type *>(s), count); +} template T *Slice::data() const noexcept { - return reinterpret_cast(this->ptr); + return reinterpret_cast(this->ptr()); } template std::size_t Slice::size() const noexcept { - return this->len; + std::size_t sliceLen(const void *) noexcept; + return sliceLen(this); } template std::size_t Slice::length() const noexcept { - return this->len; + return this->size(); } template bool Slice::empty() const noexcept { - return this->len == 0; + return this->size() == 0; } template T &Slice::operator[](std::size_t n) const noexcept { assert(n < this->size()); - auto pos = static_cast(this->ptr) + size_of() * n; + auto pos = static_cast(this->ptr()) + size_of() * n; return *reinterpret_cast(pos); } @@ -540,7 +544,7 @@ T &Slice::front() const noexcept { template T &Slice::back() const noexcept { assert(!this->empty()); - return (*this)[this->len - 1]; + return (*this)[this->size() - 1]; } template @@ -659,7 +663,7 @@ bool Slice::iterator::operator>=(const iterator &other) const noexcept { template typename Slice::iterator Slice::begin() const noexcept { iterator it; - it.pos = this->ptr; + it.pos = this->ptr(); it.stride = size_of(); return it; } @@ -667,7 +671,7 @@ typename Slice::iterator Slice::begin() const noexcept { template typename Slice::iterator Slice::end() const noexcept { iterator it = this->begin(); - it.pos = static_cast(it.pos) + it.stride * this->len; + it.pos = static_cast(it.pos) + it.stride * this->size(); return it; } @@ -675,6 +679,12 @@ template void Slice::swap(Slice &rhs) noexcept { std::swap(*this, rhs); } + +template +void *Slice::ptr() const noexcept { + void *slicePtr(const void *) noexcept; + return slicePtr(this); +} #endif // CXXBRIDGE1_RUST_SLICE #ifndef CXXBRIDGE1_RUST_BOX diff --git a/src/cxx.cc b/src/cxx.cc index 605845e1a..ccf44b200 100644 --- a/src/cxx.cc +++ b/src/cxx.cc @@ -45,6 +45,12 @@ bool cxxbridge1$str$from(rust::Str *self, const char *ptr, std::size_t len) noexcept; const char *cxxbridge1$str$ptr(const rust::Str *self) noexcept; std::size_t cxxbridge1$str$len(const rust::Str *self) noexcept; + +// rust::Slice +void cxxbridge1$slice$new(void *self, const void *ptr, + std::size_t len) noexcept; +void *cxxbridge1$slice$ptr(const void *self) noexcept; +std::size_t cxxbridge1$slice$len(const void *self) noexcept; } // extern "C" namespace rust { @@ -274,6 +280,16 @@ std::ostream &operator<<(std::ostream &os, const Str &s) { return os; } +void sliceInit(void *self, const void *ptr, std::size_t len) noexcept { + cxxbridge1$slice$new(self, ptr, len); +} + +void *slicePtr(const void *self) noexcept { return cxxbridge1$slice$ptr(self); } + +std::size_t sliceLen(const void *self) noexcept { + return cxxbridge1$slice$len(self); +} + // Rust specifies that usize is ABI compatible with C's uintptr_t. // https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize // However there is no direct Rust equivalent for size_t. C does not guarantee diff --git a/src/rust_slice.rs b/src/rust_slice.rs index 8a5e74b3f..b4b5f2cb0 100644 --- a/src/rust_slice.rs +++ b/src/rust_slice.rs @@ -1,36 +1,37 @@ use core::mem; -use core::ptr::NonNull; +use core::ptr::{self, NonNull}; use core::slice; -// Not necessarily ABI compatible with &[T]. Codegen performs the translation. #[repr(C)] -#[derive(Copy, Clone)] pub struct RustSlice { - pub(crate) ptr: NonNull<()>, - pub(crate) len: usize, + pub(crate) repr: NonNull<[()]>, } impl RustSlice { - pub fn from_ref(s: &[T]) -> Self { + pub fn from_ref(slice: &[T]) -> Self { + let ptr = ptr::slice_from_raw_parts::<()>(slice.as_ptr().cast(), slice.len()); RustSlice { - ptr: NonNull::from(s).cast::<()>(), - len: s.len(), + repr: unsafe { NonNull::new_unchecked(ptr as *mut _) }, } } - pub fn from_mut(s: &mut [T]) -> Self { + pub fn from_mut(slice: &mut [T]) -> Self { + let ptr = ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().cast(), slice.len()); RustSlice { - len: s.len(), - ptr: NonNull::from(s).cast::<()>(), + repr: unsafe { NonNull::new_unchecked(ptr) }, } } pub unsafe fn as_slice<'a, T>(self) -> &'a [T] { - slice::from_raw_parts(self.ptr.as_ptr().cast::(), self.len) + let ptr = self.repr.as_ptr(); + let len = self.repr.as_ref().len(); + slice::from_raw_parts(ptr.cast(), len) } pub unsafe fn as_mut_slice<'a, T>(self) -> &'a mut [T] { - slice::from_raw_parts_mut(self.ptr.as_ptr().cast::(), self.len) + let ptr = self.repr.as_ptr(); + let len = self.repr.as_ref().len(); + slice::from_raw_parts_mut(ptr.cast(), len) } } diff --git a/src/symbols/mod.rs b/src/symbols/mod.rs index a9d158db8..e00bb550e 100644 --- a/src/symbols/mod.rs +++ b/src/symbols/mod.rs @@ -1,4 +1,5 @@ mod exception; +mod rust_slice; mod rust_str; mod rust_string; mod rust_vec; diff --git a/src/symbols/rust_slice.rs b/src/symbols/rust_slice.rs new file mode 100644 index 000000000..055b4dee6 --- /dev/null +++ b/src/symbols/rust_slice.rs @@ -0,0 +1,22 @@ +use crate::rust_slice::RustSlice; +use core::mem::MaybeUninit; +use core::ptr::{self, NonNull}; + +#[export_name = "cxxbridge1$slice$new"] +unsafe extern "C" fn slice_new(this: &mut MaybeUninit, ptr: *const (), len: usize) { + let ptr = ptr::slice_from_raw_parts(ptr, len); + let rust_slice = RustSlice { + repr: NonNull::new_unchecked(ptr as *mut _), + }; + ptr::write(this.as_mut_ptr(), rust_slice); +} + +#[export_name = "cxxbridge1$slice$ptr"] +unsafe extern "C" fn slice_ptr(this: &RustSlice) -> *const () { + this.repr.as_ptr().cast() +} + +#[export_name = "cxxbridge1$slice$len"] +unsafe extern "C" fn slice_len(this: &RustSlice) -> usize { + this.repr.as_ref().len() +} From 0e3f77636279b5cb14da142d7757c50de72fbacf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 2 Jan 2021 15:01:10 -0800 Subject: [PATCH 2/3] Fix slice compilation on MSVC cxxbridge-demo.lib(blobstore.o) : error LNK2019: unresolved external symbol "void __cdecl sliceInit(void *,void const *,unsigned __int64)" (?sliceInit@@YAXPEAXPEBX_K@Z) referenced in function "public: __cdecl rust::cxxbridge1::Slice::Slice(unsigned char const *,unsigned __int64)" (??0?$Slice@$$CBE@cxxbridge1@rust@@QEAA@PEBE_K@Z) cxxbridge-demo.lib(blobstore.o) : error LNK2001: unresolved external symbol "void __cdecl sliceInit(void *,void const *,unsigned __int64)" (?sliceInit@@YAXPEAXPEBX_K@Z) cxxbridge-demo.lib(main.rs.o) : error LNK2001: unresolved external symbol "void __cdecl sliceInit(void *,void const *,unsigned __int64)" (?sliceInit@@YAXPEAXPEBX_K@Z) cxxbridge-demo.lib(main.rs.o) : error LNK2001: unresolved external symbol "void __cdecl sliceInit(void *,void const *,unsigned __int64)" (?sliceInit@@YAXPEAXPEBX_K@Z) Hint on symbols that are defined and could potentially match: "void __cdecl rust::cxxbridge1::sliceInit(void *,void const *,unsigned __int64)" (?sliceInit@cxxbridge1@rust@@YAXPEAXPEBX_K@Z) cxxbridge-demo.lib(blobstore.o) : error LNK2019: unresolved external symbol "unsigned __int64 __cdecl sliceLen(void const *)" (?sliceLen@@YA_KPEBX@Z) referenced in function "public: unsigned __int64 __cdecl rust::cxxbridge1::Slice::size(void)const " (?size@?$Slice@$$CBE@cxxbridge1@rust@@QEBA_KXZ) cxxbridge-demo.lib(main.rs.o) : error LNK2001: unresolved external symbol "unsigned __int64 __cdecl sliceLen(void const *)" (?sliceLen@@YA_KPEBX@Z) Hint on symbols that are defined and could potentially match: "unsigned __int64 __cdecl rust::cxxbridge1::sliceLen(void const *)" (?sliceLen@cxxbridge1@rust@@YA_KPEBX@Z) cxxbridge-demo.lib(blobstore.o) : error LNK2019: unresolved external symbol "void * __cdecl slicePtr(void const *)" (?slicePtr@@YAPEAXPEBX@Z) referenced in function "private: void * __cdecl rust::cxxbridge1::Slice::ptr(void)const " (?ptr@?$Slice@$$CBE@cxxbridge1@rust@@AEBAPEAXXZ) cxxbridge-demo.lib(main.rs.o) : error LNK2001: unresolved external symbol "void * __cdecl slicePtr(void const *)" (?slicePtr@@YAPEAXPEBX@Z) Hint on symbols that are defined and could potentially match: "void * __cdecl rust::cxxbridge1::slicePtr(void const *)" (?slicePtr@cxxbridge1@rust@@YAPEAXPEBX@Z) D:\a\cxx\cxx\target\debug\deps\demo.exe : fatal error LNK1120: 3 unresolved externals --- include/cxx.h | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/include/cxx.h b/include/cxx.h index a81fc2130..acf2b1bfd 100644 --- a/include/cxx.h +++ b/include/cxx.h @@ -180,8 +180,6 @@ class Slice final void swap(Slice &) noexcept; private: - void *ptr() const noexcept; - std::array repr; }; @@ -487,26 +485,27 @@ constexpr unsafe_bitcopy_t unsafe_bitcopy{}; #ifndef CXXBRIDGE1_RUST_SLICE #define CXXBRIDGE1_RUST_SLICE +void sliceInit(void *, const void *, std::size_t) noexcept; +void *slicePtr(const void *) noexcept; +std::size_t sliceLen(const void *) noexcept; + template Slice::Slice() noexcept { - void sliceInit(void *, const void *, std::size_t) noexcept; sliceInit(this, reinterpret_cast(align_of()), 0); } template Slice::Slice(T *s, std::size_t count) noexcept { - void sliceInit(void *, const void *, std::size_t) noexcept; sliceInit(this, const_cast::type *>(s), count); } template T *Slice::data() const noexcept { - return reinterpret_cast(this->ptr()); + return reinterpret_cast(slicePtr(this)); } template std::size_t Slice::size() const noexcept { - std::size_t sliceLen(const void *) noexcept; return sliceLen(this); } @@ -523,7 +522,7 @@ bool Slice::empty() const noexcept { template T &Slice::operator[](std::size_t n) const noexcept { assert(n < this->size()); - auto pos = static_cast(this->ptr()) + size_of() * n; + auto pos = static_cast(slicePtr(this)) + size_of() * n; return *reinterpret_cast(pos); } @@ -663,7 +662,7 @@ bool Slice::iterator::operator>=(const iterator &other) const noexcept { template typename Slice::iterator Slice::begin() const noexcept { iterator it; - it.pos = this->ptr(); + it.pos = slicePtr(this); it.stride = size_of(); return it; } @@ -679,12 +678,6 @@ template void Slice::swap(Slice &rhs) noexcept { std::swap(*this, rhs); } - -template -void *Slice::ptr() const noexcept { - void *slicePtr(const void *) noexcept; - return slicePtr(this); -} #endif // CXXBRIDGE1_RUST_SLICE #ifndef CXXBRIDGE1_RUST_BOX From 0e1cc3da8c58e7dfe6db4e97cae9aa8e6c4bc893 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 2 Jan 2021 15:09:03 -0800 Subject: [PATCH 3/3] Hide slice implementation details from name lookup --- include/cxx.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/cxx.h b/include/cxx.h index acf2b1bfd..41138c84e 100644 --- a/include/cxx.h +++ b/include/cxx.h @@ -180,6 +180,10 @@ class Slice final void swap(Slice &) noexcept; private: + friend void sliceInit(void *, const void *, std::size_t) noexcept; + friend void *slicePtr(const void *) noexcept; + friend std::size_t sliceLen(const void *) noexcept; + std::array repr; }; @@ -485,10 +489,6 @@ constexpr unsafe_bitcopy_t unsafe_bitcopy{}; #ifndef CXXBRIDGE1_RUST_SLICE #define CXXBRIDGE1_RUST_SLICE -void sliceInit(void *, const void *, std::size_t) noexcept; -void *slicePtr(const void *) noexcept; -std::size_t sliceLen(const void *) noexcept; - template Slice::Slice() noexcept { sliceInit(this, reinterpret_cast(align_of()), 0);