Skip to content

Commit 0865aee

Browse files
committed
Preserve &[T]'s Rust representation in rust::Slice
1 parent 2a58a8a commit 0865aee

File tree

5 files changed

+79
-29
lines changed

5 files changed

+79
-29
lines changed

include/cxx.h

+26-16
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,9 @@ class Slice final
180180
void swap(Slice &) noexcept;
181181

182182
private:
183-
// Not necessarily ABI compatible with &[T]. Codegen will translate to
184-
// cxx::rust_slice::RustSlice which matches this layout.
185-
void *ptr;
186-
std::size_t len;
183+
void *ptr() const noexcept;
184+
185+
std::array<std::uintptr_t, 2> repr;
187186
};
188187

189188
template <typename T>
@@ -489,37 +488,42 @@ constexpr unsafe_bitcopy_t unsafe_bitcopy{};
489488
#ifndef CXXBRIDGE1_RUST_SLICE
490489
#define CXXBRIDGE1_RUST_SLICE
491490
template <typename T>
492-
Slice<T>::Slice() noexcept
493-
: ptr(reinterpret_cast<void *>(align_of<T>())), len(0) {}
491+
Slice<T>::Slice() noexcept {
492+
void sliceInit(void *, const void *, std::size_t);
493+
sliceInit(this, reinterpret_cast<void *>(align_of<T>()), 0);
494+
}
494495

495496
template <typename T>
496-
Slice<T>::Slice(T *s, std::size_t count) noexcept
497-
: ptr(const_cast<typename std::remove_const<T>::type *>(s)), len(count) {}
497+
Slice<T>::Slice(T *s, std::size_t count) noexcept {
498+
void sliceInit(void *, const void *, std::size_t);
499+
sliceInit(this, const_cast<typename std::remove_const<T>::type *>(s), count);
500+
}
498501

499502
template <typename T>
500503
T *Slice<T>::data() const noexcept {
501-
return reinterpret_cast<T *>(this->ptr);
504+
return reinterpret_cast<T *>(this->ptr());
502505
}
503506

504507
template <typename T>
505508
std::size_t Slice<T>::size() const noexcept {
506-
return this->len;
509+
std::size_t sliceLen(const void *);
510+
return sliceLen(this);
507511
}
508512

509513
template <typename T>
510514
std::size_t Slice<T>::length() const noexcept {
511-
return this->len;
515+
return this->size();
512516
}
513517

514518
template <typename T>
515519
bool Slice<T>::empty() const noexcept {
516-
return this->len == 0;
520+
return this->size() == 0;
517521
}
518522

519523
template <typename T>
520524
T &Slice<T>::operator[](std::size_t n) const noexcept {
521525
assert(n < this->size());
522-
auto pos = static_cast<char *>(this->ptr) + size_of<T>() * n;
526+
auto pos = static_cast<char *>(this->ptr()) + size_of<T>() * n;
523527
return *reinterpret_cast<T *>(pos);
524528
}
525529

@@ -540,7 +544,7 @@ T &Slice<T>::front() const noexcept {
540544
template <typename T>
541545
T &Slice<T>::back() const noexcept {
542546
assert(!this->empty());
543-
return (*this)[this->len - 1];
547+
return (*this)[this->size() - 1];
544548
}
545549

546550
template <typename T>
@@ -659,22 +663,28 @@ bool Slice<T>::iterator::operator>=(const iterator &other) const noexcept {
659663
template <typename T>
660664
typename Slice<T>::iterator Slice<T>::begin() const noexcept {
661665
iterator it;
662-
it.pos = this->ptr;
666+
it.pos = this->ptr();
663667
it.stride = size_of<T>();
664668
return it;
665669
}
666670

667671
template <typename T>
668672
typename Slice<T>::iterator Slice<T>::end() const noexcept {
669673
iterator it = this->begin();
670-
it.pos = static_cast<char *>(it.pos) + it.stride * this->len;
674+
it.pos = static_cast<char *>(it.pos) + it.stride * this->size();
671675
return it;
672676
}
673677

674678
template <typename T>
675679
void Slice<T>::swap(Slice &rhs) noexcept {
676680
std::swap(*this, rhs);
677681
}
682+
683+
template <typename T>
684+
void *Slice<T>::ptr() const noexcept {
685+
void *slicePtr(const void *);
686+
return slicePtr(this);
687+
}
678688
#endif // CXXBRIDGE1_RUST_SLICE
679689

680690
#ifndef CXXBRIDGE1_RUST_BOX

src/cxx.cc

+16
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ bool cxxbridge1$str$from(rust::Str *self, const char *ptr,
4545
std::size_t len) noexcept;
4646
const char *cxxbridge1$str$ptr(const rust::Str *self) noexcept;
4747
std::size_t cxxbridge1$str$len(const rust::Str *self) noexcept;
48+
49+
// rust::Slice
50+
void cxxbridge1$slice$new(void *self, const void *ptr,
51+
std::size_t len) noexcept;
52+
void *cxxbridge1$slice$ptr(const void *self) noexcept;
53+
std::size_t cxxbridge1$slice$len(const void *self) noexcept;
4854
} // extern "C"
4955

5056
namespace rust {
@@ -274,6 +280,16 @@ std::ostream &operator<<(std::ostream &os, const Str &s) {
274280
return os;
275281
}
276282

283+
void sliceInit(void *self, const void *ptr, std::size_t len) {
284+
cxxbridge1$slice$new(self, ptr, len);
285+
}
286+
287+
void *slicePtr(const void *self) noexcept { return cxxbridge1$slice$ptr(self); }
288+
289+
std::size_t sliceLen(const void *self) noexcept {
290+
return cxxbridge1$slice$len(self);
291+
}
292+
277293
// Rust specifies that usize is ABI compatible with C's uintptr_t.
278294
// https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize
279295
// However there is no direct Rust equivalent for size_t. C does not guarantee

src/rust_slice.rs

+14-13
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,37 @@
11
use core::mem;
2-
use core::ptr::NonNull;
2+
use core::ptr::{self, NonNull};
33
use core::slice;
44

5-
// Not necessarily ABI compatible with &[T]. Codegen performs the translation.
65
#[repr(C)]
7-
#[derive(Copy, Clone)]
86
pub struct RustSlice {
9-
pub(crate) ptr: NonNull<()>,
10-
pub(crate) len: usize,
7+
pub(crate) repr: NonNull<[()]>,
118
}
129

1310
impl RustSlice {
14-
pub fn from_ref<T>(s: &[T]) -> Self {
11+
pub fn from_ref<T>(slice: &[T]) -> Self {
12+
let ptr = ptr::slice_from_raw_parts::<()>(slice.as_ptr().cast(), slice.len());
1513
RustSlice {
16-
ptr: NonNull::from(s).cast::<()>(),
17-
len: s.len(),
14+
repr: unsafe { NonNull::new_unchecked(ptr as *mut _) },
1815
}
1916
}
2017

21-
pub fn from_mut<T>(s: &mut [T]) -> Self {
18+
pub fn from_mut<T>(slice: &mut [T]) -> Self {
19+
let ptr = ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().cast(), slice.len());
2220
RustSlice {
23-
len: s.len(),
24-
ptr: NonNull::from(s).cast::<()>(),
21+
repr: unsafe { NonNull::new_unchecked(ptr) },
2522
}
2623
}
2724

2825
pub unsafe fn as_slice<'a, T>(self) -> &'a [T] {
29-
slice::from_raw_parts(self.ptr.as_ptr().cast::<T>(), self.len)
26+
let ptr = self.repr.as_ptr();
27+
let len = self.repr.as_ref().len();
28+
slice::from_raw_parts(ptr.cast(), len)
3029
}
3130

3231
pub unsafe fn as_mut_slice<'a, T>(self) -> &'a mut [T] {
33-
slice::from_raw_parts_mut(self.ptr.as_ptr().cast::<T>(), self.len)
32+
let ptr = self.repr.as_ptr();
33+
let len = self.repr.as_ref().len();
34+
slice::from_raw_parts_mut(ptr.cast(), len)
3435
}
3536
}
3637

src/symbols/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod exception;
2+
mod rust_slice;
23
mod rust_str;
34
mod rust_string;
45
mod rust_vec;

src/symbols/rust_slice.rs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::rust_slice::RustSlice;
2+
use core::mem::MaybeUninit;
3+
use core::ptr::{self, NonNull};
4+
5+
#[export_name = "cxxbridge1$slice$new"]
6+
unsafe extern "C" fn slice_new(this: &mut MaybeUninit<RustSlice>, ptr: *const (), len: usize) {
7+
let ptr = ptr::slice_from_raw_parts(ptr, len);
8+
let rust_slice = RustSlice {
9+
repr: NonNull::new_unchecked(ptr as *mut _),
10+
};
11+
ptr::write(this.as_mut_ptr(), rust_slice);
12+
}
13+
14+
#[export_name = "cxxbridge1$slice$ptr"]
15+
unsafe extern "C" fn slice_ptr(this: &RustSlice) -> *const () {
16+
this.repr.as_ptr().cast()
17+
}
18+
19+
#[export_name = "cxxbridge1$slice$len"]
20+
unsafe extern "C" fn slice_len(this: &RustSlice) -> usize {
21+
this.repr.as_ref().len()
22+
}

0 commit comments

Comments
 (0)