Skip to content

Commit 40b5bda

Browse files
authored
Merge pull request #17789 from protocolbuffers/cp-string-type
Introduce FieldDescriptor::cpp_string_type() API to replace direct ct…
2 parents 2d5c729 + 72b0b7a commit 40b5bda

File tree

4 files changed

+115
-8
lines changed

4 files changed

+115
-8
lines changed

src/google/protobuf/descriptor.cc

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3941,6 +3941,29 @@ bool FieldDescriptor::has_optional_keyword() const {
39413941
is_optional() && !containing_oneof());
39423942
}
39433943

3944+
FieldDescriptor::CppStringType FieldDescriptor::cpp_string_type() const {
3945+
ABSL_DCHECK(cpp_type() == FieldDescriptor::CPPTYPE_STRING);
3946+
switch (features().GetExtension(pb::cpp).string_type()) {
3947+
case pb::CppFeatures::VIEW:
3948+
return CppStringType::kView;
3949+
case pb::CppFeatures::CORD:
3950+
// In open-source, protobuf CORD is only supported for singular bytes
3951+
// fields.
3952+
if (type() != FieldDescriptor::TYPE_BYTES || is_repeated() ||
3953+
is_extension()) {
3954+
return CppStringType::kString;
3955+
}
3956+
return CppStringType::kCord;
3957+
case pb::CppFeatures::STRING:
3958+
return CppStringType::kString;
3959+
default:
3960+
// If features haven't been resolved, this is a dynamic build not for C++
3961+
// codegen. Just use string type.
3962+
ABSL_DCHECK(!features().GetExtension(pb::cpp).has_string_type());
3963+
return CppStringType::kString;
3964+
}
3965+
}
3966+
39443967
// Location methods ===============================================
39453968

39463969
bool FileDescriptor::GetSourceLocation(const std::vector<int>& path,

src/google/protobuf/descriptor.h

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,10 @@ class PROTOBUF_EXPORT FieldDescriptor : private internal::SymbolBase,
859859
const char* cpp_type_name() const; // Name of the C++ type.
860860
Label label() const; // optional/required/repeated
861861

862+
#ifndef SWIG
863+
CppStringType cpp_string_type() const; // The C++ string type of this field.
864+
#endif
865+
862866
bool is_required() const; // shorthand for label() == LABEL_REQUIRED
863867
bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL
864868
bool is_repeated() const; // shorthand for label() == LABEL_REPEATED
@@ -2892,22 +2896,21 @@ PROTOBUF_EXPORT bool HasPreservingUnknownEnumSemantics(
28922896

28932897
PROTOBUF_EXPORT bool HasHasbit(const FieldDescriptor* field);
28942898

2899+
#ifndef SWIG
28952900
// For a string field, returns the effective ctype. If the actual ctype is
28962901
// not supported, returns the default of STRING.
28972902
template <typename FieldDesc = FieldDescriptor,
28982903
typename FieldOpts = FieldOptions>
28992904
typename FieldOpts::CType EffectiveStringCType(const FieldDesc* field) {
2900-
ABSL_DCHECK(field->cpp_type() == FieldDescriptor::CPPTYPE_STRING);
2901-
// Open-source protobuf release only supports STRING ctype and CORD for
2902-
// sinuglar bytes.
2903-
if (field->type() == FieldDescriptor::TYPE_BYTES && !field->is_repeated() &&
2904-
field->options().ctype() == FieldOpts::CORD && !field->is_extension()) {
2905-
return FieldOpts::CORD;
2905+
// TODO Replace this function with FieldDescriptor::string_type;
2906+
switch (field->cpp_string_type()) {
2907+
case FieldDescriptor::CppStringType::kCord:
2908+
return FieldOpts::CORD;
2909+
default:
2910+
return FieldOpts::STRING;
29062911
}
2907-
return FieldOpts::STRING;
29082912
}
29092913

2910-
#ifndef SWIG
29112914
enum class Utf8CheckMode : uint8_t {
29122915
kStrict = 0, // Parsing will fail if non UTF-8 data is in string fields.
29132916
kVerify = 1, // Only log an error but parsing will succeed.

src/google/protobuf/descriptor_lite.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ class FieldDescriptorLite {
7878
MAX_LABEL = 3, // Constant useful for defining lookup tables
7979
// indexed by Label.
8080
};
81+
82+
// Identifies the storage type of a C++ string field. This corresponds to
83+
// pb.CppFeatures.StringType, but is compatible with ctype prior to Edition
84+
// 2024. 0 is reserved for errors.
85+
#ifndef SWIG
86+
enum class CppStringType {
87+
kView = 1,
88+
kCord = 2,
89+
kString = 3,
90+
};
91+
#endif
8192
};
8293

8394
} // namespace internal

src/google/protobuf/descriptor_unittest.cc

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7593,6 +7593,9 @@ TEST_F(FeaturesTest, Proto2Features) {
75937593
EXPECT_TRUE(message->FindFieldByName("req")->is_required());
75947594
EXPECT_TRUE(file->enum_type(0)->is_closed());
75957595

7596+
EXPECT_EQ(message->FindFieldByName("str")->cpp_string_type(),
7597+
FieldDescriptor::CppStringType::kString);
7598+
75967599
// Check round-trip consistency.
75977600
FileDescriptorProto proto;
75987601
file->CopyTo(&proto);
@@ -9709,6 +9712,73 @@ TEST_F(FeaturesTest, EnumFeatureHelpers) {
97099712
EXPECT_FALSE(HasPreservingUnknownEnumSemantics(field_legacy_closed));
97109713
}
97119714

9715+
TEST_F(FeaturesTest, FieldCppStringType) {
9716+
BuildDescriptorMessagesInTestPool();
9717+
const std::string file_contents = absl::Substitute(
9718+
R"pb(
9719+
name: "foo.proto"
9720+
syntax: "editions"
9721+
edition: EDITION_2024
9722+
message_type {
9723+
name: "Foo"
9724+
field {
9725+
name: "view"
9726+
number: 1
9727+
label: LABEL_OPTIONAL
9728+
type: TYPE_STRING
9729+
}
9730+
field {
9731+
name: "str"
9732+
number: 2
9733+
label: LABEL_OPTIONAL
9734+
type: TYPE_STRING
9735+
options {
9736+
features {
9737+
[pb.cpp] { string_type: STRING }
9738+
}
9739+
}
9740+
}
9741+
field {
9742+
name: "cord"
9743+
number: 3
9744+
label: LABEL_OPTIONAL
9745+
type: TYPE_STRING
9746+
options {
9747+
features {
9748+
[pb.cpp] { string_type: CORD }
9749+
}
9750+
}
9751+
}
9752+
field {
9753+
name: "cord_bytes"
9754+
number: 4
9755+
label: LABEL_OPTIONAL
9756+
type: TYPE_BYTES
9757+
options {
9758+
features {
9759+
[pb.cpp] { string_type: CORD }
9760+
}
9761+
}
9762+
} $0
9763+
}
9764+
)pb",
9765+
""
9766+
);
9767+
const FileDescriptor* file = BuildFile(file_contents);
9768+
const Descriptor* message = file->message_type(0);
9769+
const FieldDescriptor* view = message->field(0);
9770+
const FieldDescriptor* str = message->field(1);
9771+
const FieldDescriptor* cord = message->field(2);
9772+
const FieldDescriptor* cord_bytes = message->field(3);
9773+
9774+
EXPECT_EQ(view->cpp_string_type(), FieldDescriptor::CppStringType::kView);
9775+
EXPECT_EQ(str->cpp_string_type(), FieldDescriptor::CppStringType::kString);
9776+
EXPECT_EQ(cord_bytes->cpp_string_type(),
9777+
FieldDescriptor::CppStringType::kCord);
9778+
EXPECT_EQ(cord->cpp_string_type(), FieldDescriptor::CppStringType::kString);
9779+
9780+
}
9781+
97129782
TEST_F(FeaturesTest, MergeFeatureValidationFailed) {
97139783
BuildDescriptorMessagesInTestPool();
97149784
BuildFileInTestPool(pb::TestFeatures::descriptor()->file());

0 commit comments

Comments
 (0)