Replace some per-message C++ thunks with a common implementation

This change adds delete, clear, serialize, parse, copy_from, and merge_from
operations to the runtime. Since these operations can all be implemented easily
on the `MessageLite` interface, we can use a common implementation in the
runtime instead of generating per-message thunks for all of these.

I suspect this will also make it possible to remove some of our generated trait
implementations and replace them with blanket implementations, but I will leave
that for a future change.

PiperOrigin-RevId: 665910927
pull/17894/head
Adam Cozzette 7 months ago committed by Copybara-Service
parent d2c7f60714
commit 7f395af40e
  1. 9
      rust/cpp.rs
  2. 1
      rust/cpp_kernel/BUILD
  3. 36
      rust/cpp_kernel/message.cc
  4. 76
      src/google/protobuf/compiler/rust/message.cc

@ -95,6 +95,15 @@ pub struct InnerProtoString {
owned_ptr: CppStdString, owned_ptr: CppStdString,
} }
extern "C" {
pub fn proto2_rust_Message_delete(m: RawMessage);
pub fn proto2_rust_Message_clear(m: RawMessage);
pub fn proto2_rust_Message_parse(m: RawMessage, input: SerializedData) -> bool;
pub fn proto2_rust_Message_serialize(m: RawMessage, output: &mut SerializedData) -> bool;
pub fn proto2_rust_Message_copy_from(dst: RawMessage, src: RawMessage) -> bool;
pub fn proto2_rust_Message_merge_from(dst: RawMessage, src: RawMessage) -> bool;
}
/// An opaque type matching MapNodeSizeInfoT from C++. /// An opaque type matching MapNodeSizeInfoT from C++.
#[doc(hidden)] #[doc(hidden)]
#[repr(transparent)] #[repr(transparent)]

@ -8,6 +8,7 @@ cc_library(
"compare.cc", "compare.cc",
"debug.cc", "debug.cc",
"map.cc", "map.cc",
"message.cc",
"repeated.cc", "repeated.cc",
"strings.cc", "strings.cc",
], ],

@ -0,0 +1,36 @@
#include <limits>
#include "google/protobuf/message_lite.h"
#include "rust/cpp_kernel/serialized_data.h"
extern "C" {
void proto2_rust_Message_delete(google::protobuf::MessageLite* m) { delete m; }
void proto2_rust_Message_clear(google::protobuf::MessageLite* m) { m->Clear(); }
bool proto2_rust_Message_parse(google::protobuf::MessageLite* m,
google::protobuf::rust::SerializedData input) {
if (input.len > std::numeric_limits<int>::max()) {
return false;
}
return m->ParseFromArray(input.data, static_cast<int>(input.len));
}
bool proto2_rust_Message_serialize(const google::protobuf::MessageLite* m,
google::protobuf::rust::SerializedData* output) {
return google::protobuf::rust::SerializeMsg(m, output);
}
void proto2_rust_Message_copy_from(google::protobuf::MessageLite* dst,
const google::protobuf::MessageLite& src) {
dst->Clear();
dst->CheckTypeAndMergeFrom(src);
}
void proto2_rust_Message_merge_from(google::protobuf::MessageLite* dst,
const google::protobuf::MessageLite& src) {
dst->CheckTypeAndMergeFrom(src);
}
} // extern "C"

@ -61,10 +61,10 @@ void MessageNew(Context& ctx, const Descriptor& msg) {
void MessageSerialize(Context& ctx, const Descriptor& msg) { void MessageSerialize(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) { switch (ctx.opts().kernel) {
case Kernel::kCpp: case Kernel::kCpp:
ctx.Emit({{"serialize_thunk", ThunkName(ctx, msg, "serialize")}}, R"rs( ctx.Emit({}, R"rs(
let mut serialized_data = $pbr$::SerializedData::new($pbi$::Private); let mut serialized_data = $pbr$::SerializedData::new($pbi$::Private);
let success = unsafe { let success = unsafe {
$serialize_thunk$(self.raw_msg(), &mut serialized_data) $pbr$::proto2_rust_Message_serialize(self.raw_msg(), &mut serialized_data)
}; };
if success { if success {
Ok(serialized_data.into_vec()) Ok(serialized_data.into_vec())
@ -95,9 +95,9 @@ void MessageSerialize(Context& ctx, const Descriptor& msg) {
void MessageMutClear(Context& ctx, const Descriptor& msg) { void MessageMutClear(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) { switch (ctx.opts().kernel) {
case Kernel::kCpp: case Kernel::kCpp:
ctx.Emit({{"clear_thunk", ThunkName(ctx, msg, "clear")}}, ctx.Emit({},
R"rs( R"rs(
unsafe { $clear_thunk$(self.raw_msg()) } unsafe { $pbr$::proto2_rust_Message_clear(self.raw_msg()) }
)rs"); )rs");
return; return;
case Kernel::kUpb: case Kernel::kUpb:
@ -116,11 +116,8 @@ void MessageMutClear(Context& ctx, const Descriptor& msg) {
void MessageClearAndParse(Context& ctx, const Descriptor& msg) { void MessageClearAndParse(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) { switch (ctx.opts().kernel) {
case Kernel::kCpp: case Kernel::kCpp:
ctx.Emit( ctx.Emit({},
{ R"rs(
{"parse_thunk", ThunkName(ctx, msg, "parse")},
},
R"rs(
let success = unsafe { let success = unsafe {
// SAFETY: `data.as_ptr()` is valid to read for `data.len()`. // SAFETY: `data.as_ptr()` is valid to read for `data.len()`.
let data = $pbr$::SerializedData::from_raw_parts( let data = $pbr$::SerializedData::from_raw_parts(
@ -128,7 +125,7 @@ void MessageClearAndParse(Context& ctx, const Descriptor& msg) {
data.len(), data.len(),
); );
$parse_thunk$(self.raw_msg(), data) $pbr$::proto2_rust_Message_parse(self.raw_msg(), data)
}; };
success.then_some(()).ok_or($pb$::ParseError) success.then_some(()).ok_or($pb$::ParseError)
)rs"); )rs");
@ -199,12 +196,6 @@ void MessageExterns(Context& ctx, const Descriptor& msg) {
ctx.Emit( ctx.Emit(
{{"new_thunk", ThunkName(ctx, msg, "new")}, {{"new_thunk", ThunkName(ctx, msg, "new")},
{"placement_new_thunk", ThunkName(ctx, msg, "placement_new")}, {"placement_new_thunk", ThunkName(ctx, msg, "placement_new")},
{"delete_thunk", ThunkName(ctx, msg, "delete")},
{"clear_thunk", ThunkName(ctx, msg, "clear")},
{"serialize_thunk", ThunkName(ctx, msg, "serialize")},
{"parse_thunk", ThunkName(ctx, msg, "parse")},
{"copy_from_thunk", ThunkName(ctx, msg, "copy_from")},
{"merge_from_thunk", ThunkName(ctx, msg, "merge_from")},
{"repeated_new_thunk", ThunkName(ctx, msg, "repeated_new")}, {"repeated_new_thunk", ThunkName(ctx, msg, "repeated_new")},
{"repeated_free_thunk", ThunkName(ctx, msg, "repeated_free")}, {"repeated_free_thunk", ThunkName(ctx, msg, "repeated_free")},
{"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")}, {"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")},
@ -219,12 +210,6 @@ void MessageExterns(Context& ctx, const Descriptor& msg) {
R"rs( R"rs(
fn $new_thunk$() -> $pbr$::RawMessage; fn $new_thunk$() -> $pbr$::RawMessage;
fn $placement_new_thunk$(ptr: *mut std::ffi::c_void, m: $pbr$::RawMessage); fn $placement_new_thunk$(ptr: *mut std::ffi::c_void, m: $pbr$::RawMessage);
fn $delete_thunk$(raw_msg: $pbr$::RawMessage);
fn $clear_thunk$(raw_msg: $pbr$::RawMessage);
fn $serialize_thunk$(raw_msg: $pbr$::RawMessage, out: &mut $pbr$::SerializedData) -> bool;
fn $parse_thunk$(raw_msg: $pbr$::RawMessage, data: $pbr$::SerializedData) -> bool;
fn $copy_from_thunk$(dst: $pbr$::RawMessage, src: $pbr$::RawMessage);
fn $merge_from_thunk$(dst: $pbr$::RawMessage, src: $pbr$::RawMessage);
fn $repeated_new_thunk$() -> $pbr$::RawRepeatedField; fn $repeated_new_thunk$() -> $pbr$::RawRepeatedField;
fn $repeated_free_thunk$(raw: $pbr$::RawRepeatedField); fn $repeated_free_thunk$(raw: $pbr$::RawRepeatedField);
fn $repeated_len_thunk$(raw: $pbr$::RawRepeatedField) -> usize; fn $repeated_len_thunk$(raw: $pbr$::RawRepeatedField) -> usize;
@ -263,19 +248,19 @@ void MessageDrop(Context& ctx, const Descriptor& msg) {
return; return;
} }
ctx.Emit({{"delete_thunk", ThunkName(ctx, msg, "delete")}}, R"rs( ctx.Emit({}, R"rs(
unsafe { $delete_thunk$(self.raw_msg()); } unsafe { $pbr$::proto2_rust_Message_delete(self.raw_msg()); }
)rs"); )rs");
} }
void IntoProxiedForMessage(Context& ctx, const Descriptor& msg) { void IntoProxiedForMessage(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) { switch (ctx.opts().kernel) {
case Kernel::kCpp: case Kernel::kCpp:
ctx.Emit({{"copy_from_thunk", ThunkName(ctx, msg, "copy_from")}}, R"rs( ctx.Emit({}, R"rs(
impl<'msg> $pb$::IntoProxied<$Msg$> for $Msg$View<'msg> { impl<'msg> $pb$::IntoProxied<$Msg$> for $Msg$View<'msg> {
fn into_proxied(self, _private: $pbi$::Private) -> $Msg$ { fn into_proxied(self, _private: $pbi$::Private) -> $Msg$ {
let dst = $Msg$::new(); let dst = $Msg$::new();
unsafe { $copy_from_thunk$(dst.inner.msg, self.msg) }; unsafe { $pbr$::proto2_rust_Message_copy_from(dst.inner.msg, self.msg) };
dst dst
} }
} }
@ -345,16 +330,13 @@ void UpbGeneratedMessageTraitImpls(Context& ctx, const Descriptor& msg) {
void MessageMutMergeFrom(Context& ctx, const Descriptor& msg) { void MessageMutMergeFrom(Context& ctx, const Descriptor& msg) {
switch (ctx.opts().kernel) { switch (ctx.opts().kernel) {
case Kernel::kCpp: case Kernel::kCpp:
ctx.Emit( ctx.Emit({},
{ R"rs(
{"merge_from_thunk", ThunkName(ctx, msg, "merge_from")},
},
R"rs(
impl $pb$::MergeFrom for $Msg$Mut<'_> { impl $pb$::MergeFrom for $Msg$Mut<'_> {
fn merge_from(&mut self, src: impl $pb$::AsView<Proxied = $Msg$>) { fn merge_from(&mut self, src: impl $pb$::AsView<Proxied = $Msg$>) {
// SAFETY: self and src are both valid `$Msg$`s. // SAFETY: self and src are both valid `$Msg$`s.
unsafe { unsafe {
$merge_from_thunk$(self.raw_msg(), src.as_view().raw_msg()); $pbr$::proto2_rust_Message_merge_from(self.raw_msg(), src.as_view().raw_msg());
} }
} }
} }
@ -389,7 +371,6 @@ void MessageProxiedInRepeated(Context& ctx, const Descriptor& msg) {
ctx.Emit( ctx.Emit(
{ {
{"Msg", RsSafeName(msg.name())}, {"Msg", RsSafeName(msg.name())},
{"copy_from_thunk", ThunkName(ctx, msg, "copy_from")},
{"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")}, {"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")},
{"repeated_get_thunk", ThunkName(ctx, msg, "repeated_get")}, {"repeated_get_thunk", ThunkName(ctx, msg, "repeated_get")},
{"repeated_get_mut_thunk", {"repeated_get_mut_thunk",
@ -438,7 +419,7 @@ void MessageProxiedInRepeated(Context& ctx, const Descriptor& msg) {
// - `i < len(f)` is promised by caller. // - `i < len(f)` is promised by caller.
// - `v.raw_msg()` is a valid `const Message&`. // - `v.raw_msg()` is a valid `const Message&`.
unsafe { unsafe {
$copy_from_thunk$( $pbr$::proto2_rust_Message_copy_from(
$repeated_get_mut_thunk$(f.as_raw($pbi$::Private), i), $repeated_get_mut_thunk$(f.as_raw($pbi$::Private), i),
v.into_proxied($pbi$::Private).raw_msg(), v.into_proxied($pbi$::Private).raw_msg(),
); );
@ -467,7 +448,7 @@ void MessageProxiedInRepeated(Context& ctx, const Descriptor& msg) {
// - `v.raw_msg()` is a valid `const Message&`. // - `v.raw_msg()` is a valid `const Message&`.
unsafe { unsafe {
let new_elem = $repeated_add_thunk$(f.as_raw($pbi$::Private)); let new_elem = $repeated_add_thunk$(f.as_raw($pbi$::Private));
$copy_from_thunk$(new_elem, v.into_proxied($pbi$::Private).raw_msg()); $pbr$::proto2_rust_Message_copy_from(new_elem, v.into_proxied($pbi$::Private).raw_msg());
} }
} }
@ -1406,12 +1387,6 @@ void GenerateThunksCc(Context& ctx, const Descriptor& msg) {
{"QualifiedMsg", cpp::QualifiedClassName(&msg)}, {"QualifiedMsg", cpp::QualifiedClassName(&msg)},
{"new_thunk", ThunkName(ctx, msg, "new")}, {"new_thunk", ThunkName(ctx, msg, "new")},
{"placement_new_thunk", ThunkName(ctx, msg, "placement_new")}, {"placement_new_thunk", ThunkName(ctx, msg, "placement_new")},
{"delete_thunk", ThunkName(ctx, msg, "delete")},
{"clear_thunk", ThunkName(ctx, msg, "clear")},
{"serialize_thunk", ThunkName(ctx, msg, "serialize")},
{"parse_thunk", ThunkName(ctx, msg, "parse")},
{"copy_from_thunk", ThunkName(ctx, msg, "copy_from")},
{"merge_from_thunk", ThunkName(ctx, msg, "merge_from")},
{"repeated_new_thunk", ThunkName(ctx, msg, "repeated_new")}, {"repeated_new_thunk", ThunkName(ctx, msg, "repeated_new")},
{"repeated_free_thunk", ThunkName(ctx, msg, "repeated_free")}, {"repeated_free_thunk", ThunkName(ctx, msg, "repeated_free")},
{"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")}, {"repeated_len_thunk", ThunkName(ctx, msg, "repeated_len")},
@ -1453,25 +1428,6 @@ void GenerateThunksCc(Context& ctx, const Descriptor& msg) {
void $placement_new_thunk$(void* ptr, $QualifiedMsg$& m) { void $placement_new_thunk$(void* ptr, $QualifiedMsg$& m) {
new (ptr) $QualifiedMsg$(std::move(m)); new (ptr) $QualifiedMsg$(std::move(m));
} }
void $delete_thunk$(void* ptr) { delete static_cast<$QualifiedMsg$*>(ptr); }
void $clear_thunk$(void* ptr) {
static_cast<$QualifiedMsg$*>(ptr)->Clear();
}
bool $serialize_thunk$($QualifiedMsg$* msg, google::protobuf::rust::SerializedData* out) {
return google::protobuf::rust::SerializeMsg(msg, out);
}
bool $parse_thunk$($QualifiedMsg$* msg,
google::protobuf::rust::SerializedData data) {
return msg->ParseFromArray(data.data, data.len);
}
void $copy_from_thunk$($QualifiedMsg$* dst, const $QualifiedMsg$* src) {
dst->CopyFrom(*src);
}
void $merge_from_thunk$($QualifiedMsg$* dst, const $QualifiedMsg$* src) {
dst->MergeFrom(*src);
}
void* $repeated_new_thunk$() { void* $repeated_new_thunk$() {
return new google::protobuf::RepeatedPtrField<$QualifiedMsg$>(); return new google::protobuf::RepeatedPtrField<$QualifiedMsg$>();

Loading…
Cancel
Save