Introduce a RustFieldType enum which captures the primitive types that a rust field can be.

The purpose is to avoid duplicating the mapping of different types that are only relevant to the serializer but not to the exposed api (e.g. FIXED32 vs INT32)

Treat type=GROUP as rust-type=MESSAGE here which is all that is needed for us to support groups in the rust codegen.

The RustFieldType is parallel to the preexisting FieldDescriptor::CppType which _almost_ does what we need, but it treats Bytes and Strings as the same cpptype which Rust codegen doesn't.

PiperOrigin-RevId: 609416940
pull/15921/head
Protobuf Team Bot 11 months ago committed by Copybara-Service
parent b9483e03c7
commit 033ff1710e
  1. 13
      rust/test/shared/accessors_test.rs
  2. 15
      src/google/protobuf/compiler/rust/BUILD.bazel
  3. 51
      src/google/protobuf/compiler/rust/accessors/accessors.cc
  4. 34
      src/google/protobuf/compiler/rust/accessors/helpers.cc
  5. 34
      src/google/protobuf/compiler/rust/naming.cc
  6. 65
      src/google/protobuf/compiler/rust/oneof.cc
  7. 53
      src/google/protobuf/compiler/rust/rust_field_type.cc
  8. 39
      src/google/protobuf/compiler/rust/rust_field_type.h

@ -1060,3 +1060,16 @@ fn test_set_message_from_view() {
assert_that!(m2.optional_int32(), eq(1i32));
}
#[test]
fn test_group() {
let mut m = TestAllTypes::new();
// Groups are exposed the same as nested message types.
assert_that!(m.optionalgroup_opt().is_set(), eq(false));
assert_that!(m.optionalgroup().a(), eq(0));
m.optionalgroup_mut().or_default().a_mut().set(7);
assert_that!(m.optionalgroup_opt().is_set(), eq(true));
assert_that!(m.optionalgroup().a(), eq(7));
}

@ -121,6 +121,7 @@ cc_library(
":context",
":helpers",
":naming",
":rust_field_type",
"//src/google/protobuf",
"//src/google/protobuf/compiler/cpp:names_internal",
"//src/google/protobuf/io:tokenizer",
@ -195,6 +196,7 @@ cc_library(
strip_include_prefix = "/src",
deps = [
":context",
":rust_field_type",
"//src/google/protobuf",
"//src/google/protobuf/compiler:code_generator",
"//src/google/protobuf/compiler/cpp:names_internal",
@ -215,6 +217,7 @@ cc_library(
":accessors",
":context",
":naming",
":rust_field_type",
"//src/google/protobuf",
"//src/google/protobuf/compiler/cpp:names",
"//src/google/protobuf/compiler/cpp:names_internal",
@ -253,6 +256,7 @@ cc_library(
deps = [
":context",
":naming",
":rust_field_type",
"//src/google/protobuf",
"//src/google/protobuf/io:tokenizer",
"@com_google_absl//absl/log:absl_check",
@ -261,3 +265,14 @@ cc_library(
"@com_google_absl//absl/strings:str_format",
],
)
cc_library(
name = "rust_field_type",
srcs = ["rust_field_type.cc"],
hdrs = ["rust_field_type.h"],
strip_include_prefix = "/src",
deps = [
"//src/google/protobuf",
"@com_google_absl//absl/log:absl_log",
],
)

@ -13,6 +13,7 @@
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/accessors/accessor_generator.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/rust_field_type.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
@ -43,43 +44,25 @@ std::unique_ptr<AccessorGenerator> AccessorGeneratorFor(
}
}
switch (field.type()) {
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_BOOL:
if (field.is_repeated()) {
return std::make_unique<RepeatedField>();
}
return std::make_unique<SingularScalar>();
case FieldDescriptor::TYPE_ENUM:
if (field.is_repeated()) {
return std::make_unique<RepeatedField>();
}
if (field.is_repeated()) {
return std::make_unique<RepeatedField>();
}
switch (GetRustFieldType(field)) {
case RustFieldType::INT32:
case RustFieldType::INT64:
case RustFieldType::UINT32:
case RustFieldType::UINT64:
case RustFieldType::FLOAT:
case RustFieldType::DOUBLE:
case RustFieldType::BOOL:
case RustFieldType::ENUM:
return std::make_unique<SingularScalar>();
case FieldDescriptor::TYPE_BYTES:
case FieldDescriptor::TYPE_STRING:
if (field.is_repeated()) {
return std::make_unique<RepeatedField>();
}
case RustFieldType::BYTES:
case RustFieldType::STRING:
return std::make_unique<SingularString>();
case FieldDescriptor::TYPE_MESSAGE:
if (field.is_repeated()) {
return std::make_unique<RepeatedField>();
}
case RustFieldType::MESSAGE:
return std::make_unique<SingularMessage>();
case FieldDescriptor::TYPE_GROUP:
return std::make_unique<UnsupportedField>("group not supported");
}
ABSL_LOG(FATAL) << "Unexpected field type: " << field.type();

@ -17,6 +17,7 @@
#include "absl/strings/str_format.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/rust_field_type.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/io/strtod.h"
@ -26,8 +27,8 @@ namespace compiler {
namespace rust {
std::string DefaultValue(Context& ctx, const FieldDescriptor& field) {
switch (field.type()) {
case FieldDescriptor::TYPE_DOUBLE:
switch (GetRustFieldType(field)) {
case RustFieldType::DOUBLE:
if (std::isfinite(field.default_value_double())) {
return absl::StrCat(io::SimpleDtoa(field.default_value_double()),
"f64");
@ -42,7 +43,7 @@ std::string DefaultValue(Context& ctx, const FieldDescriptor& field) {
} else {
ABSL_LOG(FATAL) << "unreachable";
}
case FieldDescriptor::TYPE_FLOAT:
case RustFieldType::FLOAT:
if (std::isfinite(field.default_value_float())) {
return absl::StrCat(io::SimpleFtoa(field.default_value_float()), "f32");
} else if (std::isnan(field.default_value_float())) {
@ -56,27 +57,21 @@ std::string DefaultValue(Context& ctx, const FieldDescriptor& field) {
} else {
ABSL_LOG(FATAL) << "unreachable";
}
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_SINT32:
case RustFieldType::INT32:
return absl::StrFormat("%d", field.default_value_int32());
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_SINT64:
case RustFieldType::INT64:
return absl::StrFormat("%d", field.default_value_int64());
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_UINT64:
case RustFieldType::UINT64:
return absl::StrFormat("%u", field.default_value_uint64());
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_UINT32:
case RustFieldType::UINT32:
return absl::StrFormat("%u", field.default_value_uint32());
case FieldDescriptor::TYPE_BOOL:
case RustFieldType::BOOL:
return absl::StrFormat("%v", field.default_value_bool());
case FieldDescriptor::TYPE_STRING:
case FieldDescriptor::TYPE_BYTES:
case RustFieldType::STRING:
case RustFieldType::BYTES:
return absl::StrFormat("b\"%s\"",
absl::CHexEscape(field.default_value_string()));
case FieldDescriptor::TYPE_ENUM:
case RustFieldType::ENUM:
// `$EnumName$::default()` might seem like the right choice here, but
// it is not. The default value for the enum type isn't the same as the
// field, since in `syntax = "proto2"`, an enum field can have a default
@ -88,9 +83,8 @@ std::string DefaultValue(Context& ctx, const FieldDescriptor& field) {
// expression. Trait methods in a `const` context aren't currently stable.
return absl::StrCat(RsTypePath(ctx, field),
"::", EnumValueRsName(*field.default_value_enum()));
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
ABSL_LOG(FATAL) << "Unsupported field type: " << field.type_name();
case RustFieldType::MESSAGE:
ABSL_LOG(FATAL) << "Messages can't have defaults: " << field.type_name();
}
ABSL_LOG(FATAL) << "unreachable";
}

@ -24,6 +24,7 @@
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/rust_field_type.h"
#include "google/protobuf/compiler/rust/rust_keywords.h"
#include "google/protobuf/descriptor.h"
@ -194,40 +195,31 @@ std::string GetFullyQualifiedPath(Context& ctx, const EnumDescriptor& enum_) {
}
std::string RsTypePath(Context& ctx, const FieldDescriptor& field) {
switch (field.type()) {
case FieldDescriptor::TYPE_BOOL:
switch (GetRustFieldType(field)) {
case RustFieldType::BOOL:
return "bool";
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SFIXED32:
case RustFieldType::INT32:
return "i32";
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_SFIXED64:
case RustFieldType::INT64:
return "i64";
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_UINT32:
case RustFieldType::UINT32:
return "u32";
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_UINT64:
case RustFieldType::UINT64:
return "u64";
case FieldDescriptor::TYPE_FLOAT:
case RustFieldType::FLOAT:
return "f32";
case FieldDescriptor::TYPE_DOUBLE:
case RustFieldType::DOUBLE:
return "f64";
case FieldDescriptor::TYPE_BYTES:
case RustFieldType::BYTES:
return "[u8]";
case FieldDescriptor::TYPE_STRING:
case RustFieldType::STRING:
return "::__pb::ProtoStr";
case FieldDescriptor::TYPE_MESSAGE:
case RustFieldType::MESSAGE:
return GetFullyQualifiedPath(ctx, *field.message_type());
case FieldDescriptor::TYPE_ENUM:
case RustFieldType::ENUM:
return GetFullyQualifiedPath(ctx, *field.enum_type());
default:
break;
}
ABSL_LOG(FATAL) << "Unsupported field type: " << field.type_name();
return "";
}
std::string RustModule(Context& ctx, const Descriptor& msg) {

@ -16,6 +16,7 @@
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/rust_field_type.h"
#include "google/protobuf/descriptor.h"
namespace google {
@ -86,31 +87,23 @@ std::string RsTypeNameView(Context& ctx, const FieldDescriptor& field) {
if (field.options().has_ctype()) {
return ""; // TODO: b/308792377 - ctype fields not supported yet.
}
switch (field.type()) {
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_BOOL:
switch (GetRustFieldType(field.type())) {
case RustFieldType::INT32:
case RustFieldType::INT64:
case RustFieldType::UINT32:
case RustFieldType::UINT64:
case RustFieldType::FLOAT:
case RustFieldType::DOUBLE:
case RustFieldType::BOOL:
return RsTypePath(ctx, field);
case FieldDescriptor::TYPE_BYTES:
case RustFieldType::BYTES:
return "&'msg [u8]";
case FieldDescriptor::TYPE_STRING:
case RustFieldType::STRING:
return "&'msg ::__pb::ProtoStr";
case FieldDescriptor::TYPE_MESSAGE:
case RustFieldType::MESSAGE:
return absl::StrCat("::__pb::View<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_ENUM:
case RustFieldType::ENUM:
return absl::StrCat("::__pb::View<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_GROUP: // Not supported yet.
return "";
}
ABSL_LOG(FATAL) << "Unexpected field type: " << field.type_name();
@ -122,32 +115,24 @@ std::string RsTypeNameMut(Context& ctx, const FieldDescriptor& field) {
if (field.options().has_ctype()) {
return ""; // TODO: b/308792377 - ctype fields not supported yet.
}
switch (field.type()) {
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_SFIXED32:
case FieldDescriptor::TYPE_SFIXED64:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_UINT32:
case FieldDescriptor::TYPE_UINT64:
case FieldDescriptor::TYPE_FLOAT:
case FieldDescriptor::TYPE_DOUBLE:
case FieldDescriptor::TYPE_BOOL:
switch (GetRustFieldType(field)) {
case RustFieldType::INT32:
case RustFieldType::INT64:
case RustFieldType::UINT32:
case RustFieldType::UINT64:
case RustFieldType::FLOAT:
case RustFieldType::DOUBLE:
case RustFieldType::BOOL:
return absl::StrCat("::__pb::PrimitiveMut<'msg, ", RsTypePath(ctx, field),
">");
case FieldDescriptor::TYPE_BYTES:
case RustFieldType::BYTES:
return "::__pb::BytesMut<'msg>";
case FieldDescriptor::TYPE_STRING:
case RustFieldType::STRING:
return "::__pb::ProtoStrMut<'msg>";
case FieldDescriptor::TYPE_MESSAGE:
case RustFieldType::MESSAGE:
return absl::StrCat("::__pb::Mut<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_ENUM:
case RustFieldType::ENUM:
return absl::StrCat("::__pb::Mut<'msg, ", RsTypePath(ctx, field), ">");
case FieldDescriptor::TYPE_GROUP: // Not supported yet.
return "";
}
ABSL_LOG(FATAL) << "Unexpected field type: " << field.type_name();

@ -0,0 +1,53 @@
#include "google/protobuf/compiler/rust/rust_field_type.h"
#include "absl/log/absl_log.h"
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
RustFieldType GetRustFieldType(const FieldDescriptor& field) {
return GetRustFieldType(field.type());
}
RustFieldType GetRustFieldType(FieldDescriptor::Type type) {
switch (type) {
case FieldDescriptor::TYPE_BOOL:
return RustFieldType::BOOL;
case FieldDescriptor::TYPE_INT32:
case FieldDescriptor::TYPE_SINT32:
case FieldDescriptor::TYPE_SFIXED32:
return RustFieldType::INT32;
case FieldDescriptor::TYPE_INT64:
case FieldDescriptor::TYPE_SINT64:
case FieldDescriptor::TYPE_SFIXED64:
return RustFieldType::INT64;
case FieldDescriptor::TYPE_FIXED32:
case FieldDescriptor::TYPE_UINT32:
return RustFieldType::UINT32;
case FieldDescriptor::TYPE_FIXED64:
case FieldDescriptor::TYPE_UINT64:
return RustFieldType::UINT64;
case FieldDescriptor::TYPE_FLOAT:
return RustFieldType::FLOAT;
case FieldDescriptor::TYPE_DOUBLE:
return RustFieldType::DOUBLE;
case FieldDescriptor::TYPE_BYTES:
return RustFieldType::BYTES;
case FieldDescriptor::TYPE_STRING:
return RustFieldType::STRING;
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
return RustFieldType::MESSAGE;
case FieldDescriptor::TYPE_ENUM:
return RustFieldType::ENUM;
}
ABSL_LOG(FATAL) << "Unknown field type: " << type;
}
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google

@ -0,0 +1,39 @@
#ifndef GOOGLE_PROTOBUF_COMPILER_RUST_RUST_FIELD_TYPE_H__
#define GOOGLE_PROTOBUF_COMPILER_RUST_RUST_FIELD_TYPE_H__
#include "google/protobuf/descriptor.h"
namespace google {
namespace protobuf {
namespace compiler {
namespace rust {
// An enum of all of the singular types as they should be seen by Rust. This
// is parallel to FieldDescriptor::CppType with the main difference being that
// that String and Bytes are treated as different types.
enum class RustFieldType {
INT32,
INT64,
UINT32,
UINT64,
DOUBLE,
FLOAT,
BOOL,
ENUM,
STRING,
BYTES,
MESSAGE,
};
// Note: for 'repeated X field' this returns the corresponding type of X.
// For map fields this returns MESSAGE.
RustFieldType GetRustFieldType(const FieldDescriptor& field);
RustFieldType GetRustFieldType(FieldDescriptor::Type type);
} // namespace rust
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_RUST_RUST_FIELD_TYPE_H__
Loading…
Cancel
Save