#protobuf #rust Generate fields with imported types

Before this change if a field type was defined in a imported .proto file then our codegen would not generate the field. After this change such fields are correctly generated (see tests). This change is rather trivial as all the supporting infra has been implemented as part of the .proto -> crate mapping CLs.

PiperOrigin-RevId: 601443383
pull/15450/head
Jakob Buchgraber 1 year ago committed by Copybara-Service
parent 5f51020f5d
commit 90015d3145
  1. 63
      rust/test/BUILD
  2. 22
      rust/test/fields_with_imported_types.proto
  3. 19
      rust/test/imported_types.proto
  4. 30
      rust/test/shared/BUILD
  5. 42
      rust/test/shared/fields_with_imported_types_test.rs
  6. 12
      src/google/protobuf/compiler/rust/accessors/accessors.cc
  7. 24
      src/google/protobuf/compiler/rust/naming.cc
  8. 16
      src/google/protobuf/compiler/rust/oneof.cc
  9. 2
      src/google/protobuf/editions/codegen_tests/BUILD
  10. 27
      src/google/protobuf/editions/codegen_tests/rust_bazel_crate_mapping.txt

@ -1,10 +1,10 @@
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
load(
"//rust:defs.bzl",
"rust_cc_proto_library",
"rust_proto_library",
"rust_upb_proto_library",
)
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
UNITTEST_PROTO_TARGET = "//src/google/protobuf:test_protos"
@ -440,3 +440,64 @@ rust_upb_proto_library(
],
deps = [":struct"],
)
proto_library(
name = "imported_types_proto",
testonly = True,
srcs = ["imported_types.proto"],
)
cc_proto_library(
name = "imported_types_cc_proto",
testonly = True,
deps = [":imported_types_proto"],
)
rust_cc_proto_library(
name = "imported_types_cc_rust_proto",
testonly = True,
visibility = [
"//rust/test/shared:__subpackages__",
],
deps = [":imported_types_cc_proto"],
)
rust_upb_proto_library(
name = "imported_types_upb_rust_proto",
testonly = True,
visibility = [
"//rust/test/shared:__subpackages__",
],
deps = [":imported_types_proto"],
)
proto_library(
name = "fields_with_imported_types_proto",
testonly = True,
srcs = ["fields_with_imported_types.proto"],
deps = [":imported_types_proto"],
)
cc_proto_library(
name = "fields_with_imported_types_cc_proto",
testonly = True,
deps = [":fields_with_imported_types_proto"],
)
rust_cc_proto_library(
name = "fields_with_imported_types_cc_rust_proto",
testonly = True,
visibility = [
"//rust/test/shared:__subpackages__",
],
deps = [":fields_with_imported_types_cc_proto"],
)
rust_upb_proto_library(
name = "fields_with_imported_types_upb_rust_proto",
testonly = True,
visibility = [
"//rust/test/shared:__subpackages__",
],
deps = [":fields_with_imported_types_proto"],
)

@ -0,0 +1,22 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
syntax = "proto2";
package main;
import "google/protobuf/rust/test/imported_types.proto";
message MsgWithFieldsWithImportedTypes {
optional imported_types.ImportedMessage imported_message_field = 1;
optional imported_types.ImportedEnum imported_enum_field = 2;
oneof imported_types_oneof {
imported_types.ImportedMessage imported_message_oneof = 3;
imported_types.ImportedEnum imported_enum_oneof = 4;
}
}

@ -0,0 +1,19 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
syntax = "proto2";
package imported_types;
message ImportedMessage {
optional int32 num = 1;
}
enum ImportedEnum {
IMPORTED_ENUM_UNKNOWN = 0;
IMPORTED_ENUM_BAR = 1;
}

@ -481,3 +481,33 @@ rust_test(
"//rust/test:struct_upb_rust_proto",
],
)
rust_test(
name = "fields_with_imported_types_cpp_test",
srcs = ["fields_with_imported_types_test.rs"],
tags = [
# TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
"not_build:arm",
],
deps = [
"//rust:protobuf_cpp",
"//rust/test:fields_with_imported_types_cc_rust_proto",
"//rust/test:imported_types_cc_rust_proto",
"@crate_index//:googletest",
],
)
rust_test(
name = "fields_with_imported_types_upb_test",
srcs = ["fields_with_imported_types_test.rs"],
tags = [
# TODO: Enable testing on arm once we support sanitizers for Rust on Arm.
"not_build:arm",
],
deps = [
"//rust:protobuf_upb",
"//rust/test:fields_with_imported_types_upb_rust_proto",
"//rust/test:imported_types_upb_rust_proto",
"@crate_index//:googletest",
],
)

@ -0,0 +1,42 @@
// Protocol Buffers - Google's data interchange format
// Copyright 2024 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
/// Tests covering that fields with types that are defined in imported .proto
/// files are generated. In particular where the imported .proto file is part of
/// a separate proto_library target.
use googletest::prelude::*;
#[test]
fn test_message_field_generated() {
use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes;
use imported_types_proto::ImportedMessageView;
let msg = MsgWithFieldsWithImportedTypes::new();
assert_that!(msg.imported_message_field(), matches_pattern!(ImportedMessageView { .. }));
}
#[test]
fn test_enum_field_generated() {
use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes;
use imported_types_proto::ImportedEnum;
let msg = MsgWithFieldsWithImportedTypes::new();
assert_that!(msg.imported_enum_field(), eq(ImportedEnum::Unknown));
}
#[test]
fn test_oneof_message_field_generated() {
use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes;
use fields_with_imported_types_proto::MsgWithFieldsWithImportedTypes_::ImportedTypesOneof::not_set;
use imported_types_proto::ImportedEnum;
use imported_types_proto::ImportedMessageView;
let msg = MsgWithFieldsWithImportedTypes::new();
assert_that!(msg.imported_message_oneof(), matches_pattern!(ImportedMessageView { .. }));
assert_that!(msg.imported_enum_oneof(), eq(ImportedEnum::Unknown));
assert_that!(msg.imported_types_oneof(), matches_pattern!(not_set(_)));
}

@ -64,12 +64,6 @@ std::unique_ptr<AccessorGenerator> AccessorGeneratorFor(
}
return std::make_unique<SingularScalar>();
case FieldDescriptor::TYPE_ENUM:
// TODO: support enums which are defined in other crates.
if (!IsInCurrentlyGeneratingCrate(ctx, *field.enum_type())) {
return std::make_unique<UnsupportedField>(
"enum fields that are imported from another proto_library"
" (defined in a separate Rust crate) are not supported");
}
if (field.is_repeated()) {
return std::make_unique<RepeatedField>();
}
@ -81,12 +75,6 @@ std::unique_ptr<AccessorGenerator> AccessorGeneratorFor(
}
return std::make_unique<SingularString>();
case FieldDescriptor::TYPE_MESSAGE:
// TODO: support messages which are defined in other crates.
if (!IsInCurrentlyGeneratingCrate(ctx, *field.message_type())) {
return std::make_unique<UnsupportedField>(
"message fields that are imported from another proto_library"
" (defined in a separate Rust crate) are not supported");
}
if (field.is_repeated()) {
return std::make_unique<RepeatedField>();
}

@ -167,6 +167,22 @@ std::string ThunkName(Context& ctx, const Descriptor& msg,
op);
}
std::string GetFullyQualifiedPath(Context& ctx, const Descriptor& msg) {
auto rel_path = GetCrateRelativeQualifiedPath(ctx, msg);
if (IsInCurrentlyGeneratingCrate(ctx, msg)) {
return absl::StrCat("crate::", rel_path);
}
return absl::StrCat(GetCrateName(ctx, *msg.file()), "::", rel_path);
}
std::string GetFullyQualifiedPath(Context& ctx, const EnumDescriptor& enum_) {
auto rel_path = GetCrateRelativeQualifiedPath(ctx, enum_);
if (IsInCurrentlyGeneratingCrate(ctx, enum_)) {
return absl::StrCat("crate::", rel_path);
}
return absl::StrCat(GetCrateName(ctx, *enum_.file()), "::", rel_path);
}
std::string RsTypePath(Context& ctx, const FieldDescriptor& field) {
switch (field.type()) {
case FieldDescriptor::TYPE_BOOL:
@ -194,13 +210,9 @@ std::string RsTypePath(Context& ctx, const FieldDescriptor& field) {
case FieldDescriptor::TYPE_STRING:
return "::__pb::ProtoStr";
case FieldDescriptor::TYPE_MESSAGE:
// TODO: Fix depending on types from other proto_libraries.
return absl::StrCat(
"crate::", GetCrateRelativeQualifiedPath(ctx, *field.message_type()));
return GetFullyQualifiedPath(ctx, *field.message_type());
case FieldDescriptor::TYPE_ENUM:
// TODO: Fix depending on types from other proto_libraries.
return absl::StrCat(
"crate::", GetCrateRelativeQualifiedPath(ctx, *field.enum_type()));
return GetFullyQualifiedPath(ctx, *field.enum_type());
default:
break;
}

@ -106,16 +106,8 @@ std::string RsTypeNameView(Context& ctx, const FieldDescriptor& field) {
case FieldDescriptor::TYPE_STRING:
return "&'msg ::__pb::ProtoStr";
case FieldDescriptor::TYPE_MESSAGE:
// TODO: support messages which are defined in other crates.
if (!IsInCurrentlyGeneratingCrate(ctx, *field.message_type())) {
return "";
}
return absl::StrCat("::__pb::View<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_ENUM:
// TODO: support enums which are defined in other crates.
if (!IsInCurrentlyGeneratingCrate(ctx, *field.enum_type())) {
return "";
}
return absl::StrCat("::__pb::View<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_GROUP: // Not supported yet.
return "";
@ -151,16 +143,8 @@ std::string RsTypeNameMut(Context& ctx, const FieldDescriptor& field) {
case FieldDescriptor::TYPE_STRING:
return "::__pb::ProtoStrMut<'msg>";
case FieldDescriptor::TYPE_MESSAGE:
// TODO: support messages which are defined in other crates.
if (!IsInCurrentlyGeneratingCrate(ctx, *field.message_type())) {
return "";
}
return absl::StrCat("::__pb::Mut<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_ENUM:
// TODO: support enums which are defined in other crates.
if (!IsInCurrentlyGeneratingCrate(ctx, *field.enum_type())) {
return "";
}
return absl::StrCat("::__pb::Mut<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_GROUP: // Not supported yet.
return "";

@ -1,7 +1,7 @@
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
exports_files(
glob(["*.proto"]),
glob(["*.proto"]) + ["rust_bazel_crate_mapping.txt"],
visibility = [
"//src/google/protobuf/editions:__pkg__",
],

@ -0,0 +1,27 @@
proto3_implicit_proto
1
third_party/protobuf/editions/codegen_tests/proto3_implicit.proto
proto2_optional_proto
1
third_party/protobuf/editions/codegen_tests/proto2_optional.proto
proto3_enum_proto
1
third_party/protobuf/editions/codegen_tests/proto3_enum.proto
struct
1
google/protobuf/struct.proto
wrappers
1
google/protobuf/wrappers.proto
duration
1
google/protobuf/duration.proto
timestamp
1
google/protobuf/timestamp.proto
field_mask
1
google/protobuf/field_mask.proto
any
1
google/protobuf/any.proto
Loading…
Cancel
Save