Zhuzh up the C++/Rust interop test to demonstrate more uses.

Taking over the work done by mcyoung@

PiperOrigin-RevId: 529063108
pull/12644/head
Marcel Hlopko 2 years ago committed by Copybara-Service
parent ba348e2b3b
commit 701e056e2b
  1. 8
      rust/shared.rs
  2. 1
      rust/test/cpp/interop/BUILD
  3. 94
      rust/test/cpp/interop/main.rs
  4. 30
      rust/test/cpp/interop/test_utils.cc
  5. 3
      src/google/protobuf/compiler/rust/message.cc

@ -41,6 +41,7 @@ pub extern crate upb as __runtime;
pub use __runtime::SerializedData;
use std::fmt;
use std::slice;
/// Represents error during deserialization.
#[derive(Debug, Clone)]
@ -55,8 +56,15 @@ impl fmt::Display for ParseError {
/// Represents an ABI-stable version of &[u8]/string_view (a borrowed slice of
/// bytes) for FFI use only.
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PtrAndLen {
/// Borrows the memory.
pub ptr: *const u8,
pub len: usize,
}
impl PtrAndLen {
pub unsafe fn as_ref<'a>(self) -> &'a [u8] {
slice::from_raw_parts(self.ptr, self.len)
}
}

@ -6,6 +6,7 @@ cc_library(
name = "test_utils",
srcs = ["test_utils.cc"],
deps = [
"//third_party/absl/strings",
"//rust/cpp_kernel:cpp_api",
"//rust/test:unittest_cc_proto",
],

@ -29,45 +29,89 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use std::ptr::NonNull;
use unittest_proto::proto2_unittest::TestAllExtensions;
use unittest_proto::proto2_unittest::TestAllTypes;
macro_rules! assert_serializes_equally {
($msg:ident) => {{
let mut msg = $msg;
let serialized_cpp =
unsafe { Serialize(msg.__unstable_cpp_repr_grant_permission_to_break()) };
let serialized_rs = msg.serialize();
macro_rules! proto_assert_eq {
($lhs:expr, $rhs:expr) => {{
let lhs = &$lhs;
let rhs = &$rhs;
assert_eq!(*serialized_rs, *serialized_cpp);
assert_eq!(lhs.optional_int64(), rhs.optional_int64());
assert_eq!(lhs.optional_bytes(), rhs.optional_bytes());
assert_eq!(lhs.optional_bool(), rhs.optional_bool());
}};
}
// Helper functions invoking C++ Protobuf APIs directly in C++.
// Defined in `test_utils.cc`.
extern "C" {
fn DeserializeTestAllTypes(data: *const u8, len: usize) -> NonNull<u8>;
fn MutateTestAllTypes(msg: NonNull<u8>);
fn SerializeTestAllTypes(msg: NonNull<u8>) -> protobuf_cpp::SerializedData;
fn NewWithExtension() -> NonNull<u8>;
fn GetBytesExtension(msg: NonNull<u8>) -> protobuf_cpp::PtrAndLen;
}
#[test]
fn mutate_message_in_cpp() {
let mut msg = TestAllTypes::new();
unsafe { MutateInt64Field(msg.__unstable_cpp_repr_grant_permission_to_break()) };
assert_serializes_equally!(msg);
let mut msg1 = TestAllTypes::new();
unsafe {
MutateTestAllTypes(msg1.__unstable_cpp_repr_grant_permission_to_break());
}
let mut msg2 = TestAllTypes::new();
msg2.optional_int64_set(Some(42));
msg2.optional_bytes_set(Some(b"something mysterious"));
msg2.optional_bool_set(Some(false));
proto_assert_eq!(msg1, msg2);
}
#[test]
fn mutate_message_in_rust() {
let mut msg = TestAllTypes::new();
msg.optional_int64_set(Some(43));
assert_serializes_equally!(msg);
fn deserialize_in_rust() {
let mut msg1 = TestAllTypes::new();
msg1.optional_int64_set(Some(-1));
msg1.optional_bytes_set(Some(b"some cool data I guess"));
let serialized =
unsafe { SerializeTestAllTypes(msg1.__unstable_cpp_repr_grant_permission_to_break()) };
let mut msg2 = TestAllTypes::new();
msg2.deserialize(&serialized).unwrap();
proto_assert_eq!(msg1, msg2);
}
#[test]
fn deserialize_message_in_rust() {
let serialized = unsafe { SerializeMutatedInstance() };
let mut msg = TestAllTypes::new();
msg.deserialize(&serialized).unwrap();
assert_serializes_equally!(msg);
fn deserialize_in_cpp() {
let mut msg1 = TestAllTypes::new();
msg1.optional_int64_set(Some(-1));
msg1.optional_bytes_set(Some(b"some cool data I guess"));
let data = msg1.serialize();
let msg2 = unsafe {
TestAllTypes::__unstable_wrap_cpp_grant_permission_to_break(DeserializeTestAllTypes(
data.as_ptr(),
data.len(),
))
};
proto_assert_eq!(msg1, msg2);
}
// Helper functions invoking C++ Protobuf APIs directly in C++. Defined in
// `//third_party/protobuf/rust/test/cpp/interop:test_utils`.
extern "C" {
fn SerializeMutatedInstance() -> protobuf_cpp::SerializedData;
fn MutateInt64Field(msg: NonNull<u8>);
fn Serialize(msg: NonNull<u8>) -> protobuf_cpp::SerializedData;
// This test ensures that random fields we (Rust) don't know about don't
// accidentally get destroyed by Rust.
#[test]
fn smuggle_extension() {
let msg1 = unsafe {
TestAllExtensions::__unstable_wrap_cpp_grant_permission_to_break(NewWithExtension())
};
let data = msg1.serialize();
let mut msg2 = TestAllExtensions::new();
msg2.deserialize(&data).unwrap();
let bytes = unsafe {
GetBytesExtension(msg2.__unstable_cpp_repr_grant_permission_to_break()).as_ref()
};
assert_eq!(&*bytes, b"smuggled");
}

@ -28,22 +28,38 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <cstddef>
#include "absl/strings/string_view.h"
#include "google/protobuf/rust/cpp_kernel/cpp_api.h"
#include "google/protobuf/unittest.pb.h"
extern "C" void MutateInt64Field(protobuf_unittest::TestAllTypes* msg) {
extern "C" void MutateTestAllTypes(protobuf_unittest::TestAllTypes* msg) {
msg->set_optional_int64(42);
msg->set_optional_bytes("something mysterious");
msg->set_optional_bool(false);
}
extern "C" google::protobuf::rust_internal::SerializedData Serialize(
extern "C" google::protobuf::rust_internal::SerializedData SerializeTestAllTypes(
const protobuf_unittest::TestAllTypes* msg) {
return google::protobuf::rust_internal::SerializeMsg(msg);
}
extern "C" google::protobuf::rust_internal::SerializedData SerializeMutatedInstance() {
protobuf_unittest::TestAllTypes* inst = new protobuf_unittest::TestAllTypes();
MutateInt64Field(inst);
return Serialize(inst);
extern "C" void* DeserializeTestAllTypes(const void* data, size_t size) {
auto* proto = new protobuf_unittest::TestAllTypes;
proto->ParseFromArray(data, size);
return proto;
}
extern "C" void* NewWithExtension() {
auto* proto = new protobuf_unittest::TestAllExtensions;
proto->SetExtension(protobuf_unittest::optional_bytes_extension, "smuggled");
return proto;
}
extern "C" google::protobuf::rust_internal::PtrAndLen GetBytesExtension(
const protobuf_unittest::TestAllExtensions* proto) {
absl::string_view bytes =
proto->GetExtension(protobuf_unittest::optional_bytes_extension);
return {bytes.data(), bytes.size()};
}

@ -324,6 +324,9 @@ void MessageGenerator::GenerateRs(Context<Descriptor> msg) {
msg.printer().PrintRaw("\n");
msg.Emit({{"Msg", msg.desc().name()}}, R"rs(
impl $Msg$ {
pub fn __unstable_wrap_cpp_grant_permission_to_break(msg: $NonNull$<u8>) -> Self {
Self { msg }
}
pub fn __unstable_cpp_repr_grant_permission_to_break(&mut self) -> $NonNull$<u8> {
self.msg
}

Loading…
Cancel
Save