diff --git a/README.md b/README.md
index 0b3aab317..ad14b574f 100644
--- a/README.md
+++ b/README.md
@@ -299,6 +299,7 @@ returns of functions.
| name in Rust | name in C++ | restrictions |
| String | rust::String | |
| &str | rust::Str | |
+| &[u8] | rust::Slice<uint8_t> | (no other slice types currently supported) |
| 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 |
@@ -316,7 +317,6 @@ matter of designing a nice API for each in its non-native language.
| name in Rust | name in C++ |
-| &[T] | tbd |
| Vec<T> | tbd |
| BTreeMap<K, V> | tbd |
| HashMap<K, V> | tbd |
diff --git a/gen/write.rs b/gen/write.rs
index 4eed1b40a..3f3cf4b65 100644
--- a/gen/write.rs
+++ b/gen/write.rs
@@ -365,6 +365,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
match &efn.ret {
Some(Type::Ref(_)) => write!(out, "&"),
Some(Type::Str(_)) if !indirect_return => write!(out, "::rust::Str::Repr("),
+ Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, "::rust::Slice::Repr("),
_ => {}
}
write!(out, "{}$(", efn.ident);
@@ -395,7 +396,7 @@ fn write_cxx_function_shim(out: &mut OutFile, efn: &ExternFn, types: &Types) {
match &efn.ret {
Some(Type::RustBox(_)) => write!(out, ".into_raw()"),
Some(Type::UniquePtr(_)) => write!(out, ".release()"),
- Some(Type::Str(_)) if !indirect_return => write!(out, ")"),
+ Some(Type::Str(_)) | Some(Type::SliceRefU8(_)) if !indirect_return => write!(out, ")"),
_ => {}
}
if indirect_return {
@@ -566,6 +567,7 @@ fn write_rust_function_shim_impl(
}
match &arg.ty {
Type::Str(_) => write!(out, "::rust::Str::Repr("),
+ Type::SliceRefU8(_) => write!(out, "::rust::Slice::Repr("),
ty if types.needs_indirect_abi(ty) => write!(out, "&"),
_ => {}
}
@@ -573,7 +575,7 @@ fn write_rust_function_shim_impl(
match &arg.ty {
Type::RustBox(_) => write!(out, ".into_raw()"),
Type::UniquePtr(_) => write!(out, ".release()"),
- Type::Str(_) => write!(out, ")"),
+ Type::Str(_) | Type::SliceRefU8(_) => write!(out, ")"),
ty if ty != RustString && types.needs_indirect_abi(ty) => write!(out, "$.value"),
_ => {}
}
@@ -637,6 +639,7 @@ fn write_indirect_return_type(out: &mut OutFile, ty: &Type) {
write!(out, " *");
}
Type::Str(_) => write!(out, "::rust::Str::Repr"),
+ Type::SliceRefU8(_) => write!(out, "::rust::Slice::Repr"),
_ => write_type(out, ty),
}
}
@@ -645,7 +648,7 @@ fn write_indirect_return_type_space(out: &mut OutFile, ty: &Type) {
write_indirect_return_type(out, ty);
match ty {
Type::RustBox(_) | Type::UniquePtr(_) | Type::Ref(_) => {}
- Type::Str(_) => write!(out, " "),
+ Type::Str(_) | Type::SliceRefU8(_) => write!(out, " "),
_ => write_space_after_type(out, ty),
}
}
@@ -664,6 +667,7 @@ fn write_extern_return_type_space(out: &mut OutFile, ty: &Option, types: &
write!(out, " *");
}
Some(Type::Str(_)) => write!(out, "::rust::Str::Repr "),
+ Some(Type::SliceRefU8(_)) => write!(out, "::rust::Slice::Repr "),
Some(ty) if types.needs_indirect_abi(ty) => write!(out, "void "),
_ => write_return_type(out, ty),
}
@@ -676,6 +680,7 @@ fn write_extern_arg(out: &mut OutFile, arg: &Var, types: &Types) {
write!(out, "*");
}
Type::Str(_) => write!(out, "::rust::Str::Repr "),
+ Type::SliceRefU8(_) => write!(out, "::rust::Slice::Repr "),
_ => write_type_space(out, &arg.ty),
}
if types.needs_indirect_abi(&arg.ty) {
@@ -721,9 +726,16 @@ fn write_type(out: &mut OutFile, ty: &Type) {
write_type(out, &r.inner);
write!(out, " &");
}
+ Type::Slice(_) => {
+ // For now, only U8 slices are supported, which are covered separately below
+ unreachable!()
+ }
Type::Str(_) => {
write!(out, "::rust::Str");
}
+ Type::SliceRefU8(_) => {
+ write!(out, "::rust::Slice");
+ }
Type::Fn(f) => {
write!(out, "::rust::{}<", if f.throws { "TryFn" } else { "Fn" });
match &f.ret {
@@ -750,11 +762,11 @@ fn write_type_space(out: &mut OutFile, ty: &Type) {
fn write_space_after_type(out: &mut OutFile, ty: &Type) {
match ty {
- Type::Ident(_) | Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::Fn(_) => {
+ Type::Ident(_) | Type::RustBox(_) | Type::UniquePtr(_) | Type::Str(_) | Type::SliceRefU8(_) | Type::Fn(_) => {
write!(out, " ")
}
Type::Ref(_) => {}
- Type::Void(_) => unreachable!(),
+ Type::Void(_) | Type::Slice(_) => unreachable!(),
}
}
diff --git a/include/cxx.h b/include/cxx.h
index a8239a122..57a6e24b7 100644
--- a/include/cxx.h
+++ b/include/cxx.h
@@ -16,6 +16,43 @@ inline namespace cxxbridge02 {
struct unsafe_bitcopy_t;
+#ifndef CXXBRIDGE02_RUST_SLICE
+#define CXXBRIDGE02_RUST_SLICE
+template
+class Slice final {
+public:
+ Slice() noexcept : repr(Repr{reinterpret_cast(this), 0}) {}
+ Slice(const Slice &) noexcept = default;
+
+ Slice(const T* s, size_t size) : repr(Repr{s, size}) {}
+
+ Slice &operator=(Slice other) noexcept {
+ this->repr = other.repr;
+ return *this;
+ }
+
+ const T *data() const noexcept { return this->repr.ptr; }
+ size_t size() const noexcept { return this->repr.len; }
+ size_t length() const noexcept { return this->repr.len; }
+
+ // Repr is PRIVATE; must not be used other than by our generated code.
+ //
+ // At present this class is only used for &[u8] slices.
+ // Not necessarily ABI compatible with &[u8]. Codegen will translate to
+ // cxx::rust_slice_u8::RustSlice which matches this layout.
+ struct Repr {
+ const T *ptr;
+ size_t len;
+ };
+ Slice(Repr repr_) noexcept : repr(repr_) {}
+ explicit operator Repr() noexcept { return this->repr; }
+
+private:
+ Repr repr;
+};
+
+#endif // CXXBRIDGE02_RUST_SLICE
+
#ifndef CXXBRIDGE02_RUST_STRING
#define CXXBRIDGE02_RUST_STRING
class String final {
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 67c34e5f5..146d21b10 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -184,6 +184,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
_ => quote!(#var),
},
Type::Str(_) => quote!(::cxx::private::RustStr::from(#var)),
+ Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8::from(#var)),
ty if types.needs_indirect_abi(ty) => quote!(#var.as_mut_ptr()),
_ => quote!(#var),
}
@@ -255,6 +256,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
_ => None,
},
Type::Str(_) => Some(quote!(#call.map(|r| r.as_str()))),
+ Type::SliceRefU8(_) => Some(quote!(#call.map(|r| r.as_slice()))),
_ => None,
})
} else {
@@ -267,6 +269,7 @@ fn expand_cxx_function_shim(namespace: &Namespace, efn: &ExternFn, types: &Types
_ => None,
},
Type::Str(_) => Some(quote!(#call.as_str())),
+ Type::SliceRefU8(_) => Some(quote!(#call.as_slice())),
_ => None,
})
}
@@ -375,6 +378,7 @@ fn expand_rust_function_shim_impl(
_ => quote!(#ident),
},
Type::Str(_) => quote!(#ident.as_str()),
+ Type::SliceRefU8(_) => quote!(#ident.as_slice()),
ty if types.needs_indirect_abi(ty) => quote!(::std::ptr::read(#ident)),
_ => quote!(#ident),
}
@@ -402,6 +406,7 @@ fn expand_rust_function_shim_impl(
_ => None,
},
Type::Str(_) => Some(quote!(::cxx::private::RustStr::from(#call))),
+ Type::SliceRefU8(_) => Some(quote!(::cxx::private::RustSliceU8::from(#call))),
_ => None,
})
.unwrap_or(call);
@@ -572,6 +577,7 @@ fn expand_extern_type(ty: &Type) -> TokenStream {
_ => quote!(#ty),
},
Type::Str(_) => quote!(::cxx::private::RustStr),
+ Type::SliceRefU8(_) => quote!(::cxx::private::RustSliceU8),
_ => quote!(#ty),
}
}
diff --git a/src/lib.rs b/src/lib.rs
index f918b298d..60750fbe7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -367,6 +367,7 @@ mod gen;
mod opaque;
mod paths;
mod result;
+mod rust_sliceu8;
mod rust_str;
mod rust_string;
mod syntax;
@@ -384,6 +385,7 @@ pub mod private {
pub use crate::function::FatFunction;
pub use crate::opaque::Opaque;
pub use crate::result::{r#try, Result};
+ pub use crate::rust_sliceu8::RustSliceU8;
pub use crate::rust_str::RustStr;
pub use crate::rust_string::RustString;
pub use crate::unique_ptr::UniquePtrTarget;
diff --git a/src/rust_sliceu8.rs b/src/rust_sliceu8.rs
new file mode 100644
index 000000000..56d37b3d6
--- /dev/null
+++ b/src/rust_sliceu8.rs
@@ -0,0 +1,26 @@
+use std::mem;
+use std::slice;
+use std::ptr::NonNull;
+
+// Not necessarily ABI compatible with &[u8]. Codegen performs the translation.
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct RustSliceU8 {
+ pub(crate) ptr: NonNull,
+ pub(crate) len: usize,
+}
+
+impl RustSliceU8 {
+ pub fn from(s: &[u8]) -> Self {
+ RustSliceU8 {
+ ptr: NonNull::from(s).cast::(),
+ len: s.len(),
+ }
+ }
+
+ pub unsafe fn as_slice<'a>(self) -> &'a [u8] {
+ slice::from_raw_parts(self.ptr.as_ptr(), self.len)
+ }
+}
+
+const_assert!(mem::size_of::