Skip to content

Commit 0194dc5

Browse files
authored
Merge pull request #647 from dtolnay/slice
Preserve &[T]'s Rust representation in rust::Slice
2 parents 2a58a8a + 0e1cc3d commit 0194dc5

File tree

5 files changed

+72
-29
lines changed

5 files changed

+72
-29
lines changed

include/cxx.h

+19-16
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,11 @@ 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+
friend void sliceInit(void *, const void *, std::size_t) noexcept;
184+
friend void *slicePtr(const void *) noexcept;
185+
friend std::size_t sliceLen(const void *) noexcept;
186+
187+
std::array<std::uintptr_t, 2> repr;
187188
};
188189

189190
template <typename T>
@@ -489,37 +490,39 @@ constexpr unsafe_bitcopy_t unsafe_bitcopy{};
489490
#ifndef CXXBRIDGE1_RUST_SLICE
490491
#define CXXBRIDGE1_RUST_SLICE
491492
template <typename T>
492-
Slice<T>::Slice() noexcept
493-
: ptr(reinterpret_cast<void *>(align_of<T>())), len(0) {}
493+
Slice<T>::Slice() noexcept {
494+
sliceInit(this, reinterpret_cast<void *>(align_of<T>()), 0);
495+
}
494496

495497
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) {}
498+
Slice<T>::Slice(T *s, std::size_t count) noexcept {
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 *>(slicePtr(this));
502505
}
503506

504507
template <typename T>
505508
std::size_t Slice<T>::size() const noexcept {
506-
return this->len;
509+
return sliceLen(this);
507510
}
508511

509512
template <typename T>
510513
std::size_t Slice<T>::length() const noexcept {
511-
return this->len;
514+
return this->size();
512515
}
513516

514517
template <typename T>
515518
bool Slice<T>::empty() const noexcept {
516-
return this->len == 0;
519+
return this->size() == 0;
517520
}
518521

519522
template <typename T>
520523
T &Slice<T>::operator[](std::size_t n) const noexcept {
521524
assert(n < this->size());
522-
auto pos = static_cast<char *>(this->ptr) + size_of<T>() * n;
525+
auto pos = static_cast<char *>(slicePtr(this)) + size_of<T>() * n;
523526
return *reinterpret_cast<T *>(pos);
524527
}
525528

@@ -540,7 +543,7 @@ T &Slice<T>::front() const noexcept {
540543
template <typename T>
541544
T &Slice<T>::back() const noexcept {
542545
assert(!this->empty());
543-
return (*this)[this->len - 1];
546+
return (*this)[this->size() - 1];
544547
}
545548

546549
template <typename T>
@@ -659,15 +662,15 @@ bool Slice<T>::iterator::operator>=(const iterator &other) const noexcept {
659662
template <typename T>
660663
typename Slice<T>::iterator Slice<T>::begin() const noexcept {
661664
iterator it;
662-
it.pos = this->ptr;
665+
it.pos = slicePtr(this);
663666
it.stride = size_of<T>();
664667
return it;
665668
}
666669

667670
template <typename T>
668671
typename Slice<T>::iterator Slice<T>::end() const noexcept {
669672
iterator it = this->begin();
670-
it.pos = static_cast<char *>(it.pos) + it.stride * this->len;
673+
it.pos = static_cast<char *>(it.pos) + it.stride * this->size();
671674
return it;
672675
}
673676

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) noexcept {
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)