Actually run destructors of C++ messages.

PiperOrigin-RevId: 525244271
pull/12498/head
Miguel Young de la Sota 2 years ago committed by Copybara-Service
parent 6ad1a6d674
commit 35b9813f85
  1. 7
      src/google/protobuf/compiler/rust/BUILD.bazel
  2. 24
      src/google/protobuf/compiler/rust/accessors/singular_bytes.cc
  3. 24
      src/google/protobuf/compiler/rust/accessors/singular_scalar.cc
  4. 100
      src/google/protobuf/compiler/rust/message.cc
  5. 26
      src/google/protobuf/compiler/rust/naming.cc
  6. 6
      src/google/protobuf/compiler/rust/naming.h

@ -36,11 +36,11 @@ cc_library(
copts = COPTS,
include_prefix = "google/protobuf/compiler/rust",
deps = [
":accessors",
":context",
":naming",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler/cpp:names",
":accessors",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
],
@ -57,16 +57,15 @@ cc_library(
copts = COPTS,
include_prefix = "google/protobuf/compiler/rust",
deps = [
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler/cpp:names_internal",
":context",
":naming",
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler/cpp:names_internal",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/strings",
],
)
cc_library(
name = "context",
srcs = ["context.cc"],

@ -50,10 +50,10 @@ class SingularBytes final : public AccessorGenerator {
field.Emit(
{
{"field", field.desc().name()},
{"hazzer_thunk", GetAccessorThunkName(field, "has")},
{"getter_thunk", GetAccessorThunkName(field, "")},
{"setter_thunk", GetAccessorThunkName(field, "set")},
{"clearer_thunk", GetAccessorThunkName(field, "clear")},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"rs(
pub fn $field$(&self) -> Option<&[u8]> {
@ -77,10 +77,10 @@ class SingularBytes final : public AccessorGenerator {
void InExternC(Context<FieldDescriptor> field) const override {
field.Emit(
{
{"hazzer_thunk", GetAccessorThunkName(field, "has")},
{"getter_thunk", GetAccessorThunkName(field, "")},
{"setter_thunk", GetAccessorThunkName(field, "set")},
{"clearer_thunk", GetAccessorThunkName(field, "clear")},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"rs(
fn $hazzer_thunk$(raw_msg: $NonNull$<u8>) -> bool;
@ -95,10 +95,10 @@ class SingularBytes final : public AccessorGenerator {
{
{"field", field.desc().name()},
{"namespace", cpp::Namespace(field.desc().containing_type())},
{"hazzer_thunk", GetAccessorThunkName(field, "has")},
{"getter_thunk", GetAccessorThunkName(field, "")},
{"setter_thunk", GetAccessorThunkName(field, "set")},
{"clearer_thunk", GetAccessorThunkName(field, "clear")},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"cc(
bool $hazzer_thunk$($namespace$::$Msg$* msg) {

@ -51,10 +51,10 @@ class SingularScalar final : public AccessorGenerator {
{
{"field", field.desc().name()},
{"Scalar", PrimitiveRsTypeName(field)},
{"hazzer_thunk", GetAccessorThunkName(field, "has")},
{"getter_thunk", GetAccessorThunkName(field, "")},
{"setter_thunk", GetAccessorThunkName(field, "set")},
{"clearer_thunk", GetAccessorThunkName(field, "clear")},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"rs(
pub fn $field$(&self) -> Option<$Scalar$> {
@ -76,10 +76,10 @@ class SingularScalar final : public AccessorGenerator {
field.Emit(
{
{"Scalar", PrimitiveRsTypeName(field)},
{"hazzer_thunk", GetAccessorThunkName(field, "has")},
{"getter_thunk", GetAccessorThunkName(field, "")},
{"setter_thunk", GetAccessorThunkName(field, "set")},
{"clearer_thunk", GetAccessorThunkName(field, "clear")},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"rs(
fn $hazzer_thunk$(raw_msg: $NonNull$<u8>) -> bool;
@ -95,10 +95,10 @@ class SingularScalar final : public AccessorGenerator {
{"field", field.desc().name()},
{"Scalar", cpp::PrimitiveTypeName(field.desc().cpp_type())},
{"namespace", cpp::Namespace(field.desc().containing_type())},
{"hazzer_thunk", GetAccessorThunkName(field, "has")},
{"getter_thunk", GetAccessorThunkName(field, "")},
{"setter_thunk", GetAccessorThunkName(field, "set")},
{"clearer_thunk", GetAccessorThunkName(field, "clear")},
{"hazzer_thunk", Thunk(field, "has")},
{"getter_thunk", Thunk(field, "get")},
{"setter_thunk", Thunk(field, "set")},
{"clearer_thunk", Thunk(field, "clear")},
},
R"cc(
bool $hazzer_thunk$($namespace$::$Msg$* msg) {

@ -65,15 +65,15 @@ void MessageStructFields(Context<Descriptor> msg) {
void MessageNew(Context<Descriptor> msg) {
switch (msg.opts().kernel) {
case Kernel::kCpp:
msg.Emit(R"rs(
Self { msg: unsafe { __rust_proto_thunk__$pkg_Msg$__new() } }
msg.Emit({{"new_thunk", Thunk(msg, "new")}}, R"rs(
Self { msg: unsafe { $new_thunk$() } }
)rs");
return;
case Kernel::kUpb:
msg.Emit(R"rs(
msg.Emit({{"new_thunk", Thunk(msg, "new")}}, R"rs(
let arena = unsafe { $pb$::Arena::new() };
let msg = unsafe { $pkg_Msg$_new(arena) };
let msg = unsafe { $new_thunk$(arena) };
$Msg$ { msg, arena }
)rs");
return;
@ -85,17 +85,17 @@ void MessageNew(Context<Descriptor> msg) {
void MessageSerialize(Context<Descriptor> msg) {
switch (msg.opts().kernel) {
case Kernel::kCpp:
msg.Emit(R"rs(
unsafe { __rust_proto_thunk__$pkg_Msg$__serialize(self.msg) }
msg.Emit({{"serialize_thunk", Thunk(msg, "serialize")}}, R"rs(
unsafe { $serialize_thunk$(self.msg) }
)rs");
return;
case Kernel::kUpb:
msg.Emit(R"rs(
msg.Emit({{"serialize_thunk", Thunk(msg, "serialize")}}, R"rs(
let arena = unsafe { $pb$::__runtime::upb_Arena_New() };
let mut len = 0;
unsafe {
let data = $pkg_Msg$_serialize(self.msg, arena, &mut len);
let data = $serialize_thunk$(self.msg, arena, &mut len);
$pb$::SerializedData::from_raw_parts(arena, data, len)
}
)rs");
@ -108,14 +108,18 @@ void MessageSerialize(Context<Descriptor> msg) {
void MessageDeserialize(Context<Descriptor> msg) {
switch (msg.opts().kernel) {
case Kernel::kCpp:
msg.Emit(R"rs(
msg.Emit(
{
{"deserialize_thunk", Thunk(msg, "deserialize")},
},
R"rs(
let success = unsafe {
let data = $pb$::SerializedData::from_raw_parts(
$NonNull$::new(data.as_ptr() as *mut _).unwrap(),
data.len(),
);
__rust_proto_thunk__$pkg_Msg$__deserialize(self.msg, data)
$deserialize_thunk$(self.msg, data)
};
success.then_some(()).ok_or($pb$::ParseError)
)rs");
@ -135,30 +139,52 @@ void MessageDeserialize(Context<Descriptor> msg) {
void MessageExterns(Context<Descriptor> msg) {
switch (msg.opts().kernel) {
case Kernel::kCpp:
msg.Emit(R"rs(
fn __rust_proto_thunk__$pkg_Msg$__new() -> $NonNull$<u8>;
fn __rust_proto_thunk__$pkg_Msg$__serialize(raw_msg: $NonNull$<u8>)
-> $pb$::SerializedData;
fn __rust_proto_thunk__$pkg_Msg$__deserialize(
raw_msg: $NonNull$<u8>,
data: $pb$::SerializedData,
) -> bool;
msg.Emit(
{
{"new_thunk", Thunk(msg, "new")},
{"delete_thunk", Thunk(msg, "delete")},
{"serialize_thunk", Thunk(msg, "serialize")},
{"deserialize_thunk", Thunk(msg, "deserialize")},
},
R"rs(
fn $new_thunk$() -> $NonNull$<u8>;
fn $delete_thunk$(raw_msg: $NonNull$<u8>);
fn $serialize_thunk$(raw_msg: $NonNull$<u8>) -> $pb$::SerializedData;
fn $deserialize_thunk$( raw_msg: $NonNull$<u8>, data: $pb$::SerializedData) -> bool;
)rs");
return;
case Kernel::kUpb:
msg.Emit(R"rs(
fn $pkg_Msg$_new(arena: *mut $pb$::Arena) -> $NonNull$<u8>;
fn $pkg_Msg$_serialize(
msg.Emit(
{
{"new_thunk", Thunk(msg, "new")},
{"serialize_thunk", Thunk(msg, "serialize")},
},
R"rs(
fn $new_thunk$(arena: *mut $pb$::Arena) -> $NonNull$<u8>;
fn $serialize_thunk$(
msg: $NonNull$<u8>,
arena: *mut $pb$::Arena,
len: &mut usize) -> $NonNull$<u8>;
len: &mut usize,
) -> $NonNull$<u8>;
)rs");
return;
}
ABSL_LOG(FATAL) << "unreachable";
}
void MessageDrop(Context<Descriptor> msg) {
if (msg.is_upb()) {
// Nothing to do here; drop glue (which will run drop(self.arena)
// automatically) is sufficient.
return;
}
msg.Emit({{"delete_thunk", Thunk(msg, "delete")}}, R"rs(
unsafe { $delete_thunk$(self.msg); }
)rs");
}
} // namespace
MessageGenerator::MessageGenerator(Context<Descriptor> msg) {
@ -176,11 +202,11 @@ void MessageGenerator::GenerateRs(Context<Descriptor> msg) {
msg.Emit(
{
{"Msg", msg.desc().name()},
{"pkg_Msg", GetUnderscoreDelimitedFullName(msg)},
{"Msg.fields", [&] { MessageStructFields(msg); }},
{"Msg::new", [&] { MessageNew(msg); }},
{"Msg::serialize", [&] { MessageSerialize(msg); }},
{"Msg::deserialize", [&] { MessageDeserialize(msg); }},
{"Msg::drop", [&] { MessageDrop(msg); }},
{"Msg_externs", [&] { MessageExterns(msg); }},
{"accessor_fns",
[&] {
@ -235,6 +261,14 @@ void MessageGenerator::GenerateRs(Context<Descriptor> msg) {
$accessor_fns$
} // impl $Msg$
//~ We implement drop unconditionally, so that `$Msg$: Drop` regardless
//~ of kernel.
impl $std$::ops::Drop for $Msg$ {
fn drop(&mut self) {
$Msg::drop$
}
}
extern "C" {
$Msg_externs$
@ -262,8 +296,11 @@ void MessageGenerator::GenerateThunkCc(Context<Descriptor> msg) {
{
{"abi", "\"C\""}, // Workaround for syntax highlight bug in VSCode.
{"Msg", msg.desc().name()},
{"pkg_Msg", GetUnderscoreDelimitedFullName(msg)},
{"namespace", cpp::Namespace(&msg.desc())},
{"pkg", cpp::Namespace(&msg.desc())},
{"new_thunk", Thunk(msg, "new")},
{"delete_thunk", Thunk(msg, "delete")},
{"serialize_thunk", Thunk(msg, "serialize")},
{"deserialize_thunk", Thunk(msg, "deserialize")},
{"accessor_thunks",
[&] {
for (int i = 0; i < msg.desc().field_count(); ++i) {
@ -276,17 +313,12 @@ void MessageGenerator::GenerateThunkCc(Context<Descriptor> msg) {
},
R"cc(
extern $abi$ {
void* __rust_proto_thunk__$pkg_Msg$__new() {
return new $namespace$::$Msg$();
}
google::protobuf::rust_internal::SerializedData
__rust_proto_thunk__$pkg_Msg$__serialize($namespace$::$Msg$ * msg) {
void* $new_thunk$() { return new $pkg$::$Msg$(); }
void $delete_thunk$(void* ptr) { delete static_cast<$pkg$::$Msg$*>(ptr); }
google::protobuf::rust_internal::SerializedData $serialize_thunk$($pkg$::$Msg$ * msg) {
return google::protobuf::rust_internal::SerializeMsg(msg);
}
bool __rust_proto_thunk__$pkg_Msg$__deserialize(
$namespace$::$Msg$ * msg,
bool $deserialize_thunk$($pkg$::$Msg$ * msg,
google::protobuf::rust_internal::SerializedData data) {
return msg->ParseFromArray(data.data, data.len);
}

@ -45,6 +45,14 @@ namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
namespace {
std::string GetUnderscoreDelimitedFullName(Context<Descriptor> msg) {
std::string result = msg.desc().full_name();
absl::StrReplaceAll({{".", "_"}}, &result);
return result;
}
} // namespace
std::string GetCrateName(Context<FileDescriptor> dep) {
absl::string_view path = dep.desc().name();
auto basename = path.substr(path.rfind('/') + 1);
@ -74,20 +82,17 @@ std::string GetHeaderFile(Context<FileDescriptor> file) {
return absl::StrCat(basename, ".proto.h");
}
std::string GetUnderscoreDelimitedFullName(Context<Descriptor> msg) {
std::string result = msg.desc().full_name();
absl::StrReplaceAll({{".", "_"}}, &result);
return result;
}
std::string Thunk(Context<FieldDescriptor> field, absl::string_view op) {
// NOTE: When field.is_upb(), this functions outputs must match the symbols
// that the upbc plugin generates exactly. Failure to do so correctly results
// in a link-time failure.
std::string GetAccessorThunkName(Context<FieldDescriptor> field,
absl::string_view op) {
absl::string_view prefix = field.is_cpp() ? "__rust_proto_thunk__" : "";
std::string thunk =
absl::StrCat(prefix, GetUnderscoreDelimitedFullName(
field.WithDesc(field.desc().containing_type())));
if (field.is_upb() && op.empty()) {
if (field.is_upb() && op == "get") {
absl::SubstituteAndAppend(&thunk, "_$0", field.desc().name());
} else {
absl::SubstituteAndAppend(&thunk, "_$0_$1", op, field.desc().name());
@ -96,6 +101,11 @@ std::string GetAccessorThunkName(Context<FieldDescriptor> field,
return thunk;
}
std::string Thunk(Context<Descriptor> msg, absl::string_view op) {
absl::string_view prefix = msg.is_cpp() ? "__rust_proto_thunk__" : "";
return absl::StrCat(prefix, GetUnderscoreDelimitedFullName(msg), "_", op);
}
absl::string_view PrimitiveRsTypeName(Context<FieldDescriptor> field) {
switch (field.desc().type()) {
case FieldDescriptor::TYPE_BOOL:

@ -48,10 +48,8 @@ std::string GetRsFile(Context<FileDescriptor> file);
std::string GetThunkCcFile(Context<FileDescriptor> file);
std::string GetHeaderFile(Context<FileDescriptor> file);
std::string GetUnderscoreDelimitedFullName(Context<Descriptor> msg);
std::string GetAccessorThunkName(Context<FieldDescriptor> field,
absl::string_view op);
std::string Thunk(Context<FieldDescriptor> field, absl::string_view op);
std::string Thunk(Context<Descriptor> msg, absl::string_view op);
bool IsSupportedFieldType(Context<FieldDescriptor> field);

Loading…
Cancel
Save