From e5679c01e8f47e8a5e7172444676bda1c2ada875 Mon Sep 17 00:00:00 2001 From: Marcel Hlopko Date: Wed, 19 Apr 2023 00:54:28 -0700 Subject: [PATCH] Implement nested messages for v0 API for cpp kernel PiperOrigin-RevId: 525372222 --- rust/test/cpp/BUILD | 10 +++ rust/test/cpp/accessors_test.rs | 2 +- rust/test/cpp/nested_messages_test.rs | 39 +++++++++++ .../compiler/rust/accessors/singular_bytes.cc | 12 ++-- .../rust/accessors/singular_scalar.cc | 11 ++-- .../protobuf/compiler/rust/generator.cc | 2 +- src/google/protobuf/compiler/rust/message.cc | 66 +++++++++++++++---- src/google/protobuf/compiler/rust/message.h | 2 +- 8 files changed, 118 insertions(+), 26 deletions(-) create mode 100644 rust/test/cpp/nested_messages_test.rs diff --git a/rust/test/cpp/BUILD b/rust/test/cpp/BUILD index 49d1de9b9c..18d68b9f3e 100644 --- a/rust/test/cpp/BUILD +++ b/rust/test/cpp/BUILD @@ -21,3 +21,13 @@ rust_test( ], deps = ["//rust/test:unittest_cc_rust_proto"], ) + +rust_test( + name = "nested_messages_test", + srcs = ["nested_messages_test.rs"], + tags = [ + # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain. + "not_build:arm", + ], + deps = ["//rust/test:unittest_cc_rust_proto"], +) diff --git a/rust/test/cpp/accessors_test.rs b/rust/test/cpp/accessors_test.rs index 6d7dcf5362..4f6c5f63f8 100644 --- a/rust/test/cpp/accessors_test.rs +++ b/rust/test/cpp/accessors_test.rs @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -/// Tests covering accessors for singular bool and int64 fields. +/// Tests covering accessors for singular bool, int64, and bytes fields. use unittest_proto::proto2_unittest::TestAllTypes; #[test] diff --git a/rust/test/cpp/nested_messages_test.rs b/rust/test/cpp/nested_messages_test.rs new file mode 100644 index 0000000000..2f82e985c7 --- /dev/null +++ b/rust/test/cpp/nested_messages_test.rs @@ -0,0 +1,39 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/// Tests covering nested messages. + +#[test] +fn test_nested_messages_accesible() { + let _parent: unittest_proto::proto2_unittest::TestAllTypes; + let _child: unittest_proto::proto2_unittest::TestAllTypes_::NestedMessage; + unittest_proto::proto2_unittest::TestChildExtensionData_:: + NestedTestAllExtensionsData_::NestedDynamicExtensions::new(); +} diff --git a/src/google/protobuf/compiler/rust/accessors/singular_bytes.cc b/src/google/protobuf/compiler/rust/accessors/singular_bytes.cc index bf2e0e5c28..20662d827c 100644 --- a/src/google/protobuf/compiler/rust/accessors/singular_bytes.cc +++ b/src/google/protobuf/compiler/rust/accessors/singular_bytes.cc @@ -94,25 +94,25 @@ class SingularBytes final : public AccessorGenerator { field.Emit( { {"field", field.desc().name()}, - {"namespace", cpp::Namespace(field.desc().containing_type())}, + {"QualifiedMsg", + cpp::QualifiedClassName(field.desc().containing_type())}, {"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) { + bool $hazzer_thunk$($QualifiedMsg$* msg) { return msg->has_$field$(); } - ::google::protobuf::rust_internal::PtrAndLen $getter_thunk$($namespace$::$Msg$* msg) { + ::google::protobuf::rust_internal::PtrAndLen $getter_thunk$($QualifiedMsg$* msg) { absl::string_view val = msg->$field$(); return google::protobuf::rust_internal::PtrAndLen(val.data(), val.size()); } - void $setter_thunk$($namespace$::$Msg$* msg, const char* ptr, - ::std::size_t size) { + void $setter_thunk$($QualifiedMsg$* msg, const char* ptr, ::std::size_t size) { msg->set_$field$(absl::string_view(ptr, size)); } - void $clearer_thunk$($namespace$::$Msg$* msg) { msg->clear_$field$(); } + void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); } )cc"); } }; diff --git a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc index dac5b3e8c7..d2128ea05b 100644 --- a/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc +++ b/src/google/protobuf/compiler/rust/accessors/singular_scalar.cc @@ -94,21 +94,22 @@ class SingularScalar final : public AccessorGenerator { { {"field", field.desc().name()}, {"Scalar", cpp::PrimitiveTypeName(field.desc().cpp_type())}, - {"namespace", cpp::Namespace(field.desc().containing_type())}, + {"QualifiedMsg", + cpp::QualifiedClassName(field.desc().containing_type())}, {"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) { + bool $hazzer_thunk$($QualifiedMsg$* msg) { return msg->has_$field$(); } - $Scalar$ $getter_thunk$($namespace$::$Msg$* msg) { return msg->$field$(); } - void $setter_thunk$($namespace$::$Msg$* msg, $Scalar$ val) { + $Scalar$ $getter_thunk$($QualifiedMsg$* msg) { return msg->$field$(); } + void $setter_thunk$($QualifiedMsg$* msg, $Scalar$ val) { msg->set_$field$(val); } - void $clearer_thunk$($namespace$::$Msg$* msg) { msg->clear_$field$(); } + void $clearer_thunk$($QualifiedMsg$* msg) { msg->clear_$field$(); } )cc"); } }; diff --git a/src/google/protobuf/compiler/rust/generator.cc b/src/google/protobuf/compiler/rust/generator.cc index 4a1d6dd072..9b4071fa30 100644 --- a/src/google/protobuf/compiler/rust/generator.cc +++ b/src/google/protobuf/compiler/rust/generator.cc @@ -153,7 +153,7 @@ bool RustGenerator::Generate(const FileDescriptor* file_desc, thunks_msg.Emit({{"Msg", msg.desc().full_name()}}, R"cc( // $Msg$ )cc"); - gen.GenerateThunkCc(thunks_msg); + gen.GenerateThunksCc(thunks_msg); thunks_msg.printer().PrintRaw("\n"); } } diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc index 64b5885371..99a33c1d35 100644 --- a/src/google/protobuf/compiler/rust/message.cc +++ b/src/google/protobuf/compiler/rust/message.cc @@ -32,6 +32,8 @@ #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" +#include "absl/strings/string_view.h" +#include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/names.h" #include "google/protobuf/compiler/rust/accessors/accessors.h" #include "google/protobuf/compiler/rust/context.h" @@ -239,6 +241,28 @@ void MessageGenerator::GenerateRs(Context msg) { msg.printer().PrintRaw("\n"); } }}, + {"nested_msgs", + [&] { + if (msg.desc().nested_type_count() == 0) { + return; + } + msg.Emit({{"Msg", msg.desc().name()}, + {"nested_msgs", + [&] { + for (int i = 0; i < msg.desc().nested_type_count(); + ++i) { + auto nested_msg = + msg.WithDesc(msg.desc().nested_type(i)); + MessageGenerator gen(nested_msg); + gen.GenerateRs(nested_msg); + } + }}}, + R"rs( + pub mod $Msg$_ { + $nested_msgs$ + } // mod $Msg$_ + )rs"); + }}, }, R"rs( #[allow(non_camel_case_types)] @@ -274,6 +298,8 @@ void MessageGenerator::GenerateRs(Context msg) { $accessor_externs$ } // extern "C" for $Msg$ + + $nested_msgs$ )rs"); if (msg.is_cpp()) { @@ -289,18 +315,27 @@ void MessageGenerator::GenerateRs(Context msg) { } // Generates code for a particular message in `.pb.thunk.cc`. -void MessageGenerator::GenerateThunkCc(Context msg) { +void MessageGenerator::GenerateThunksCc(Context msg) { ABSL_CHECK(msg.is_cpp()); msg.Emit( { {"abi", "\"C\""}, // Workaround for syntax highlight bug in VSCode. {"Msg", msg.desc().name()}, - {"pkg", cpp::Namespace(&msg.desc())}, + {"QualifiedMsg", cpp::QualifiedClassName(&msg.desc())}, {"new_thunk", Thunk(msg, "new")}, {"delete_thunk", Thunk(msg, "delete")}, {"serialize_thunk", Thunk(msg, "serialize")}, {"deserialize_thunk", Thunk(msg, "deserialize")}, + {"nested_msg_thunks", + [&] { + for (int i = 0; i < msg.desc().nested_type_count(); ++i) { + Context nested_msg = + msg.WithDesc(msg.desc().nested_type(i)); + MessageGenerator gen(nested_msg); + gen.GenerateThunksCc(nested_msg); + } + }}, {"accessor_thunks", [&] { for (int i = 0; i < msg.desc().field_count(); ++i) { @@ -312,19 +347,26 @@ void MessageGenerator::GenerateThunkCc(Context msg) { }}, }, R"cc( + // $abi$ is a workaround for a syntax highlight bug in VSCode. However, + // that confuses clang-format (it refuses to keep the newline after + // `$abi${`). Disabling clang-format for the block. + // clang-format off extern $abi$ { - 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 $deserialize_thunk$($pkg$::$Msg$ * msg, - google::protobuf::rust_internal::SerializedData data) { - return msg->ParseFromArray(data.data, data.len); - } + void * $new_thunk$(){return new $QualifiedMsg$(); } + void $delete_thunk$(void* ptr) { delete static_cast<$QualifiedMsg$*>(ptr); } + google::protobuf::rust_internal::SerializedData $serialize_thunk$($QualifiedMsg$* msg) { + return google::protobuf::rust_internal::SerializeMsg(msg); + } + bool $deserialize_thunk$($QualifiedMsg$* msg, + google::protobuf::rust_internal::SerializedData data) { + return msg->ParseFromArray(data.data, data.len); + } - $accessor_thunks$ + $accessor_thunks$ } // extern $abi$ + // clang-format on + + $nested_msg_thunks$ )cc"); } diff --git a/src/google/protobuf/compiler/rust/message.h b/src/google/protobuf/compiler/rust/message.h index e205ed6f8e..0834e2cf38 100644 --- a/src/google/protobuf/compiler/rust/message.h +++ b/src/google/protobuf/compiler/rust/message.h @@ -51,7 +51,7 @@ class MessageGenerator final { void GenerateRs(Context msg); // Generates code for a particular message in `.pb.thunk.cc`. - void GenerateThunkCc(Context msg); + void GenerateThunksCc(Context msg); private: std::vector> accessors_;