Make util function for whether a string field with unsupported ctype results in the fields being 'privatized'.

Use that function to disable generation of accessors in Rust OSS if the underlying C++ accessors are not available.

PiperOrigin-RevId: 694094592
pull/19110/head
Protobuf Team Bot 4 months ago committed by Copybara-Service
parent 9b156f12c8
commit a0d13b9003
  1. 8
      src/google/protobuf/compiler/cpp/field_generators/string_field.cc
  2. 8
      src/google/protobuf/compiler/cpp/field_generators/string_view_field.cc
  3. 29
      src/google/protobuf/compiler/rust/accessors/accessors.cc
  4. 5
      src/google/protobuf/compiler/rust/accessors/accessors.h
  5. 4
      src/google/protobuf/compiler/rust/accessors/generator.h
  6. 6
      src/google/protobuf/compiler/rust/accessors/unsupported_field.cc
  7. 40
      src/google/protobuf/compiler/rust/oneof.cc
  8. 26
      src/google/protobuf/descriptor.cc
  9. 8
      src/google/protobuf/descriptor.h

@ -234,9 +234,7 @@ void SingularString::GenerateAccessorDeclarations(io::Printer* p) const {
// files that applied the ctype. The field can still be accessed via the
// reflection interface since the reflection interface is independent of
// the string's underlying representation.
bool unknown_ctype = GetDeclaredStringType() != pb::CppFeatures::STRING;
if (unknown_ctype) {
if (internal::cpp::IsStringFieldWithPrivatizedAccessors(*field_)) {
p->Emit(R"cc(
private: // Hidden due to unknown ctype option.
)cc");
@ -817,9 +815,7 @@ class RepeatedString : public FieldGeneratorBase {
};
void RepeatedString::GenerateAccessorDeclarations(io::Printer* p) const {
bool unknown_ctype = GetDeclaredStringType() != pb::CppFeatures::STRING;
if (unknown_ctype) {
if (internal::cpp::IsStringFieldWithPrivatizedAccessors(*field_)) {
p->Emit(R"cc(
private: // Hidden due to unknown ctype option.
)cc");

@ -635,13 +635,7 @@ class RepeatedStringView : public FieldGeneratorBase {
};
void RepeatedStringView::GenerateAccessorDeclarations(io::Printer* p) const {
bool unknown_ctype = GetDeclaredStringType() != pb::CppFeatures::VIEW;
if (unknown_ctype) {
p->Emit(R"cc(
private: // Hidden due to unknown ctype option.
)cc");
}
ABSL_DCHECK(GetDeclaredStringType() == pb::CppFeatures::VIEW);
auto v1 = p->WithVars(AnnotatedAccessors(field_, {"", "_internal_"}));
auto v2 = p->WithVars(

@ -23,18 +23,35 @@ namespace protobuf {
namespace compiler {
namespace rust {
namespace {
bool IsSupportedField(Context& ctx, const FieldDescriptor& field) {
if (ctx.is_upb()) {
// All fields supported on upb kernel.
return true;
}
std::unique_ptr<AccessorGenerator> AccessorGeneratorFor(
Context& ctx, const FieldDescriptor& field) {
// TODO: We do not support repeated strings on C++ kernel if
// they are not string_view or string type.
if (ctx.is_cpp() && field.is_repeated() &&
if (field.is_repeated() &&
field.cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
field.cpp_string_type() != FieldDescriptor::CppStringType::kView &&
field.cpp_string_type() != FieldDescriptor::CppStringType::kString) {
return std::make_unique<UnsupportedField>(
"unsupported repeated string type");
return false;
}
// If cpp has made the accessors private, we can't make accessors on top.
if (internal::cpp::IsStringFieldWithPrivatizedAccessors(field)) {
return false;
}
return true;
}
namespace {
std::unique_ptr<AccessorGenerator> AccessorGeneratorFor(
Context& ctx, const FieldDescriptor& field) {
if (!IsSupportedField(ctx, field)) {
return std::make_unique<UnsupportedField>();
}
if (field.is_map()) {

@ -17,6 +17,11 @@ namespace protobuf {
namespace compiler {
namespace rust {
// Returns true if the field will have accessors generated for it. This will
// return true for nearly all fields; there are a few edge cases of string
// types that we don't generate accessors for.
bool IsSupportedField(Context& ctx, const FieldDescriptor& field);
// Generates the Rust accessors: expected to be called once each for each
// Message, MessageMut and MessageView's impl.
void GenerateAccessorMsgImpl(Context& ctx, const FieldDescriptor& field,

@ -124,13 +124,9 @@ class RepeatedField final : public AccessorGenerator {
class UnsupportedField final : public AccessorGenerator {
public:
explicit UnsupportedField(std::string reason) : reason_(std::move(reason)) {}
~UnsupportedField() override = default;
void InMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) const override;
private:
std::string reason_;
};
class Map final : public AccessorGenerator {

@ -18,10 +18,10 @@ namespace rust {
void UnsupportedField::InMsgImpl(Context& ctx, const FieldDescriptor& field,
AccessorCase accessor_case) const {
ctx.Emit({{"reason", reason_}}, R"rs(
// Unsupported! :( Reason: $reason$
ctx.Emit(R"rs(
// Unsupported field! :(
)rs");
ctx.printer().PrintRaw("\n");
}
} // namespace rust

@ -15,6 +15,7 @@
#include "absl/strings/string_view.h"
#include "google/protobuf/compiler/cpp/helpers.h"
#include "google/protobuf/compiler/rust/accessors/accessor_case.h"
#include "google/protobuf/compiler/rust/accessors/accessors.h"
#include "google/protobuf/compiler/rust/context.h"
#include "google/protobuf/compiler/rust/naming.h"
#include "google/protobuf/compiler/rust/rust_field_type.h"
@ -81,13 +82,28 @@ namespace rust {
// }
namespace {
// A user-friendly rust type for a view of this field with lifetime 'msg.
std::string RsTypeNameView(Context& ctx, const FieldDescriptor& field) {
bool IsSupportedOneofFieldCase(Context& ctx, const FieldDescriptor& field) {
if (!IsSupportedField(ctx, field)) {
return false;
}
// In addition to any fields that are otherwise unsupported, if the
// oneof contains a string or bytes field which is not string_view or string
// representation (namely, Cord or StringPiece), we don't support it
// currently.
if (ctx.is_cpp() && field.cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
field.cpp_string_type() != FieldDescriptor::CppStringType::kView &&
field.cpp_string_type() != FieldDescriptor::CppStringType::kString) {
return ""; // TODO: b/308792377 - ctype fields not supported yet.
field.cpp_string_type() != FieldDescriptor::CppStringType::kString &&
field.cpp_string_type() != FieldDescriptor::CppStringType::kView) {
return false;
}
return true;
}
// A user-friendly rust type for a view of this field with lifetime 'msg.
std::string RsTypeNameView(Context& ctx, const FieldDescriptor& field) {
ABSL_CHECK(IsSupportedOneofFieldCase(ctx, field));
switch (GetRustFieldType(field.type())) {
case RustFieldType::INT32:
case RustFieldType::INT64:
@ -121,10 +137,10 @@ void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof) {
[&] {
for (int i = 0; i < oneof.field_count(); ++i) {
auto& field = *oneof.field(i);
std::string rs_type = RsTypeNameView(ctx, field);
if (rs_type.empty()) {
if (!IsSupportedOneofFieldCase(ctx, field)) {
continue;
}
std::string rs_type = RsTypeNameView(ctx, field);
ctx.Emit({{"name", OneofCaseRsName(field)},
{"type", rs_type},
{"number", std::to_string(field.number())}},
@ -159,6 +175,9 @@ void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof) {
[&] {
for (int i = 0; i < oneof.field_count(); ++i) {
auto& field = *oneof.field(i);
if (!IsSupportedOneofFieldCase(ctx, field)) {
continue;
}
ctx.Emit({{"name", OneofCaseRsName(field)},
{"number", std::to_string(field.number())}},
R"rs($name$ = $number$,
@ -169,6 +188,9 @@ void GenerateOneofDefinition(Context& ctx, const OneofDescriptor& oneof) {
[&] {
for (int i = 0; i < oneof.field_count(); ++i) {
auto& field = *oneof.field(i);
if (!IsSupportedOneofFieldCase(ctx, field)) {
continue;
}
ctx.Emit({{"name", OneofCaseRsName(field)},
{"number", std::to_string(field.number())}},
R"rs($number$ => Some($case_enum_name$::$name$),
@ -217,10 +239,10 @@ void GenerateOneofAccessors(Context& ctx, const OneofDescriptor& oneof,
[&] {
for (int i = 0; i < oneof.field_count(); ++i) {
auto& field = *oneof.field(i);
std::string rs_type = RsTypeNameView(ctx, field);
if (rs_type.empty()) {
if (!IsSupportedOneofFieldCase(ctx, field)) {
continue;
}
std::string rs_type = RsTypeNameView(ctx, field);
std::string field_name = FieldNameWithCollisionAvoidance(field);
ctx.Emit(
{

@ -3960,16 +3960,15 @@ bool FieldDescriptor::has_optional_keyword() const {
FieldDescriptor::CppStringType FieldDescriptor::cpp_string_type() const {
ABSL_DCHECK(cpp_type() == FieldDescriptor::CPPTYPE_STRING);
if (internal::cpp::IsStringFieldWithPrivatizedAccessors(*this)) {
return CppStringType::kString;
}
switch (features().GetExtension(pb::cpp).string_type()) {
case pb::CppFeatures::VIEW:
return CppStringType::kView;
case pb::CppFeatures::CORD:
// In open-source, protobuf CORD is only supported for singular bytes
// fields.
if (type() != FieldDescriptor::TYPE_BYTES || is_repeated() ||
is_extension()) {
return CppStringType::kString;
}
return CppStringType::kCord;
case pb::CppFeatures::STRING:
return CppStringType::kString;
@ -9871,6 +9870,21 @@ bool IsLazilyInitializedFile(absl::string_view filename) {
filename == "google/protobuf/descriptor.proto";
}
bool IsStringFieldWithPrivatizedAccessors(const FieldDescriptor& field) {
// In open-source, protobuf CORD is only supported for singular bytes
// fields.
if (field.cpp_type() == FieldDescriptor::CPPTYPE_STRING &&
InternalFeatureHelper::GetFeatures(field)
.GetExtension(pb::cpp)
.string_type() == pb::CppFeatures::CORD &&
(field.type() != FieldDescriptor::TYPE_BYTES || field.is_repeated() ||
field.is_extension())) {
return true;
}
return false;
}
} // namespace cpp
} // namespace internal

@ -3035,6 +3035,14 @@ auto VisitDescriptorsInFileOrder(const FileDescriptor* file,
}
#endif // !SWIG
// Whether the given string field should have the accessors be privatized due
// to it being an unsupported type. If this returns true, cpp_string_type()
// returns kString for the storage, the C++ Generator will not generate
// public accessors for the type, but the field will sill be accessible via
// reflection.
PROTOBUF_EXPORT bool IsStringFieldWithPrivatizedAccessors(
const FieldDescriptor& field);
} // namespace cpp
} // namespace internal

Loading…
Cancel
Save