diff --git a/README.md b/README.md
index bc7600640..e4ac67e64 100644
--- a/README.md
+++ b/README.md
@@ -323,6 +323,7 @@ returns of functions.
String | rust::String | |
&str | rust::Str | |
&[u8] | rust::Slice<const uint8_t> | arbitrary &[T] not implemented yet |
+&mut [u8] | rust::Slice<uint8_t> | arbitrary &mut [T] not implemented yet |
CxxString | std::string | cannot be passed by value |
Box<T> | rust::Box<T> | cannot hold opaque C++ type |
UniquePtr<T> | std::unique_ptr<T> | cannot hold opaque Rust type |
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index 31cbb4624..e10c2ccbd 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -25,7 +25,7 @@
- [Reference: built-in bindings](bindings.md)
- [String — rust::String](binding/string.md)
- [&str — rust::Str](binding/str.md)
- - [&[T] — rust::Slice\](binding/slice.md)
+ - [&[T], &mut [T] — rust::Slice\](binding/slice.md)
- [CxxString — std::string](binding/cxxstring.md)
- [Box\ — rust::Box\](binding/box.md)
- [UniquePtr\ — std::unique\_ptr\](binding/uniqueptr.md)
diff --git a/book/src/binding/slice.md b/book/src/binding/slice.md
index aacd56b2b..4da7d7397 100644
--- a/book/src/binding/slice.md
+++ b/book/src/binding/slice.md
@@ -1,5 +1,8 @@
{{#title rust::Slice — Rust ♡ C++}}
-# rust::Slice\
+# rust::Slice\, rust::Slice\
+
+- Rust `&[T]` is written `rust::Slice` in C++
+- Rust `&mut [T]` is written `rust::Slice` in C++
### Public API:
@@ -15,7 +18,10 @@ public:
Slice(const Slice &) noexcept;
Slice(T *, size_t count) noexcept;
+ // if std::is_const {
Slice &operator=(const Slice &) noexcept;
+ // }
+ Slice &operator=(Slice &&) noexcept;
T *data() const noexcept;
size_t size() const noexcept;
@@ -27,11 +33,14 @@ public:
### Restrictions:
-Only &\[u8\] i.e. rust::Slice\ is currently implemented.
-Support for arbitrary &\[T\] is coming.
+Only T=u8 i.e. rust::Slice\ and rust::Slice\ are
+currently implemented. Support for arbitrary T is coming.
Allowed as function argument or return value. Not supported in shared structs.
-&mut \[T\] is not supported yet.
+
+Only rust::Slice\ is copy-assignable, not rust::Slice\. (Both are
+move-assignable.) You'll need to write std::move occasionally as a reminder that
+accidentally exposing overlapping &mut \[T\] to Rust is UB.
## Example
diff --git a/book/src/bindings.md b/book/src/bindings.md
index f19dc5d13..df6a8d7c4 100644
--- a/book/src/bindings.md
+++ b/book/src/bindings.md
@@ -12,6 +12,7 @@ returns of extern functions.
String | rust::String | |
&str | rust::Str | |
&[u8] | rust::Slice<const uint8_t> | arbitrary &[T] not implemented yet |
+&mut [u8] | rust::Slice<uint8_t> | arbitrary &mut [T] not implemented yet |
CxxString | std::string | cannot be passed by value |
Box<T> | rust::Box<T> | cannot hold opaque C++ type |
UniquePtr<T> | std::unique_ptr<T> | cannot hold opaque Rust type |
@@ -43,7 +44,6 @@ matter of designing a nice API for each in its non-native language.
name in Rust | name in C++ |
-&mut [T] | rust::Slice<T> |
BTreeMap<K, V> | tbd |
HashMap<K, V> | tbd |
Arc<T> | tbd |
diff --git a/gen/src/builtin.rs b/gen/src/builtin.rs
index 9c5f4fd78..53facbfed 100644
--- a/gen/src/builtin.rs
+++ b/gen/src/builtin.rs
@@ -149,7 +149,7 @@ pub(super) fn write(out: &mut OutFile) {
if builtin.ptr_len {
out.begin_block(Block::Namespace("repr"));
writeln!(out, "struct PtrLen final {{");
- writeln!(out, " const void *ptr;");
+ writeln!(out, " void *ptr;");
writeln!(out, " size_t len;");
writeln!(out, "}};");
out.end_block(Block::Namespace("repr"));
@@ -173,7 +173,10 @@ pub(super) fn write(out: &mut OutFile) {
}
if builtin.rust_str_repr {
writeln!(out, " static repr::PtrLen repr(Str str) noexcept {{");
- writeln!(out, " return repr::PtrLen{{str.ptr, str.len}};");
+ writeln!(
+ out,
+ " return repr::PtrLen{{const_cast(str.ptr), str.len}};",
+ );
writeln!(out, " }}");
}
writeln!(out, "}};");
@@ -189,18 +192,21 @@ pub(super) fn write(out: &mut OutFile) {
out,
" static Slice slice(repr::PtrLen repr) noexcept {{",
);
- writeln!(
- out,
- " return {{static_cast(repr.ptr), repr.len}};",
- );
+ writeln!(out, " return {{static_cast(repr.ptr), repr.len}};");
writeln!(out, " }}");
}
if builtin.rust_slice_repr {
+ include.type_traits = true;
writeln!(
out,
" static repr::PtrLen repr(Slice slice) noexcept {{",
);
- writeln!(out, " return repr::PtrLen{{slice.ptr, slice.len}};");
+ writeln!(out, " return repr::PtrLen{{");
+ writeln!(
+ out,
+ " const_cast::type *>(slice.ptr),",
+ );
+ writeln!(out, " slice.len}};");
writeln!(out, " }}");
}
writeln!(out, "}};");
diff --git a/gen/src/write.rs b/gen/src/write.rs
index d99778605..8b512daf2 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -436,9 +436,11 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
out.builtin.rust_str_repr = true;
write!(out, "::rust::impl<::rust::Str>::repr(");
}
- Some(Type::SliceRefU8(_)) if !indirect_return => {
+ Some(ty @ Type::SliceRefU8(_)) if !indirect_return => {
out.builtin.rust_slice_repr = true;
- write!(out, "::rust::impl<::rust::Slice>::repr(")
+ write!(out, "::rust::impl<");
+ write_type(out, ty);
+ write!(out, ">::repr(");
}
_ => {}
}
@@ -474,12 +476,13 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
out.builtin.unsafe_bitcopy = true;
write_type(out, &arg.ty);
write!(out, "(::rust::unsafe_bitcopy, *{})", arg.ident);
- } else if let Type::SliceRefU8(_) = arg.ty {
- write!(
- out,
- "::rust::Slice(static_cast({0}.ptr), {0}.len)",
- arg.ident,
- );
+ } else if let Type::SliceRefU8(slice) = &arg.ty {
+ write_type(out, &arg.ty);
+ write!(out, "(static_cast<");
+ if slice.mutability.is_none() {
+ write!(out, "const ");
+ }
+ write!(out, "uint8_t *>({0}.ptr), {0}.len)", arg.ident);
} else if out.types.needs_indirect_abi(&arg.ty) {
out.include.utility = true;
write!(out, "::std::move(*{})", arg.ident);
@@ -507,7 +510,7 @@ fn write_cxx_function_shim<'a>(out: &mut OutFile<'a>, efn: &'a ExternFn) {
writeln!(out, " throw$.len = ::std::strlen(catch$);");
writeln!(
out,
- " throw$.ptr = ::cxxbridge1$exception(catch$, throw$.len);",
+ " throw$.ptr = const_cast(::cxxbridge1$exception(catch$, throw$.len));",
);
writeln!(out, " }});");
writeln!(out, " return throw$;");
@@ -694,7 +697,9 @@ fn write_rust_function_shim_impl(
}
Type::SliceRefU8(_) => {
out.builtin.rust_slice_new = true;
- write!(out, "::rust::impl<::rust::Slice>::slice(");
+ write!(out, "::rust::impl<");
+ write_type(out, ret);
+ write!(out, ">::slice(");
}
_ => {}
}
@@ -720,7 +725,9 @@ fn write_rust_function_shim_impl(
}
Type::SliceRefU8(_) => {
out.builtin.rust_slice_repr = true;
- write!(out, "::rust::impl<::rust::Slice>::repr(");
+ write!(out, "::rust::impl<");
+ write_type(out, &arg.ty);
+ write!(out, ">::repr(");
}
ty if out.types.needs_indirect_abi(ty) => write!(out, "&"),
_ => {}
@@ -890,8 +897,12 @@ fn write_type(out: &mut OutFile, ty: &Type) {
Type::Str(_) => {
write!(out, "::rust::Str");
}
- Type::SliceRefU8(_) => {
- write!(out, "::rust::Slice");
+ Type::SliceRefU8(ty) => {
+ write!(out, "::rust::Slice<");
+ if ty.mutability.is_none() {
+ write!(out, "const ");
+ }
+ write!(out, "uint8_t>");
}
Type::Fn(f) => {
write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
diff --git a/include/cxx.h b/include/cxx.h
index 812278686..1b30497a2 100644
--- a/include/cxx.h
+++ b/include/cxx.h
@@ -87,16 +87,28 @@ class Str final {
#endif // CXXBRIDGE1_RUST_STR
#ifndef CXXBRIDGE1_RUST_SLICE
-template
-class Slice final {
- static_assert(std::is_const::value,
- "&[T] needs to be written as rust::Slice in C++");
+namespace detail {
+template
+struct copy_assignable_if {};
+
+template <>
+struct copy_assignable_if {
+ copy_assignable_if() noexcept = default;
+ copy_assignable_if(const copy_assignable_if &) noexcept = default;
+ copy_assignable_if &operator=(const copy_assignable_if &) noexcept = delete;
+ copy_assignable_if &operator=(copy_assignable_if &&) noexcept = default;
+};
+} // namespace detail
+template
+class Slice final
+ : private detail::copy_assignable_if::value> {
public:
Slice() noexcept;
Slice(T *, size_t count) noexcept;
Slice &operator=(const Slice &) noexcept = default;
+ Slice &operator=(Slice &&) noexcept = default;
T *data() const noexcept;
size_t size() const noexcept;
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index f29c4cc1e..1fee9286e 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -330,7 +330,10 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
_ => quote!(#var),
},
Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
- Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8::from(#var)),
+ Type::SliceRefU8(ty) => match ty.mutable {
+ false => quote!(::cxx::private::RustSliceU8::from_ref(#var)),
+ true => quote!(::cxx::private::RustSliceU8::from_mut(#var)),
+ },
ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
_ => quote!(#var),
}
@@ -423,7 +426,10 @@ fn expand_cxx_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
_ => call,
},
Type::Str(_) => quote!(#call.as_str()),
- Type::SliceRefU8(_) => quote!(#call.as_slice()),
+ Type::SliceRefU8(ty) => match ty.mutable {
+ false => quote!(#call.as_slice()),
+ true => quote!(#call.as_mut_slice()),
+ },
_ => call,
},
};
@@ -610,7 +616,10 @@ fn expand_rust_function_shim_impl(
_ => quote!(#ident),
},
Type::Str(_) => quote!(#ident.as_str()),
- Type::SliceRefU8(_) => quote!(#ident.as_slice()),
+ Type::SliceRefU8(ty) => match ty.mutable {
+ false => quote!(#ident.as_slice()),
+ true => quote!(#ident.as_mut_slice()),
+ },
ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
_ => quote!(#ident),
}
@@ -654,7 +663,10 @@ fn expand_rust_function_shim_impl(
_ => None,
},
Type::Str(_) => Some(quote!(::cxx::private::RustStr::from)),
- Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustSliceU8::from)),
+ Type::SliceRefU8(ty) => match ty.mutable {
+ false => Some(quote!(::cxx::private::RustSliceU8::from_ref)),
+ true => Some(quote!(::cxx::private::RustSliceU8::from_mut)),
+ },
_ => None,
});
diff --git a/src/cxx.cc b/src/cxx.cc
index 923b6412d..28506ef6a 100644
--- a/src/cxx.cc
+++ b/src/cxx.cc
@@ -180,6 +180,17 @@ static_assert(std::is_trivially_move_assignable>::value,
static_assert(std::is_trivially_destructible>::value,
"trivial ~Slice()");
+static_assert(std::is_trivially_copy_constructible>::value,
+ "trivial Slice(const Slice &)");
+static_assert(std::is_trivially_move_constructible>::value,
+ "trivial Slice(Slice &&)");
+static_assert(!std::is_copy_assignable>::value,
+ "delete Slice::operator=(const Slice &) for mut slices");
+static_assert(std::is_trivially_move_assignable>::value,
+ "trivial Slice::operator=(Slice &&)");
+static_assert(std::is_trivially_destructible>::value,
+ "trivial ~Slice()");
+
extern "C" {
const char *cxxbridge1$error(const char *ptr, size_t len) {
char *copy = new char[len];
diff --git a/src/lib.rs b/src/lib.rs
index 0427af699..d1c894ee7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -332,6 +332,7 @@
//! String | rust::String | |
//! &str | rust::Str | |
//! &[u8] | rust::Slice<const uint8_t> | arbitrary &[T] not implemented yet |
+//! &mut [u8] | rust::Slice<uint8_t> | arbitrary &mut [T] not implemented yet |
//! CxxString | std::string | cannot be passed by value |
//! Box<T> | rust::Box<T> | cannot hold opaque C++ type |
//! UniquePtr<T> | std::unique_ptr<T> | cannot hold opaque Rust type |
diff --git a/src/rust_sliceu8.rs b/src/rust_sliceu8.rs
index 32f8798bd..e14f98859 100644
--- a/src/rust_sliceu8.rs
+++ b/src/rust_sliceu8.rs
@@ -11,16 +11,27 @@ pub struct RustSliceU8 {
}
impl RustSliceU8 {
- pub fn from(s: &[u8]) -> Self {
+ pub fn from_ref(s: &[u8]) -> Self {
RustSliceU8 {
ptr: NonNull::from(s).cast::(),
len: s.len(),
}
}
+ pub fn from_mut(s: &mut [u8]) -> Self {
+ RustSliceU8 {
+ len: s.len(),
+ ptr: NonNull::from(s).cast::(),
+ }
+ }
+
pub unsafe fn as_slice<'a>(self) -> &'a [u8] {
slice::from_raw_parts(self.ptr.as_ptr(), self.len)
}
+
+ pub unsafe fn as_mut_slice<'a>(self) -> &'a mut [u8] {
+ slice::from_raw_parts_mut(self.ptr.as_ptr(), self.len)
+ }
}
const_assert_eq!(
diff --git a/syntax/check.rs b/syntax/check.rs
index 2e94f4db2..1ec6178c1 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -178,7 +178,10 @@ fn check_type_ref(cx: &mut Check, ty: &Ref) {
}
fn check_type_slice(cx: &mut Check, ty: &Slice) {
- cx.error(ty, "only &[u8] is supported so far, not other slice types");
+ cx.error(
+ ty,
+ "only &[u8] and &mut [u8] are supported so far, not other slice types",
+ );
}
fn check_type_fn(cx: &mut Check, ty: &Signature) {
@@ -489,7 +492,10 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
Type::Str(_) => "&str".to_owned(),
Type::CxxVector(_) => "C++ vector".to_owned(),
Type::Slice(_) => "slice".to_owned(),
- Type::SliceRefU8(_) => "&[u8]".to_owned(),
+ Type::SliceRefU8(ty) => match ty.mutable {
+ false => "&[u8]".to_owned(),
+ true => "&mut [u8]".to_owned(),
+ },
Type::Fn(_) => "function pointer".to_owned(),
Type::Void(_) => "()".to_owned(),
}
diff --git a/syntax/parse.rs b/syntax/parse.rs
index 38b3dccf4..c6d64804d 100644
--- a/syntax/parse.rs
+++ b/syntax/parse.rs
@@ -658,7 +658,7 @@ fn parse_type_reference(ty: &TypeReference, namespace: &Namespace) -> Result match &slice.inner {
- Type::Ident(ident) if ident.rust == U8 && ty.mutability.is_none() => Type::SliceRefU8,
+ Type::Ident(ident) if ident.rust == U8 => Type::SliceRefU8,
_ => Type::Ref,
},
_ => Type::Ref,
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index 762af4d67..af72fb46d 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -77,6 +77,7 @@ pub mod ffi {
fn c_return_mut(shared: &mut Shared) -> &mut usize;
fn c_return_str(shared: &Shared) -> &str;
fn c_return_sliceu8(shared: &Shared) -> &[u8];
+ fn c_return_mutsliceu8(slice: &mut [u8]) -> &mut [u8];
fn c_return_rust_string() -> String;
fn c_return_unique_ptr_string() -> UniquePtr;
fn c_return_unique_ptr_vector_u8() -> UniquePtr>;
@@ -140,6 +141,7 @@ pub mod ffi {
fn c_try_return_ref(s: &String) -> Result<&String>;
fn c_try_return_str(s: &str) -> Result<&str>;
fn c_try_return_sliceu8(s: &[u8]) -> Result<&[u8]>;
+ fn c_try_return_mutsliceu8(s: &mut [u8]) -> Result<&mut [u8]>;
fn c_try_return_rust_string() -> Result;
fn c_try_return_unique_ptr_string() -> Result>;
fn c_try_return_rust_vec() -> Result>;
@@ -187,6 +189,7 @@ pub mod ffi {
fn r_return_mut(shared: &mut Shared) -> &mut usize;
fn r_return_str(shared: &Shared) -> &str;
fn r_return_sliceu8(shared: &Shared) -> &[u8];
+ fn r_return_mutsliceu8(slice: &mut [u8]) -> &mut [u8];
fn r_return_rust_string() -> String;
fn r_return_unique_ptr_string() -> UniquePtr;
fn r_return_rust_vec() -> Vec;
@@ -220,6 +223,7 @@ pub mod ffi {
fn r_try_return_box() -> Result>;
fn r_fail_return_primitive() -> Result;
fn r_try_return_sliceu8(s: &[u8]) -> Result<&[u8]>;
+ fn r_try_return_mutsliceu8(s: &mut [u8]) -> Result<&mut [u8]>;
fn get(self: &R) -> usize;
fn set(self: &mut R, n: usize) -> usize;
@@ -371,6 +375,10 @@ fn r_return_sliceu8(shared: &ffi::Shared) -> &[u8] {
b"2020"
}
+fn r_return_mutsliceu8(slice: &mut [u8]) -> &mut [u8] {
+ slice
+}
+
fn r_return_rust_string() -> String {
"2020".to_owned()
}
@@ -509,6 +517,10 @@ fn r_try_return_sliceu8(slice: &[u8]) -> Result<&[u8], Error> {
Ok(slice)
}
+fn r_try_return_mutsliceu8(slice: &mut [u8]) -> Result<&mut [u8], Error> {
+ Ok(slice)
+}
+
fn r_aliased_function(x: i32) -> String {
x.to_string()
}
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index f1c293de9..238b1457d 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -77,6 +77,10 @@ rust::Slice c_return_sliceu8(const Shared &shared) {
reinterpret_cast(SLICE_DATA), sizeof(SLICE_DATA));
}
+rust::Slice c_return_mutsliceu8(rust::Slice slice) {
+ return slice;
+}
+
rust::String c_return_rust_string() { return "2020"; }
std::unique_ptr c_return_unique_ptr_string() {
@@ -435,6 +439,10 @@ rust::Slice c_try_return_sliceu8(rust::Slice s) {
return s;
}
+rust::Slice c_try_return_mutsliceu8(rust::Slice s) {
+ return s;
+}
+
rust::String c_try_return_rust_string() { return c_return_rust_string(); }
std::unique_ptr c_try_return_unique_ptr_string() {
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index 5acf469db..6c288d724 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -84,6 +84,7 @@ const size_t &c_return_nested_ns_ref(const ::A::B::ABShared &shared);
size_t &c_return_mut(Shared &shared);
rust::Str c_return_str(const Shared &shared);
rust::Slice c_return_sliceu8(const Shared &shared);
+rust::Slice c_return_mutsliceu8(rust::Slice slice);
rust::String c_return_rust_string();
std::unique_ptr c_return_unique_ptr_string();
std::unique_ptr> c_return_unique_ptr_vector_u8();
@@ -148,6 +149,7 @@ rust::Box c_try_return_box();
const rust::String &c_try_return_ref(const rust::String &);
rust::Str c_try_return_str(rust::Str);
rust::Slice c_try_return_sliceu8(rust::Slice);
+rust::Slice c_try_return_mutsliceu8(rust::Slice);
rust::String c_try_return_rust_string();
std::unique_ptr c_try_return_unique_ptr_string();
rust::Vec c_try_return_rust_vec();