diff --git a/rust/test/shared/accessors_test.rs b/rust/test/shared/accessors_test.rs index 8f5b6c3895..6d73c5ff2d 100644 --- a/rust/test/shared/accessors_test.rs +++ b/rust/test/shared/accessors_test.rs @@ -364,10 +364,11 @@ fn test_nonempty_default_string_accessors() { #[test] fn test_singular_msg_field() { + use crate::TestAllTypes_::NestedMessageView; let msg = TestAllTypes::new(); // TODO("b/285309454"): fetch the inner integer `bb` // call should look like msg.optional_nested_message().bb() - let _msg: unittest_proto::proto2_unittest::TestAllTypesView = msg.optional_nested_message(); + let _msg: NestedMessageView = msg.optional_nested_message(); } #[test] diff --git a/src/google/protobuf/compiler/rust/accessors/singular_message.cc b/src/google/protobuf/compiler/rust/accessors/singular_message.cc index fba30ca651..3fe54d1e73 100644 --- a/src/google/protobuf/compiler/rust/accessors/singular_message.cc +++ b/src/google/protobuf/compiler/rust/accessors/singular_message.cc @@ -5,9 +5,13 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd +#include "absl/strings/match.h" #include "absl/strings/string_view.h" +#include "absl/strings/strip.h" +#include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/rust/accessors/accessor_generator.h" #include "google/protobuf/compiler/rust/context.h" +#include "google/protobuf/compiler/rust/naming.h" #include "google/protobuf/descriptor.h" namespace google { @@ -16,29 +20,46 @@ namespace compiler { namespace rust { void SingularMessage::InMsgImpl(Context field) const { + Context d = field.WithDesc(field.desc().message_type()); + auto prefix = "crate::" + GetCrateRelativeQualifiedPath(d); + // here we defer unit tests with messages that have import inside their + // pkg name e.g. unittest_import.proto + if (absl::StrContains(prefix, "import")) { + // TODO(b/285309454): Handle imports correctly, default to $Msg$View for now + prefix = field.desc().containing_type()->name(); + } field.Emit( { + {"prefix", prefix}, {"field", field.desc().name()}, + {"getter_thunk", Thunk(field, "get")}, }, R"rs( - // inMsgImpl - pub fn r#$field$(&self) -> $Msg$View { - $Msg$View { msg: self.inner.msg, _phantom: std::marker::PhantomData } + pub fn r#$field$(&self) -> $prefix$View { + $prefix$View::new($pbi$::Private, unsafe { $getter_thunk$(self.inner.msg) } ) } )rs"); } void SingularMessage::InExternC(Context field) const { - field.Emit({}, - R"rs( - // inExternC + field.Emit( + { + {"getter_thunk", Thunk(field, "get")}, + }, + R"rs( + fn $getter_thunk$(raw_msg: $pbi$::RawMessage) -> $pbi$::RawMessage; )rs"); } void SingularMessage::InThunkCc(Context field) const { - field.Emit({}, + field.Emit({{"QualifiedMsg", + cpp::QualifiedClassName(field.desc().containing_type())}, + {"getter_thunk", Thunk(field, "get")}, + {"field", cpp::FieldName(&field.desc())}}, R"cc( - // inThunkCC + const void* $getter_thunk$($QualifiedMsg$* msg) { + return static_cast(&msg->$field$()); + } )cc"); } diff --git a/src/google/protobuf/compiler/rust/generator.cc b/src/google/protobuf/compiler/rust/generator.cc index d14335caa3..43504fb8cd 100644 --- a/src/google/protobuf/compiler/rust/generator.cc +++ b/src/google/protobuf/compiler/rust/generator.cc @@ -96,6 +96,8 @@ void EmitPubUseOfOwnMessages(Context& primary_file, primary_file.Emit({{"mod", mod}, {"Msg", name}}, R"rs( pub use crate::$mod$::$Msg$; + // TODO(b/285309454) Address use for imported crates + pub use crate::$mod$::$Msg$View; )rs"); } } @@ -110,10 +112,11 @@ void EmitPubUseForImportedMessages(Context& primary_file, std::string crate_name = GetCrateName(dep); for (int i = 0; i < dep.desc().message_type_count(); ++i) { auto msg = primary_file.WithDesc(dep.desc().message_type(i)); - auto path = GetCrateRelativeQualifiedPath(msg); + auto path = GetCrateRelativeQualifiedPath(msg); // TODO: b/300080946 primary_file.Emit({{"crate", crate_name}, {"pkg::Msg", path}}, R"rs( pub use $crate$::$pkg::Msg$; + pub use $crate$::$pkg::Msg$View; )rs"); } } diff --git a/src/google/protobuf/compiler/rust/message.cc b/src/google/protobuf/compiler/rust/message.cc index 7feb9b0c76..7d762c6b63 100644 --- a/src/google/protobuf/compiler/rust/message.cc +++ b/src/google/protobuf/compiler/rust/message.cc @@ -274,6 +274,13 @@ void GenerateRs(Context msg) { _phantom: $Phantom$<&'a ()>, } + impl<'a> $Msg$View<'a> { + #[doc(hidden)] + pub fn new(_private: $pbi$::Private, msg: $pbi$::RawMessage) -> Self { + Self { msg, _phantom: std::marker::PhantomData } + } + } + // SAFETY: // - `$Msg$View` does not perform any mutation. // - While a `$Msg$View` exists, a `$Msg$Mut` can't exist to mutate diff --git a/src/google/protobuf/compiler/rust/naming.cc b/src/google/protobuf/compiler/rust/naming.cc index 7f857eb913..fb2362d043 100644 --- a/src/google/protobuf/compiler/rust/naming.cc +++ b/src/google/protobuf/compiler/rust/naming.cc @@ -10,9 +10,11 @@ #include #include "absl/log/absl_log.h" +#include "absl/strings/match.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_replace.h" #include "absl/strings/string_view.h" +#include "absl/strings/strip.h" #include "absl/strings/substitute.h" #include "google/protobuf/compiler/code_generator.h" #include "google/protobuf/compiler/rust/context.h" @@ -148,10 +150,19 @@ std::string RustInternalModuleName(Context file) { } std::string GetCrateRelativeQualifiedPath(Context msg) { + std::string name = msg.desc().full_name(); if (msg.desc().file()->package().empty()) { - return msg.desc().name(); + return name; } - return absl::StrCat(RustModule(msg), "::", msg.desc().name()); + // when computing the relative path, we don't want the package name, so we + // strip that out + name = + std::string(absl::StripPrefix(name, msg.desc().file()->package() + ".")); + // proto nesting is marked with periods in .proto files -- this gets + // translated to delimiting via _:: in terra rust + absl::StrReplaceAll({{".", "_::"}}, &name); + + return absl::StrCat(RustModule(msg), "::", name); } std::string FieldInfoComment(Context field) {