diff --git a/src/google/protobuf/compiler/cpp/BUILD.bazel b/src/google/protobuf/compiler/cpp/BUILD.bazel index 5d23c660e5..ac1184d32e 100644 --- a/src/google/protobuf/compiler/cpp/BUILD.bazel +++ b/src/google/protobuf/compiler/cpp/BUILD.bazel @@ -34,8 +34,8 @@ cc_library( copts = COPTS, include_prefix = "google/protobuf/compiler/cpp", visibility = [ - "//pkg:__pkg__", - "//src/google/protobuf/compiler/rust:__subpackages__", + "//pkg:__pkg__", + "//src/google/protobuf/compiler/rust:__subpackages__", ], deps = [ "//src/google/protobuf:protobuf_nowkt", diff --git a/src/google/protobuf/compiler/rust/BUILD.bazel b/src/google/protobuf/compiler/rust/BUILD.bazel index 61d159bb34..fb87e1d016 100644 --- a/src/google/protobuf/compiler/rust/BUILD.bazel +++ b/src/google/protobuf/compiler/rust/BUILD.bazel @@ -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"], diff --git a/src/google/protobuf/compiler/rust/accessors/singular_bytes.cc b/src/google/protobuf/compiler/rust/accessors/singular_bytes.cc index a5b0171322..bf2e0e5c28 100644 --- a/src/google/protobuf/compiler/rust/accessors/singular_bytes.cc +++ b/src/google/protobuf/compiler/rust/accessors/singular_bytes.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 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$) -> 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) { diff --git a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc index 5797a19b38..dac5b3e8c7 100644 --- a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc +++ b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc @@ -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$) -> 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) { diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc index ba22d696ec..64b5885371 100644 --- a/src/google/protobuf/compiler/rust/message.cc +++ b/src/google/protobuf/compiler/rust/message.cc @@ -65,15 +65,15 @@ void MessageStructFields(Context msg) { void MessageNew(Context 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 msg) { void MessageSerialize(Context 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,17 +108,21 @@ void MessageSerialize(Context msg) { void MessageDeserialize(Context msg) { switch (msg.opts().kernel) { case Kernel::kCpp: - msg.Emit(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) - }; - success.then_some(()).ok_or($pb$::ParseError) - )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(), + ); + + $deserialize_thunk$(self.msg, data) + }; + success.then_some(()).ok_or($pb$::ParseError) + )rs"); return; case Kernel::kUpb: @@ -135,30 +139,52 @@ void MessageDeserialize(Context msg) { void MessageExterns(Context msg) { switch (msg.opts().kernel) { case Kernel::kCpp: - msg.Emit(R"rs( - fn __rust_proto_thunk__$pkg_Msg$__new() -> $NonNull$; - fn __rust_proto_thunk__$pkg_Msg$__serialize(raw_msg: $NonNull$) - -> $pb$::SerializedData; - fn __rust_proto_thunk__$pkg_Msg$__deserialize( - raw_msg: $NonNull$, - data: $pb$::SerializedData, - ) -> bool; - )rs"); + 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$; + fn $delete_thunk$(raw_msg: $NonNull$); + fn $serialize_thunk$(raw_msg: $NonNull$) -> $pb$::SerializedData; + fn $deserialize_thunk$( raw_msg: $NonNull$, data: $pb$::SerializedData) -> bool; + )rs"); return; case Kernel::kUpb: - msg.Emit(R"rs( - fn $pkg_Msg$_new(arena: *mut $pb$::Arena) -> $NonNull$; - 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$; + fn $serialize_thunk$( msg: $NonNull$, arena: *mut $pb$::Arena, - len: &mut usize) -> $NonNull$; - )rs"); + len: &mut usize, + ) -> $NonNull$; + )rs"); return; } ABSL_LOG(FATAL) << "unreachable"; } + +void MessageDrop(Context 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 msg) { @@ -176,11 +202,11 @@ void MessageGenerator::GenerateRs(Context 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 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 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,18 +313,13 @@ void MessageGenerator::GenerateThunkCc(Context 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, - google::protobuf::rust_internal::SerializedData data) { + bool $deserialize_thunk$($pkg$::$Msg$ * msg, + google::protobuf::rust_internal::SerializedData data) { return msg->ParseFromArray(data.data, data.len); } diff --git a/src/google/protobuf/compiler/rust/naming.cc b/src/google/protobuf/compiler/rust/naming.cc index 3e21a6e0c0..330f9cb4e3 100644 --- a/src/google/protobuf/compiler/rust/naming.cc +++ b/src/google/protobuf/compiler/rust/naming.cc @@ -45,6 +45,14 @@ namespace google { namespace protobuf { namespace compiler { namespace rust { +namespace { +std::string GetUnderscoreDelimitedFullName(Context msg) { + std::string result = msg.desc().full_name(); + absl::StrReplaceAll({{".", "_"}}, &result); + return result; +} +} // namespace + std::string GetCrateName(Context dep) { absl::string_view path = dep.desc().name(); auto basename = path.substr(path.rfind('/') + 1); @@ -74,20 +82,17 @@ std::string GetHeaderFile(Context file) { return absl::StrCat(basename, ".proto.h"); } -std::string GetUnderscoreDelimitedFullName(Context msg) { - std::string result = msg.desc().full_name(); - absl::StrReplaceAll({{".", "_"}}, &result); - return result; -} +std::string Thunk(Context 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 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 field, return thunk; } +std::string Thunk(Context 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 field) { switch (field.desc().type()) { case FieldDescriptor::TYPE_BOOL: diff --git a/src/google/protobuf/compiler/rust/naming.h b/src/google/protobuf/compiler/rust/naming.h index 0b34c23a10..8b3481739e 100644 --- a/src/google/protobuf/compiler/rust/naming.h +++ b/src/google/protobuf/compiler/rust/naming.h @@ -48,10 +48,8 @@ std::string GetRsFile(Context file); std::string GetThunkCcFile(Context file); std::string GetHeaderFile(Context file); -std::string GetUnderscoreDelimitedFullName(Context msg); - -std::string GetAccessorThunkName(Context field, - absl::string_view op); +std::string Thunk(Context field, absl::string_view op); +std::string Thunk(Context msg, absl::string_view op); bool IsSupportedFieldType(Context field);