Add traits for interop fns.

The owned and mut interop traits have the corresponding to/from behaviors on cpp but are defined as empty on upb, while the view interop is implemented for both.

PiperOrigin-RevId: 657617187
pull/17664/head
Protobuf Team Bot 6 months ago committed by Copybara-Service
parent 9cceb6278d
commit 76c767fa1c
  1. 85
      rust/codegen_traits.rs
  2. 1
      rust/shared.rs
  3. 27
      rust/test/cpp/interop/main.rs
  4. 54
      src/google/protobuf/compiler/rust/message.cc

@ -8,8 +8,10 @@
//! Traits that are implemeted by codegen types.
use crate::__internal::SealedInternal;
use crate::__runtime::RawMessage;
use crate::{MutProxied, MutProxy, ViewProxy};
use create::Parse;
use interop::{MessageMutInterop, MessageViewInterop, OwnedMessageInterop};
use read::Serialize;
use std::fmt::Debug;
use write::{Clear, ClearAndParse};
@ -27,7 +29,10 @@ pub trait Message: SealedInternal
+ Send + Sync
// Copy/Clone:
+ Clone
{}
// C++ Interop:
+ OwnedMessageInterop
{
}
/// A trait that all generated message views implement.
pub trait MessageView<'msg>: SealedInternal
@ -38,6 +43,8 @@ pub trait MessageView<'msg>: SealedInternal
+ Send + Sync
// Copy/Clone:
+ Copy + Clone
// C++ Interop:
+ MessageViewInterop<'msg>
{
#[doc(hidden)]
type Message: Message;
@ -55,6 +62,8 @@ pub trait MessageMut<'msg>: SealedInternal
+ Sync
// Copy/Clone:
// (Neither)
// C++ Interop:
+ MessageMutInterop<'msg>
{
#[doc(hidden)]
type Message: Message;
@ -94,3 +103,77 @@ pub(crate) mod write {
fn clear_and_parse(&mut self, data: &[u8]) -> Result<(), crate::ParseError>;
}
}
/// Traits related to interop with C or C++.
///
/// These traits are deliberately not available on the prelude, as they should
/// be used rarely and with great care.
pub(crate) mod interop {
use super::{RawMessage, SealedInternal};
/// Traits related to owned message interop. Note that these trait fns
/// are only available on C++ kernel as upb interop of owned messages
/// requires more work to handle the Arena behavior.
pub trait OwnedMessageInterop: SealedInternal {
/// Drops `self` and returns the `RawMessage` that it was wrapping
/// without deleting it.
///
/// The caller is responsible for ensuring the returned RawMessage is
/// subsequently deleted (eg by moving it into a std::unique_ptr in
/// C++), or else it will leak.
#[cfg(cpp_kernel)]
fn __unstable_leak_raw_message(self) -> RawMessage;
/// Takes exclusive ownership of the `raw_message`.
///
/// # Safety
/// - The underlying message must be for the same type as `Self`
/// - The pointer passed in must not be used by the caller after being
/// passed here (must not be read, written, or deleted)
#[cfg(cpp_kernel)]
unsafe fn __unstable_take_ownership_of_raw_message(raw_message: RawMessage) -> Self;
}
/// Traits related to message view interop.
pub trait MessageViewInterop<'msg>: SealedInternal {
/// Borrows `self` as an underlying `RawMessage`.
///
/// Note that the returned Value must be used under the same constraints
/// as though it were a borrow of `self`: it should be treated as a
/// `const Message*` in C++, and not be mutated in any way, and any
/// mutation to the parent message may invalidate it, and it
/// must not be deleted.
fn __unstable_as_raw_message(&self) -> RawMessage;
/// Wraps the provided `RawMessage` as a MessageView.
///
/// # Safety
/// - The underlying message must be for the same type as `Self`
/// - The underlying message must be alive for 'msg and not mutated
/// while the wrapper is live.
unsafe fn __unstable_wrap_raw_message(raw: &'msg RawMessage) -> Self;
}
/// Traits related to message mut interop. Note that these trait fns
/// are only available on C++ kernel as upb interop of owned messages
/// requires more work to handle the Arena behavior.
pub trait MessageMutInterop<'msg>: SealedInternal {
/// Exclusive borrows `self` as a `RawMessage`.
///
/// Note that the returned Value must be used under the same constraints
/// as though it were a mut borrow of `self`: it should be treated as a
/// non-owned `Message*` in C++. And any mutation to the parent message
/// may invalidate it, and it must not be deleted.
#[cfg(cpp_kernel)]
fn __unstable_as_raw_message_mut(&mut self) -> RawMessage;
/// Wraps the provided `RawMessage` as a MessageMut.
///
/// # Safety
/// - The underlying message must be for the same type as `Self`
/// - The underlying message must be alive for 'msg and not read or
/// mutated while the wrapper is live.
#[cfg(cpp_kernel)]
unsafe fn __unstable_wrap_raw_message_mut(raw: &'msg mut RawMessage) -> Self;
}
}

@ -24,6 +24,7 @@ use std::fmt;
pub mod __public {
pub use crate::codegen_traits::{
create::Parse,
interop::{MessageMutInterop, MessageViewInterop, OwnedMessageInterop},
read::Serialize,
write::{Clear, ClearAndParse},
Message, MessageMut, MessageView,

@ -9,6 +9,7 @@ use googletest::prelude::*;
use protobuf_cpp::prelude::*;
use protobuf_cpp::__runtime::{PtrAndLen, RawMessage};
use protobuf_cpp::{MessageMutInterop, MessageViewInterop, OwnedMessageInterop};
use unittest_rust_proto::{TestAllExtensions, TestAllTypes, TestAllTypesMut, TestAllTypesView};
macro_rules! proto_assert_eq {
@ -39,9 +40,7 @@ extern "C" {
fn send_to_cpp() {
let mut msg1 = TestAllTypes::new();
msg1.set_optional_int32(7);
let i = unsafe {
TakeOwnershipAndGetOptionalInt32(msg1.__unstable_leak_cpp_repr_grant_permission_to_break())
};
let i = unsafe { TakeOwnershipAndGetOptionalInt32(msg1.__unstable_leak_raw_message()) };
assert_eq!(i, 7);
}
@ -49,7 +48,7 @@ fn send_to_cpp() {
fn mutate_message_mut_in_cpp() {
let mut msg1 = TestAllTypes::new();
unsafe {
MutateTestAllTypes(msg1.as_mut().__unstable_cpp_repr_grant_permission_to_break());
MutateTestAllTypes(msg1.as_mut().__unstable_as_raw_message_mut());
}
let mut msg2 = TestAllTypes::new();
@ -65,9 +64,7 @@ fn deserialize_in_rust() {
let mut msg1 = TestAllTypes::new();
msg1.set_optional_int64(-1);
msg1.set_optional_bytes(b"some cool data I guess");
let serialized = unsafe {
SerializeTestAllTypes(msg1.as_view().__unstable_cpp_repr_grant_permission_to_break())
};
let serialized = unsafe { SerializeTestAllTypes(msg1.as_view().__unstable_as_raw_message()) };
let msg2 = TestAllTypes::parse(&serialized).unwrap();
proto_assert_eq!(msg1, msg2);
@ -81,7 +78,7 @@ fn deserialize_in_cpp() {
let data = msg1.serialize().unwrap();
let msg2 = unsafe {
TestAllTypes::__unstable_wrap_cpp_grant_permission_to_break(DeserializeTestAllTypes(
TestAllTypes::__unstable_take_ownership_of_raw_message(DeserializeTestAllTypes(
(*data).as_ptr(),
data.len(),
))
@ -98,7 +95,7 @@ fn deserialize_in_cpp_into_mut() {
let data = msg1.serialize().unwrap();
let mut raw_msg = unsafe { DeserializeTestAllTypes((*data).as_ptr(), data.len()) };
let msg2 = TestAllTypesMut::__unstable_wrap_cpp_grant_permission_to_break(&mut raw_msg);
let msg2 = unsafe { TestAllTypesMut::__unstable_wrap_raw_message_mut(&mut raw_msg) };
proto_assert_eq!(msg1, msg2);
@ -116,7 +113,7 @@ fn deserialize_in_cpp_into_view() {
let data = msg1.serialize().unwrap();
let raw_msg = unsafe { DeserializeTestAllTypes((*data).as_ptr(), data.len()) };
let msg2 = TestAllTypesView::__unstable_wrap_cpp_grant_permission_to_break(&raw_msg);
let msg2 = unsafe { TestAllTypesView::__unstable_wrap_raw_message(&raw_msg) };
proto_assert_eq!(msg1, msg2);
@ -130,14 +127,12 @@ fn deserialize_in_cpp_into_view() {
// accidentally get destroyed by Rust.
#[googletest::test]
fn smuggle_extension() {
let msg1 = unsafe {
TestAllExtensions::__unstable_wrap_cpp_grant_permission_to_break(NewWithExtension())
};
let msg1 =
unsafe { TestAllExtensions::__unstable_take_ownership_of_raw_message(NewWithExtension()) };
let data = msg1.serialize().unwrap();
let mut msg2 = TestAllExtensions::parse(&data).unwrap();
let bytes = unsafe {
GetBytesExtension(msg2.as_mut().__unstable_cpp_repr_grant_permission_to_break()).as_ref()
};
let bytes =
unsafe { GetBytesExtension(msg2.as_mut().__unstable_as_raw_message_mut()).as_ref() };
assert_eq!(bytes, b"smuggled");
}

@ -1287,8 +1287,8 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
$nested_in_msg$
)rs");
ctx.printer().PrintRaw("\n");
if (ctx.is_cpp()) {
ctx.printer().PrintRaw("\n");
ctx.Emit({{"Msg", RsSafeName(msg.name())}}, R"rs(
impl $Msg$ {
pub fn __unstable_wrap_cpp_grant_permission_to_break(msg: $pbr$::RawMessage) -> Self {
@ -1299,7 +1299,6 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
s.raw_msg()
}
}
impl<'a> $Msg$Mut<'a> {
//~ msg is a &mut so that the borrow checker enforces exclusivity to
//~ prevent constructing multiple Muts/Views from the same RawMessage.
@ -1325,9 +1324,58 @@ void GenerateRs(Context& ctx, const Descriptor& msg) {
self.msg
}
}
impl $pb$::OwnedMessageInterop for $Msg$ {
unsafe fn __unstable_take_ownership_of_raw_message(msg: $pbr$::RawMessage) -> Self {
Self { inner: $pbr$::MessageInner { msg } }
}
fn __unstable_leak_raw_message(self) -> $pbr$::RawMessage {
let s = std::mem::ManuallyDrop::new(self);
s.raw_msg()
}
}
impl<'a> $pb$::MessageMutInterop<'a> for $Msg$Mut<'a> {
unsafe fn __unstable_wrap_raw_message_mut(
msg: &'a mut $pbr$::RawMessage) -> Self {
Self {
inner: $pbr$::MutatorMessageRef::from_raw_msg($pbi$::Private, msg)
}
}
fn __unstable_as_raw_message_mut(&mut self) -> $pbr$::RawMessage {
self.raw_msg()
}
}
impl<'a> $pb$::MessageViewInterop<'a> for $Msg$View<'a> {
unsafe fn __unstable_wrap_raw_message(
msg: &'a $pbr$::RawMessage) -> Self {
Self::new($pbi$::Private, *msg)
}
fn __unstable_as_raw_message(&self) -> $pbr$::RawMessage {
self.msg
}
}
)rs");
} else {
ctx.Emit({{"Msg", RsSafeName(msg.name())}}, R"rs(
// upb kernel doesn't support any owned message or message mut interop.
impl $pb$::OwnedMessageInterop for $Msg$ {}
impl<'a> $pb$::MessageMutInterop<'a> for $Msg$Mut<'a> {}
impl<'a> $pb$::MessageViewInterop<'a> for $Msg$View<'a> {
unsafe fn __unstable_wrap_raw_message(
msg: &'a $pbr$::RawMessage) -> Self {
Self::new($pbi$::Private, *msg)
}
fn __unstable_as_raw_message(&self) -> $pbr$::RawMessage {
self.msg
}
}
)rs");
}
}
} // NOLINT(readability/fn_size)
// Generates code for a particular message in `.pb.thunk.cc`.
void GenerateThunksCc(Context& ctx, const Descriptor& msg) {

Loading…
Cancel
Save