Skip to content

Commit c5629f0

Browse files
committed
Support &mut [u8]
1 parent cd271f2 commit c5629f0

File tree

11 files changed

+123
-32
lines changed

11 files changed

+123
-32
lines changed

gen/src/builtin.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ pub(super) fn write(out: &mut OutFile) {
149149
if builtin.ptr_len {
150150
out.begin_block(Block::Namespace("repr"));
151151
writeln!(out, "struct PtrLen final {{");
152-
writeln!(out, " const void *ptr;");
152+
writeln!(out, " void *ptr;");
153153
writeln!(out, " size_t len;");
154154
writeln!(out, "}};");
155155
out.end_block(Block::Namespace("repr"));
@@ -173,7 +173,10 @@ pub(super) fn write(out: &mut OutFile) {
173173
}
174174
if builtin.rust_str_repr {
175175
writeln!(out, " static repr::PtrLen repr(Str str) noexcept {{");
176-
writeln!(out, " return repr::PtrLen{{str.ptr, str.len}};");
176+
writeln!(
177+
out,
178+
" return repr::PtrLen{{const_cast<char *>(str.ptr), str.len}};",
179+
);
177180
writeln!(out, " }}");
178181
}
179182
writeln!(out, "}};");
@@ -189,18 +192,21 @@ pub(super) fn write(out: &mut OutFile) {
189192
out,
190193
" static Slice<T> slice(repr::PtrLen repr) noexcept {{",
191194
);
192-
writeln!(
193-
out,
194-
" return {{static_cast<const T *>(repr.ptr), repr.len}};",
195-
);
195+
writeln!(out, " return {{static_cast<T *>(repr.ptr), repr.len}};");
196196
writeln!(out, " }}");
197197
}
198198
if builtin.rust_slice_repr {
199+
include.type_traits = true;
199200
writeln!(
200201
out,
201202
" static repr::PtrLen repr(Slice<T> slice) noexcept {{",
202203
);
203-
writeln!(out, " return repr::PtrLen{{slice.ptr, slice.len}};");
204+
writeln!(out, " return repr::PtrLen{{");
205+
writeln!(
206+
out,
207+
" const_cast<typename ::std::remove_const<T>::type *>(slice.ptr),",
208+
);
209+
writeln!(out, " slice.len}};");
204210
writeln!(out, " }}");
205211
}
206212
writeln!(out, "}};");

gen/src/write.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -436,9 +436,11 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
436436
out.builtin.rust_str_repr = true;
437437
write!(out, "::rust::impl<::rust::Str>::repr(");
438438
}
439-
Some(Type::SliceRefU8(_)) if !indirect_return => {
439+
Some(ty @ Type::SliceRefU8(_)) if !indirect_return => {
440440
out.builtin.rust_slice_repr = true;
441-
write!(out, "::rust::impl<::rust::Slice<const uint8_t>>::repr(")
441+
write!(out, "::rust::impl<");
442+
write_type(out, ty);
443+
write!(out, ">::repr(");
442444
}
443445
_ => {}
444446
}
@@ -474,12 +476,13 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
474476
out.builtin.unsafe_bitcopy = true;
475477
write_type(out, &arg.ty);
476478
write!(out, "(::rust::unsafe_bitcopy, *{})", arg.ident);
477-
} else if let Type::SliceRefU8(_) = arg.ty {
478-
write!(
479-
out,
480-
"::rust::Slice<const uint8_t>(static_cast<const uint8_t *>({0}.ptr), {0}.len)",
481-
arg.ident,
482-
);
479+
} else if let Type::SliceRefU8(slice) = &arg.ty {
480+
write_type(out, &arg.ty);
481+
write!(out, "(static_cast<");
482+
if slice.mutability.is_none() {
483+
write!(out, "const ");
484+
}
485+
write!(out, "uint8_t *>({0}.ptr), {0}.len)", arg.ident);
483486
} else if out.types.needs_indirect_abi(&arg.ty) {
484487
out.include.utility = true;
485488
write!(out, "::std::move(*{})", arg.ident);
@@ -507,7 +510,7 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
507510
writeln!(out, " throw$.len = ::std::strlen(catch$);");
508511
writeln!(
509512
out,
510-
" throw$.ptr = ::cxxbridge1$exception(catch$, throw$.len);",
513+
" throw$.ptr = const_cast<char *>(::cxxbridge1$exception(catch$, throw$.len));",
511514
);
512515
writeln!(out, " }});");
513516
writeln!(out, " return throw$;");
@@ -694,7 +697,9 @@ fn write_rust_function_shim_impl(
694697
}
695698
Type::SliceRefU8(_) => {
696699
out.builtin.rust_slice_new = true;
697-
write!(out, "::rust::impl<::rust::Slice<const uint8_t>>::slice(");
700+
write!(out, "::rust::impl<");
701+
write_type(out, ret);
702+
write!(out, ">::slice(");
698703
}
699704
_ => {}
700705
}
@@ -720,7 +725,9 @@ fn write_rust_function_shim_impl(
720725
}
721726
Type::SliceRefU8(_) => {
722727
out.builtin.rust_slice_repr = true;
723-
write!(out, "::rust::impl<::rust::Slice<const uint8_t>>::repr(");
728+
write!(out, "::rust::impl<");
729+
write_type(out, &arg.ty);
730+
write!(out, ">::repr(");
724731
}
725732
ty if out.types.needs_indirect_abi(ty) => write!(out, "&"),
726733
_ => {}
@@ -890,8 +897,12 @@ fn write_type(out: &mut OutFile, ty: &Type) {
890897
Type::Str(_) => {
891898
write!(out, "::rust::Str");
892899
}
893-
Type::SliceRefU8(_) => {
894-
write!(out, "::rust::Slice<const uint8_t>");
900+
Type::SliceRefU8(ty) => {
901+
write!(out, "::rust::Slice<");
902+
if ty.mutability.is_none() {
903+
write!(out, "const ");
904+
}
905+
write!(out, "uint8_t>");
895906
}
896907
Type::Fn(f) => {
897908
write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });

include/cxx.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,28 @@ class Str final {
8787
#endif // CXXBRIDGE1_RUST_STR
8888

8989
#ifndef CXXBRIDGE1_RUST_SLICE
90-
template <typename T>
91-
class Slice final {
92-
static_assert(std::is_const<T>::value,
93-
"&[T] needs to be written as rust::Slice<const T> in C++");
90+
namespace detail {
91+
template <bool cond>
92+
struct copy_assignable_if {};
93+
94+
template <>
95+
struct copy_assignable_if<false> {
96+
copy_assignable_if() noexcept = default;
97+
copy_assignable_if(const copy_assignable_if &) noexcept = default;
98+
copy_assignable_if &operator=(const copy_assignable_if &) noexcept = delete;
99+
copy_assignable_if &operator=(copy_assignable_if &&) noexcept = default;
100+
};
101+
} // namespace detail
94102

103+
template <typename T>
104+
class Slice final
105+
: private detail::copy_assignable_if<std::is_const<T>::value> {
95106
public:
96107
Slice() noexcept;
97108
Slice(T *, size_t count) noexcept;
98109

99110
Slice &operator=(const Slice<T> &) noexcept = default;
111+
Slice &operator=(Slice<T> &&) noexcept = default;
100112

101113
T *data() const noexcept;
102114
size_t size() const noexcept;

macro/src/expand.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,10 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
330330
_ => quote!(#var),
331331
},
332332
Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
333-
Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8::from(#var)),
333+
Type::SliceRefU8(ty) => match ty.mutable {
334+
false => quote!(::cxx::private::RustSliceU8::from_ref(#var)),
335+
true => quote!(::cxx::private::RustSliceU8::from_mut(#var)),
336+
},
334337
ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
335338
_ => quote!(#var),
336339
}
@@ -423,7 +426,10 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
423426
_ => call,
424427
},
425428
Type::Str(_) => quote!(#call.as_str()),
426-
Type::SliceRefU8(_) => quote!(#call.as_slice()),
429+
Type::SliceRefU8(ty) => match ty.mutable {
430+
false => quote!(#call.as_slice()),
431+
true => quote!(#call.as_mut_slice()),
432+
},
427433
_ => call,
428434
},
429435
};
@@ -610,7 +616,10 @@ fn expand_rust_function_shim_impl(
610616
_ => quote!(#ident),
611617
},
612618
Type::Str(_) => quote!(#ident.as_str()),
613-
Type::SliceRefU8(_) => quote!(#ident.as_slice()),
619+
Type::SliceRefU8(ty) => match ty.mutable {
620+
false => quote!(#ident.as_slice()),
621+
true => quote!(#ident.as_mut_slice()),
622+
},
614623
ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
615624
_ => quote!(#ident),
616625
}
@@ -654,7 +663,10 @@ fn expand_rust_function_shim_impl(
654663
_ => None,
655664
},
656665
Type::Str(_) => Some(quote!(::cxx::private::RustStr::from)),
657-
Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustSliceU8::from)),
666+
Type::SliceRefU8(ty) => match ty.mutable {
667+
false => Some(quote!(::cxx::private::RustSliceU8::from_ref)),
668+
true => Some(quote!(::cxx::private::RustSliceU8::from_mut)),
669+
},
658670
_ => None,
659671
});
660672

src/cxx.cc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ static_assert(std::is_trivially_move_assignable<Slice<const uint8_t>>::value,
180180
static_assert(std::is_trivially_destructible<Slice<const uint8_t>>::value,
181181
"trivial ~Slice()");
182182

183+
static_assert(std::is_trivially_copy_constructible<Slice<uint8_t>>::value,
184+
"trivial Slice(const Slice &)");
185+
static_assert(std::is_trivially_move_constructible<Slice<uint8_t>>::value,
186+
"trivial Slice(Slice &&)");
187+
static_assert(!std::is_copy_assignable<Slice<uint8_t>>::value,
188+
"delete Slice::operator=(const Slice &) for mut slices");
189+
static_assert(std::is_trivially_move_assignable<Slice<uint8_t>>::value,
190+
"trivial Slice::operator=(Slice &&)");
191+
static_assert(std::is_trivially_destructible<Slice<uint8_t>>::value,
192+
"trivial ~Slice()");
193+
183194
extern "C" {
184195
const char *cxxbridge1$error(const char *ptr, size_t len) {
185196
char *copy = new char[len];

src/rust_sliceu8.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,27 @@ pub struct RustSliceU8 {
1111
}
1212

1313
impl RustSliceU8 {
14-
pub fn from(s: &[u8]) -> Self {
14+
pub fn from_ref(s: &[u8]) -> Self {
1515
RustSliceU8 {
1616
ptr: NonNull::from(s).cast::<u8>(),
1717
len: s.len(),
1818
}
1919
}
2020

21+
pub fn from_mut(s: &mut [u8]) -> Self {
22+
RustSliceU8 {
23+
len: s.len(),
24+
ptr: NonNull::from(s).cast::<u8>(),
25+
}
26+
}
27+
2128
pub unsafe fn as_slice<'a>(self) -> &'a [u8] {
2229
slice::from_raw_parts(self.ptr.as_ptr(), self.len)
2330
}
31+
32+
pub unsafe fn as_mut_slice<'a>(self) -> &'a mut [u8] {
33+
slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len)
34+
}
2435
}
2536

2637
const_assert_eq!(

syntax/check.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,10 @@ fn check_type_ref(cx: &mut Check, ty: &Ref) {
178178
}
179179

180180
fn check_type_slice(cx: &mut Check, ty: &Slice) {
181-
cx.error(ty, "only &[u8] is supported so far, not other slice types");
181+
cx.error(
182+
ty,
183+
"only &[u8] and &mut [u8] are supported so far, not other slice types",
184+
);
182185
}
183186

184187
fn check_type_fn(cx: &mut Check, ty: &Signature) {
@@ -489,7 +492,10 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
489492
Type::Str(_) => "&str".to_owned(),
490493
Type::CxxVector(_) => "C++ vector".to_owned(),
491494
Type::Slice(_) => "slice".to_owned(),
492-
Type::SliceRefU8(_) => "&[u8]".to_owned(),
495+
Type::SliceRefU8(ty) => match ty.mutable {
496+
false => "&[u8]".to_owned(),
497+
true => "&mut [u8]".to_owned(),
498+
},
493499
Type::Fn(_) => "function pointer".to_owned(),
494500
Type::Void(_) => "()".to_owned(),
495501
}

syntax/parse.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ fn parse_type_reference(ty: &TypeReference, namespace: &Namespace) -> Result<Typ
658658
}
659659
}
660660
Type::Slice(slice) => match &slice.inner {
661-
Type::Ident(ident) if ident.rust == U8 && ty.mutability.is_none() => Type::SliceRefU8,
661+
Type::Ident(ident) if ident.rust == U8 => Type::SliceRefU8,
662662
_ => Type::Ref,
663663
},
664664
_ => Type::Ref,

tests/ffi/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ pub mod ffi {
7777
fn c_return_mut(shared: &mut Shared) -> &mut usize;
7878
fn c_return_str(shared: &Shared) -> &str;
7979
fn c_return_sliceu8(shared: &Shared) -> &[u8];
80+
fn c_return_mutsliceu8(slice: &mut [u8]) -> &mut [u8];
8081
fn c_return_rust_string() -> String;
8182
fn c_return_unique_ptr_string() -> UniquePtr<CxxString>;
8283
fn c_return_unique_ptr_vector_u8() -> UniquePtr<CxxVector<u8>>;
@@ -140,6 +141,7 @@ pub mod ffi {
140141
fn c_try_return_ref(s: &String) -> Result<&String>;
141142
fn c_try_return_str(s: &str) -> Result<&str>;
142143
fn c_try_return_sliceu8(s: &[u8]) -> Result<&[u8]>;
144+
fn c_try_return_mutsliceu8(s: &mut [u8]) -> Result<&mut [u8]>;
143145
fn c_try_return_rust_string() -> Result<String>;
144146
fn c_try_return_unique_ptr_string() -> Result<UniquePtr<CxxString>>;
145147
fn c_try_return_rust_vec() -> Result<Vec<u8>>;
@@ -187,6 +189,7 @@ pub mod ffi {
187189
fn r_return_mut(shared: &mut Shared) -> &mut usize;
188190
fn r_return_str(shared: &Shared) -> &str;
189191
fn r_return_sliceu8(shared: &Shared) -> &[u8];
192+
fn r_return_mutsliceu8(slice: &mut [u8]) -> &mut [u8];
190193
fn r_return_rust_string() -> String;
191194
fn r_return_unique_ptr_string() -> UniquePtr<CxxString>;
192195
fn r_return_rust_vec() -> Vec<u8>;
@@ -220,6 +223,7 @@ pub mod ffi {
220223
fn r_try_return_box() -> Result<Box<R>>;
221224
fn r_fail_return_primitive() -> Result<usize>;
222225
fn r_try_return_sliceu8(s: &[u8]) -> Result<&[u8]>;
226+
fn r_try_return_mutsliceu8(s: &mut [u8]) -> Result<&mut [u8]>;
223227

224228
fn get(self: &R) -> usize;
225229
fn set(self: &mut R, n: usize) -> usize;
@@ -371,6 +375,10 @@ fn r_return_sliceu8(shared: &ffi::Shared) -> &[u8] {
371375
b"2020"
372376
}
373377

378+
fn r_return_mutsliceu8(slice: &mut [u8]) -> &mut [u8] {
379+
slice
380+
}
381+
374382
fn r_return_rust_string() -> String {
375383
"2020".to_owned()
376384
}
@@ -509,6 +517,10 @@ fn r_try_return_sliceu8(slice: &[u8]) -> Result<&[u8], Error> {
509517
Ok(slice)
510518
}
511519

520+
fn r_try_return_mutsliceu8(slice: &mut [u8]) -> Result<&mut [u8], Error> {
521+
Ok(slice)
522+
}
523+
512524
fn r_aliased_function(x: i32) -> String {
513525
x.to_string()
514526
}

tests/ffi/tests.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ rust::Slice<const uint8_t> c_return_sliceu8(const Shared &shared) {
7777
reinterpret_cast<const uint8_t *>(SLICE_DATA), sizeof(SLICE_DATA));
7878
}
7979

80+
rust::Slice<uint8_t> c_return_mutsliceu8(rust::Slice<uint8_t> slice) {
81+
return slice;
82+
}
83+
8084
rust::String c_return_rust_string() { return "2020"; }
8185

8286
std::unique_ptr<std::string> c_return_unique_ptr_string() {
@@ -435,6 +439,10 @@ rust::Slice<const uint8_t> c_try_return_sliceu8(rust::Slice<const uint8_t> s) {
435439
return s;
436440
}
437441

442+
rust::Slice<uint8_t> c_try_return_mutsliceu8(rust::Slice<uint8_t> s) {
443+
return s;
444+
}
445+
438446
rust::String c_try_return_rust_string() { return c_return_rust_string(); }
439447

440448
std::unique_ptr<std::string> c_try_return_unique_ptr_string() {

tests/ffi/tests.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ const size_t &c_return_nested_ns_ref(const ::A::B::ABShared &shared);
8484
size_t &c_return_mut(Shared &shared);
8585
rust::Str c_return_str(const Shared &shared);
8686
rust::Slice<const uint8_t> c_return_sliceu8(const Shared &shared);
87+
rust::Slice<uint8_t> c_return_mutsliceu8(rust::Slice<uint8_t> slice);
8788
rust::String c_return_rust_string();
8889
std::unique_ptr<std::string> c_return_unique_ptr_string();
8990
std::unique_ptr<std::vector<uint8_t>> c_return_unique_ptr_vector_u8();
@@ -148,6 +149,7 @@ rust::Box<R> c_try_return_box();
148149
const rust::String &c_try_return_ref(const rust::String &);
149150
rust::Str c_try_return_str(rust::Str);
150151
rust::Slice<const uint8_t> c_try_return_sliceu8(rust::Slice<const uint8_t>);
152+
rust::Slice<uint8_t> c_try_return_mutsliceu8(rust::Slice<uint8_t>);
151153
rust::String c_try_return_rust_string();
152154
std::unique_ptr<std::string> c_try_return_unique_ptr_string();
153155
rust::Vec<uint8_t> c_try_return_rust_vec();

0 commit comments

Comments
 (0)