diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index 53a5885c3b..dc81d0806e 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -13715,6 +13715,40 @@ bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { UPB_DESC(FeatureSet_VERIFY); } +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f) { + // Groups are always tag-delimited. + if (UPB_DESC(FeatureSet_message_encoding)(upb_FieldDef_ResolvedFeatures(f)) != + UPB_DESC(FeatureSet_DELIMITED)) { + return false; + } + + const upb_MessageDef* msg = upb_FieldDef_MessageSubDef(f); + + // Group fields always are always the lowercase type name. + const char* mname = upb_MessageDef_Name(msg); + const char* fname = upb_FieldDef_Name(f); + size_t name_size = strlen(fname); + if (name_size != strlen(mname)) return false; + for (size_t i = 0; i < name_size; ++i) { + if ((mname[i] | 0x20) != fname[i]) { + // Case-insensitive ascii comparison. + return false; + } + } + + if (upb_MessageDef_File(msg) != upb_FieldDef_File(f)) { + return false; + } + + // Group messages are always defined in the same scope as the field. File + // level extensions will compare NULL == NULL here, which is why the file + // comparison above is necessary to ensure both come from the same file. + return upb_FieldDef_IsExtension(f) ? upb_FieldDef_ExtensionScope(f) == + upb_MessageDef_ContainingType(msg) + : upb_FieldDef_ContainingType(f) == + upb_MessageDef_ContainingType(msg); +} + uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index 16e3493544..fbc66b54e7 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -11484,6 +11484,7 @@ UPB_API upb_Label upb_FieldDef_Label(const upb_FieldDef* f); uint32_t upb_FieldDef_LayoutIndex(const upb_FieldDef* f); UPB_API const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f); +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f); // Creates a mini descriptor string for a field, returns true on success. bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 626078c84d..e139232af6 100644 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -13208,6 +13208,40 @@ bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { UPB_DESC(FeatureSet_VERIFY); } +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f) { + // Groups are always tag-delimited. + if (UPB_DESC(FeatureSet_message_encoding)(upb_FieldDef_ResolvedFeatures(f)) != + UPB_DESC(FeatureSet_DELIMITED)) { + return false; + } + + const upb_MessageDef* msg = upb_FieldDef_MessageSubDef(f); + + // Group fields always are always the lowercase type name. + const char* mname = upb_MessageDef_Name(msg); + const char* fname = upb_FieldDef_Name(f); + size_t name_size = strlen(fname); + if (name_size != strlen(mname)) return false; + for (size_t i = 0; i < name_size; ++i) { + if ((mname[i] | 0x20) != fname[i]) { + // Case-insensitive ascii comparison. + return false; + } + } + + if (upb_MessageDef_File(msg) != upb_FieldDef_File(f)) { + return false; + } + + // Group messages are always defined in the same scope as the field. File + // level extensions will compare NULL == NULL here, which is why the file + // comparison above is necessary to ensure both come from the same file. + return upb_FieldDef_IsExtension(f) ? upb_FieldDef_ExtensionScope(f) == + upb_MessageDef_ContainingType(msg) + : upb_FieldDef_ContainingType(f) == + upb_MessageDef_ContainingType(msg); +} + uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index 7a84ef1ba6..d2cf56e965 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -11886,6 +11886,7 @@ UPB_API upb_Label upb_FieldDef_Label(const upb_FieldDef* f); uint32_t upb_FieldDef_LayoutIndex(const upb_FieldDef* f); UPB_API const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f); bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f); +bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f); // Creates a mini descriptor string for a field, returns true on success. bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a,