Skip to content

Commit 61ffe41

Browse files
committed
&mut [u8] support
1 parent 36c2f84 commit 61ffe41

File tree

10 files changed

+176
-19
lines changed

10 files changed

+176
-19
lines changed

gen/src/builtin.rs

+35
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub struct Builtins<'a> {
88
pub rust_string: bool,
99
pub rust_str: bool,
1010
pub rust_slice: bool,
11+
pub rust_mut_slice: bool,
1112
pub rust_box: bool,
1213
pub rust_vec: bool,
1314
pub rust_fn: bool,
@@ -22,6 +23,8 @@ pub struct Builtins<'a> {
2223
pub rust_str_repr: bool,
2324
pub rust_slice_new: bool,
2425
pub rust_slice_repr: bool,
26+
pub rust_mut_slice_new: bool,
27+
pub rust_mut_slice_repr: bool,
2528
pub exception: bool,
2629
pub relocatable: bool,
2730
pub friend_impl: bool,
@@ -59,6 +62,10 @@ pub(super) fn write(out: &mut OutFile) {
5962
builtin.friend_impl = true;
6063
}
6164

65+
if builtin.rust_mut_slice {
66+
builtin.friend_impl = true;
67+
}
68+
6269
if builtin.rust_box {
6370
include.new = true;
6471
include.type_traits = true;
@@ -112,6 +119,7 @@ pub(super) fn write(out: &mut OutFile) {
112119
ifndef::write(out, builtin.rust_string, "CXXBRIDGE05_RUST_STRING");
113120
ifndef::write(out, builtin.rust_str, "CXXBRIDGE05_RUST_STR");
114121
ifndef::write(out, builtin.rust_slice, "CXXBRIDGE05_RUST_SLICE");
122+
ifndef::write(out, builtin.rust_mut_slice, "CXXBRIDGE05_RUST_MUT_SLICE");
115123
ifndef::write(out, builtin.rust_box, "CXXBRIDGE05_RUST_BOX");
116124
ifndef::write(out, builtin.unsafe_bitcopy, "CXXBRIDGE05_RUST_BITCOPY");
117125
ifndef::write(out, builtin.rust_vec, "CXXBRIDGE05_RUST_VEC");
@@ -206,6 +214,33 @@ pub(super) fn write(out: &mut OutFile) {
206214
writeln!(out, "}};");
207215
}
208216

217+
if builtin.rust_mut_slice_new || builtin.rust_mut_slice_repr {
218+
out.next_section();
219+
writeln!(out, "template <typename T>");
220+
writeln!(out, "class impl<MutSlice<T>> final {{");
221+
writeln!(out, "public:");
222+
if builtin.rust_mut_slice_new {
223+
writeln!(
224+
out,
225+
" static MutSlice<T> slice(repr::PtrLen repr) noexcept {{",
226+
);
227+
writeln!(
228+
out,
229+
" return {{static_cast<T *>(repr.ptr), repr.len}};",
230+
);
231+
writeln!(out, " }}");
232+
}
233+
if builtin.rust_mut_slice_repr {
234+
writeln!(
235+
out,
236+
" static repr::PtrLen repr(MutSlice<T> slice) noexcept {{",
237+
);
238+
writeln!(out, " return repr::PtrLen{{slice.ptr, slice.len}};");
239+
writeln!(out, " }}");
240+
}
241+
writeln!(out, "}};");
242+
}
243+
209244
if builtin.rust_error {
210245
out.next_section();
211246
writeln!(out, "template <>");

gen/src/write.rs

+35-12
Original file line numberDiff line numberDiff line change
@@ -168,9 +168,10 @@ fn pick_includes_and_builtins(out: &mut OutFile, apis: &[Api]) {
168168
Type::CxxVector(_) => out.include.vector = true,
169169
Type::Fn(_) => out.builtin.rust_fn = true,
170170
Type::Slice(_) => out.builtin.rust_slice = true,
171-
Type::SliceRefU8(_) => {
171+
Type::SliceRefU8(ty) => {
172172
out.include.cstdint = true;
173-
out.builtin.rust_slice = true;
173+
out.builtin.rust_slice |= ty.mutability.is_none();
174+
out.builtin.rust_mut_slice |= ty.mutability.is_some();
174175
}
175176
Type::Ref(_) | Type::Void(_) => {}
176177
}
@@ -430,10 +431,14 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
430431
out.builtin.rust_str_repr = true;
431432
write!(out, "::rust::impl<::rust::Str>::repr(");
432433
}
433-
Some(Type::SliceRefU8(_)) if !indirect_return => {
434+
Some(Type::SliceRefU8(ty)) if !indirect_return && ty.mutability.is_none() => {
434435
out.builtin.rust_slice_repr = true;
435436
write!(out, "::rust::impl<::rust::Slice<uint8_t>>::repr(")
436437
}
438+
Some(Type::SliceRefU8(_)) if !indirect_return => {
439+
out.builtin.rust_mut_slice_repr = true;
440+
write!(out, "::rust::impl<::rust::MutSlice<uint8_t>>::repr(")
441+
}
437442
_ => {}
438443
}
439444
match &efn.receiver {
@@ -468,12 +473,19 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
468473
out.builtin.unsafe_bitcopy = true;
469474
write_type(out, &arg.ty);
470475
write!(out, "(::rust::unsafe_bitcopy, *{})", arg.ident);
471-
} else if let Type::SliceRefU8(_) = arg.ty {
472-
write!(
473-
out,
474-
"::rust::Slice<uint8_t>(static_cast<const uint8_t *>({0}.ptr), {0}.len)",
475-
arg.ident,
476-
);
476+
} else if let Type::SliceRefU8(ref ty) = arg.ty {
477+
match ty.mutability {
478+
None => write!(
479+
out,
480+
"::rust::Slice<uint8_t>(static_cast<const uint8_t *>({0}.ptr), {0}.len)",
481+
arg.ident,
482+
),
483+
Some(_) => write!(
484+
out,
485+
"::rust::MutSlice<uint8_t>(static_cast<uint8_t *>({0}.ptr), {0}.len)",
486+
arg.ident,
487+
)
488+
}
477489
} else if out.types.needs_indirect_abi(&arg.ty) {
478490
out.include.utility = true;
479491
write!(out, "::std::move(*{})", arg.ident);
@@ -686,10 +698,14 @@ fn write_rust_function_shim_impl(
686698
out.builtin.rust_str_new_unchecked = true;
687699
write!(out, "::rust::impl<::rust::Str>::new_unchecked(");
688700
}
689-
Type::SliceRefU8(_) => {
701+
Type::SliceRefU8(ty) if ty.mutability.is_none() => {
690702
out.builtin.rust_slice_new = true;
691703
write!(out, "::rust::impl<::rust::Slice<uint8_t>>::slice(");
692704
}
705+
Type::SliceRefU8(_) => {
706+
out.builtin.rust_mut_slice_new = true;
707+
write!(out, "::rust::impl<::rust::MutSlice<uint8_t>>::slice(");
708+
}
693709
_ => {}
694710
}
695711
}
@@ -712,10 +728,14 @@ fn write_rust_function_shim_impl(
712728
out.builtin.rust_str_repr = true;
713729
write!(out, "::rust::impl<::rust::Str>::repr(");
714730
}
715-
Type::SliceRefU8(_) => {
731+
Type::SliceRefU8(ty) if ty.mutability.is_none() => {
716732
out.builtin.rust_slice_repr = true;
717733
write!(out, "::rust::impl<::rust::Slice<uint8_t>>::repr(");
718734
}
735+
Type::SliceRefU8(_) => {
736+
out.builtin.rust_mut_slice_repr = true;
737+
write!(out, "::rust::impl<::rust::MutSlice<uint8_t>>::repr(");
738+
}
719739
ty if out.types.needs_indirect_abi(ty) => write!(out, "&"),
720740
_ => {}
721741
}
@@ -884,9 +904,12 @@ fn write_type(out: &mut OutFile, ty: &Type) {
884904
Type::Str(_) => {
885905
write!(out, "::rust::Str");
886906
}
887-
Type::SliceRefU8(_) => {
907+
Type::SliceRefU8(ty) if ty.mutability.is_none() => {
888908
write!(out, "::rust::Slice<uint8_t>");
889909
}
910+
Type::SliceRefU8(_) => {
911+
write!(out, "::rust::MutSlice<uint8_t>");
912+
}
890913
Type::Fn(f) => {
891914
write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
892915
match &f.ret {

include/cxx.h

+50
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,32 @@ class Slice final {
113113
};
114114
#endif // CXXBRIDGE05_RUST_SLICE
115115

116+
#ifndef CXXBRIDGE05_RUST_MUT_SLICE
117+
template <typename T>
118+
class MutSlice final {
119+
public:
120+
MutSlice() noexcept;
121+
MutSlice(T *, size_t count) noexcept;
122+
123+
MutSlice &operator=(const MutSlice<T> &) noexcept = default;
124+
125+
T *data() const noexcept;
126+
size_t size() const noexcept;
127+
size_t length() const noexcept;
128+
129+
// Important in order for System V ABI to pass in registers.
130+
MutSlice(const MutSlice<T> &) noexcept = default;
131+
~MutSlice() noexcept = default;
132+
133+
private:
134+
friend impl<MutSlice>;
135+
// Not necessarily ABI compatible with &mut [T]. Codegen will translate to
136+
// cxx::rust_mutsliceu8::RustMutSliceU8 which matches this layout.
137+
T *ptr;
138+
size_t len;
139+
};
140+
#endif // CXXBRIDGE05_RUST_MUT_SLICE
141+
116142
#ifndef CXXBRIDGE05_RUST_BOX
117143
template <typename T>
118144
class Box final {
@@ -379,6 +405,30 @@ size_t Slice<T>::length() const noexcept {
379405
}
380406
#endif // CXXBRIDGE05_RUST_SLICE
381407

408+
#ifndef CXXBRIDGE05_RUST_MUT_SLICE
409+
#define CXXBRIDGE05_RUST_MUT_SLICE
410+
template <typename T>
411+
MutSlice<T>::MutSlice() noexcept : ptr(reinterpret_cast<T *>(this)), len(0) {}
412+
413+
template <typename T>
414+
MutSlice<T>::MutSlice(T *s, size_t count) noexcept : ptr(s), len(count) {}
415+
416+
template <typename T>
417+
T *MutSlice<T>::data() const noexcept {
418+
return this->ptr;
419+
}
420+
421+
template <typename T>
422+
size_t MutSlice<T>::size() const noexcept {
423+
return this->len;
424+
}
425+
426+
template <typename T>
427+
size_t MutSlice<T>::length() const noexcept {
428+
return this->len;
429+
}
430+
#endif // CXXBRIDGE05_RUST_MUT_SLICE
431+
382432
#ifndef CXXBRIDGE05_RUST_BOX
383433
#define CXXBRIDGE05_RUST_BOX
384434
template <typename T>

macro/src/expand.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,8 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
294294
_ => quote!(#var),
295295
},
296296
Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
297-
Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8::from(#var)),
297+
Type::SliceRefU8(ty) if ty.mutability.is_none() => quote!(::cxx::private::RustSliceU8::from(#var)),
298+
Type::SliceRefU8(_) => quote!(::cxx::private::RustMutSliceU8::from(#var)),
298299
ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
299300
_ => quote!(#var),
300301
}
@@ -387,7 +388,8 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
387388
_ => call,
388389
},
389390
Type::Str(_) => quote!(#call.as_str()),
390-
Type::SliceRefU8(_) => quote!(#call.as_slice()),
391+
Type::SliceRefU8(ty) if ty.mutability.is_none() => quote!(#call.as_slice()),
392+
Type::SliceRefU8(ty) if ty.mutability.is_some() => quote!(#call.as_mut_slice()),
391393
_ => call,
392394
},
393395
};
@@ -600,7 +602,8 @@ fn expand_rust_function_shim_impl(
600602
_ => None,
601603
},
602604
Type::Str(_) => Some(quote!(::cxx::private::RustStr::from)),
603-
Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustSliceU8::from)),
605+
Type::SliceRefU8(ty) if ty.mutability.is_none() => Some(quote!(::cxx::private::RustSliceU8::from)),
606+
Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustMutSliceU8::from)),
604607
_ => None,
605608
});
606609

@@ -1038,7 +1041,8 @@ fn expand_extern_type(ty: &Type, types: &Types, proper: bool) -> TokenStream {
10381041
}
10391042
}
10401043
Type::Str(_) => quote!(::cxx::private::RustStr),
1041-
Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8),
1044+
Type::SliceRefU8(ty) if ty.mutability.is_none() => quote!(::cxx::private::RustSliceU8),
1045+
Type::SliceRefU8(_) => quote!(::cxx::private::RustMutSliceU8),
10421046
_ => quote!(#ty),
10431047
}
10441048
}

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ mod function;
383383
mod opaque;
384384
mod result;
385385
mod rust_sliceu8;
386+
mod rust_mutsliceu8;
386387
mod rust_str;
387388
mod rust_string;
388389
mod rust_vec;
@@ -425,6 +426,7 @@ pub mod private {
425426
pub use crate::opaque::Opaque;
426427
pub use crate::result::{r#try, Result};
427428
pub use crate::rust_sliceu8::RustSliceU8;
429+
pub use crate::rust_mutsliceu8::RustMutSliceU8;
428430
pub use crate::rust_str::RustStr;
429431
pub use crate::rust_string::RustString;
430432
pub use crate::rust_vec::RustVec;

src/rust_mutsliceu8.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use core::mem;
2+
use core::ptr::NonNull;
3+
use core::slice;
4+
5+
// Not necessarily ABI compatible with &mut [u8]. Codegen performs the translation.
6+
#[repr(C)]
7+
#[derive(Copy, Clone)]
8+
pub struct RustMutSliceU8 {
9+
pub(crate) ptr: NonNull<u8>,
10+
pub(crate) len: usize,
11+
}
12+
13+
impl RustMutSliceU8 {
14+
pub fn from(s: &mut [u8]) -> Self {
15+
let len = s.len();
16+
RustMutSliceU8 {
17+
ptr: NonNull::from(s).cast::<u8>(),
18+
len,
19+
}
20+
}
21+
22+
pub unsafe fn as_slice<'a>(self) -> &'a mut [u8] {
23+
slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len)
24+
}
25+
}
26+
27+
const_assert_eq!(
28+
mem::size_of::<Option<RustMutSliceU8>>(),
29+
mem::size_of::<RustMutSliceU8>(),
30+
);

syntax/check.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ fn check_type_ref(cx: &mut Check, ty: &Ref) {
163163
}
164164

165165
fn check_type_slice(cx: &mut Check, ty: &Slice) {
166-
cx.error(ty, "only &[u8] is supported so far, not other slice types");
166+
cx.error(ty, "only &[u8] and &mut [u8] are supported so far, not other slice types");
167167
}
168168

169169
fn check_api_struct(cx: &mut Check, strct: &Struct) {
@@ -421,7 +421,8 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
421421
Type::Str(_) => "&str".to_owned(),
422422
Type::CxxVector(_) => "C++ vector".to_owned(),
423423
Type::Slice(_) => "slice".to_owned(),
424-
Type::SliceRefU8(_) => "&[u8]".to_owned(),
424+
Type::SliceRefU8(ty) if ty.mutability.is_none() => "&[u8]".to_owned(),
425+
Type::SliceRefU8(_) => "&mut [u8]".to_owned(),
425426
Type::Fn(_) => "function pointer".to_owned(),
426427
Type::Void(_) => "()".to_owned(),
427428
}

syntax/parse.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ fn parse_type_reference(ty: &TypeReference, namespace: &Namespace) -> Result<Typ
600600
}
601601
}
602602
Type::Slice(slice) => match &slice.inner {
603-
Type::Ident(ident) if ident.rust == U8 && ty.mutability.is_none() => Type::SliceRefU8,
603+
Type::Ident(ident) if ident.rust == U8 => Type::SliceRefU8,
604604
_ => Type::Ref,
605605
},
606606
_ => Type::Ref,

tests/ffi/lib.rs

+9
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ pub mod ffi {
129129
fn c_return_mut(shared: &mut Shared) -> &mut usize;
130130
fn c_return_str(shared: &Shared) -> &str;
131131
fn c_return_sliceu8(shared: &Shared) -> &[u8];
132+
fn c_return_mutsliceu8(shared: &Shared) -> &mut [u8];
132133
fn c_return_rust_string() -> String;
133134
fn c_return_unique_ptr_string() -> UniquePtr<CxxString>;
134135
fn c_return_unique_ptr_vector_u8() -> UniquePtr<CxxVector<u8>>;
@@ -157,6 +158,7 @@ pub mod ffi {
157158
fn c_take_ref_c(c: &C);
158159
fn c_take_str(s: &str);
159160
fn c_take_sliceu8(s: &[u8]);
161+
fn c_take_mutsliceu8(s: &mut [u8]);
160162
fn c_take_rust_string(s: String);
161163
fn c_take_unique_ptr_string(s: UniquePtr<CxxString>);
162164
fn c_take_unique_ptr_vector_u8(v: UniquePtr<CxxVector<u8>>);
@@ -192,6 +194,7 @@ pub mod ffi {
192194
fn c_try_return_ref(s: &String) -> Result<&String>;
193195
fn c_try_return_str(s: &str) -> Result<&str>;
194196
fn c_try_return_sliceu8(s: &[u8]) -> Result<&[u8]>;
197+
fn c_try_return_mutsliceu8(s: &mut [u8]) -> Result<&mut [u8]>;
195198
fn c_try_return_rust_string() -> Result<String>;
196199
fn c_try_return_unique_ptr_string() -> Result<UniquePtr<CxxString>>;
197200
fn c_try_return_rust_vec() -> Result<Vec<u8>>;
@@ -258,6 +261,7 @@ pub mod ffi {
258261
fn r_take_ref_c(c: &C);
259262
fn r_take_str(s: &str);
260263
fn r_take_sliceu8(s: &[u8]);
264+
fn r_take_mutsliceu8(s: &mut [u8]);
261265
fn r_take_rust_string(s: String);
262266
fn r_take_unique_ptr_string(s: UniquePtr<CxxString>);
263267
fn r_take_ref_vector(v: &CxxVector<u8>);
@@ -452,6 +456,11 @@ fn r_take_sliceu8(s: &[u8]) {
452456
assert_eq!(std::str::from_utf8(s).unwrap(), "2020\0");
453457
}
454458

459+
fn r_take_mutsliceu8(s: &mut [u8]) {
460+
assert_eq!(s.len(), 5);
461+
assert_eq!(std::str::from_utf8(s).unwrap(), "2020\0");
462+
}
463+
455464
fn r_take_unique_ptr_string(s: UniquePtr<CxxString>) {
456465
assert_eq!(s.as_ref().unwrap().to_str().unwrap(), "2020");
457466
}

0 commit comments

Comments
 (0)