Repository: dtolnay/cxx (language: rust)

Issue:
Support opaque Rust types in a rust::Slice
Currently only primitives and shared types are supported in a slice in the FFI.

The following is currently rejected, but it should be possible to support:

```rust
#[cxx::bridge]
mod ffi {
    extern "Rust" {
        type MyType;
    }

    unsafe extern "C++" {
        fn f(slice: &[MyType]);
    }
}
```

The slice iterators and indexing operations will need to obtain a `stride` at runtime from Rust, exactly like we already do for rust::Vec containing opaque Rust types.


Discussion / hints:
Can `&[String]` be supported as well? If not, I guess a workaround would be wrapping it into a struct...
`&[String]` should already be working. If not, please file a separate issue with a repro.
Sorry, I confused it with `&[&str]`, which doesn't seem to be.

Fix patch:
diff --git a/syntax/check.rs b/syntax/check.rs
index 2ac800b7f..f43c1e258 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -210,6 +210,7 @@ fn check_type_ref(cx: &mut Check, ty: &Ref) {
 fn check_type_slice_ref(cx: &mut Check, ty: &SliceRef) {
     let supported = match &ty.inner {
         Type::Str(_) | Type::SliceRef(_) => false,
+        Type::Ident(ident) => !is_opaque_cxx(cx, &ident.rust),
         element => !is_unsized(cx, element),
     };
 
@@ -217,9 +218,7 @@ fn check_type_slice_ref(cx: &mut Check, ty: &SliceRef) {
         let mutable = if ty.mutable { "mut " } else { "" };
         let mut msg = format!("unsupported &{}[T] element type", mutable);
         if let Type::Ident(ident) = &ty.inner {
-            if cx.types.rust.contains(&ident.rust) {
-                msg += ": opaque Rust type is not supported yet";
-            } else if is_opaque_cxx(cx, &ident.rust) {
+            if is_opaque_cxx(cx, &ident.rust) {
                 msg += ": opaque C++ type is not supported yet";
             }
         }


Test patch:
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index df5c2794a..6814d0093 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -121,6 +121,7 @@ pub mod ffi {
         fn c_take_slice_char(s: &[c_char]);
         fn c_take_slice_shared(s: &[Shared]);
         fn c_take_slice_shared_sort(s: &mut [Shared]);
+        fn c_take_slice_r(s: &[R]);
         fn c_take_rust_string(s: String);
         fn c_take_unique_ptr_string(s: UniquePtr<CxxString>);
         fn c_take_unique_ptr_vector_u8(v: UniquePtr<CxxVector<u8>>);
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index 2bb7d71f0..f0bab82a8 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -289,6 +289,12 @@ void c_take_slice_shared_sort(rust::Slice<Shared> s) {
   }
 }
 
+void c_take_slice_r(rust::Slice<const R> s) {
+  if (s.size() == 2 && s[0].get() == 2020 && s[1].get() == 2021) {
+    cxx_test_suite_set_correct();
+  }
+}
+
 void c_take_rust_string(rust::String s) {
   if (std::string(s) == "2020") {
     cxx_test_suite_set_correct();
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index 50a80054d..7dfaa3d33 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -124,6 +124,7 @@ void c_take_str(rust::Str s);
 void c_take_slice_char(rust::Slice<const char> s);
 void c_take_slice_shared(rust::Slice<const Shared> s);
 void c_take_slice_shared_sort(rust::Slice<Shared> s);
+void c_take_slice_r(rust::Slice<const R> s);
 void c_take_rust_string(rust::String s);
 void c_take_unique_ptr_string(std::unique_ptr<std::string> s);
 void c_take_unique_ptr_vector_u8(std::unique_ptr<std::vector<uint8_t>> v);
diff --git a/tests/test.rs b/tests/test.rs
index 0620a9caf..6178d89c8 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -132,6 +132,7 @@ fn test_c_take() {
         ffi::Shared { z: 4 },
     ];
     check!(ffi::c_take_slice_shared_sort(shared_sort_slice));
+    check!(ffi::c_take_slice_r(&[R(2020), R(2021)]));
     assert_eq!(shared_sort_slice[0].z, 0);
     assert_eq!(shared_sort_slice[1].z, 2);
     assert_eq!(shared_sort_slice[2].z, 4);