Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 17 additions & 19 deletions tests/cxx_gen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,25 +34,26 @@ fn test_impl_annotation() {
const BRIDGE1: &str = r#"
#[cxx::bridge]
mod ffi {
unsafe extern "C++" {
extern "C++" {
type CppType;
}

extern "Rust" {
fn rust_method_cpp_context(self: Pin<&mut CppType>);
fn rust_method_cpp_receiver(self: Pin<&mut CppType>);
}
}
"#;

// Ensure that implementing a Rust method on a C++ type only causes generation
// of the implementation.
// Ensure that implementing a Rust method on an opaque C++ type only causes
// generation of the member function definition, not a member function
// declaration in a class definition.
//
// The header should be implemented in the C++ class definition and the Rust
// implementation in the usual way.
// The member function declaration will come from whichever header provides the
// C++ class definition.
//
// This allows for developers and crates that are generating both C++ and Rust
// code to have a C++ method implemented in Rust without having to use a
// free method and passing through the C++ "this" as an argument.
// This allows for developers and crates that are producing both C++ and Rust
// code to have a C++ method implemented in Rust without having to use a free
// function and passing through the C++ "this" as an argument.
#[test]
fn test_extern_rust_method_on_c_type() {
let opt = Opt::default();
Expand All @@ -61,17 +62,14 @@ fn test_extern_rust_method_on_c_type() {
let header = str::from_utf8(&generated.header).unwrap();
let implementation = str::from_utf8(&generated.implementation).unwrap();

// To avoid continual breakage we won't test every byte.
// Let's look for the major features.

// Check that the header doesn't have the Rust method
assert!(!header.contains("rust_method_cpp_context"));
// Check that the header doesn't have the Rust method.
assert!(!header.contains("rust_method_cpp_receiver"));

// Check that there is a cxxbridge to the Rust method
// Check that there is a generated C signature bridging to the Rust method.
assert!(implementation
.contains("void cxxbridge1$CppType$rust_method_cpp_context(::CppType &self) noexcept;"));
.contains("void cxxbridge1$CppType$rust_method_cpp_receiver(::CppType &self) noexcept;"));

// Check that there is a implementation on the C++ class calling the Rust method
assert!(implementation.contains("void CppType::rust_method_cpp_context() noexcept {"));
assert!(implementation.contains("cxxbridge1$CppType$rust_method_cpp_context(*this);"));
// Check that there is an implementation on the C++ class calling the Rust method.
assert!(implementation.contains("void CppType::rust_method_cpp_receiver() noexcept {"));
assert!(implementation.contains("cxxbridge1$CppType$rust_method_cpp_receiver(*this);"));
}
4 changes: 2 additions & 2 deletions tests/ffi/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ pub mod ffi {
fn set(self: &mut R, n: usize) -> usize;
fn r_method_on_shared(self: &Shared) -> String;
fn r_get_array_sum(self: &Array) -> i32;
// Ensure that a Rust method can be implemented on a C++ type
// Ensure that a Rust method can be implemented on an opaque C++ type.
fn r_method_on_c_get_mut(self: Pin<&mut C>) -> &mut usize;

#[cxx_name = "rAliasedFunction"]
Expand Down Expand Up @@ -450,7 +450,7 @@ impl ffi::Array {
}
}

// A Rust method implemented on the C++ type
// A Rust method implemented on an opaque C++ type.
impl ffi::C {
pub fn r_method_on_c_get_mut(self: core::pin::Pin<&mut Self>) -> &mut usize {
self.getMut()
Expand Down
5 changes: 3 additions & 2 deletions tests/ffi/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@ class C {
rust::String cOverloadedMethod(int32_t x) const;
rust::String cOverloadedMethod(rust::Str x) const;
static size_t c_static_method();
// Note that the implementation of this method is generated by CXX itself
// which is then bridged to a Rust method but with the C++ type as self
// Unlike the other contents of this class, the C++ definition of this member
// function is generated by CXX and forwards to a Rust method implementation
// in an `impl ffi::C` block.
size_t &r_method_on_c_get_mut() noexcept;

private:
Expand Down
Loading