From 7a09c4569bec008504bca3eb0201f0e75863a1fc Mon Sep 17 00:00:00 2001 From: Hong Shin Date: Wed, 1 May 2024 11:30:23 -0700 Subject: [PATCH] Add upb_Message_ClearOneof upb users currently need to manually fetch a oneof field in order to clear it. In this CL, we add a convenience method to do that in one fell swoop. PiperOrigin-RevId: 629782904 --- upb/message/accessors.h | 8 +++----- upb/message/accessors_test.cc | 23 +++++++++++++++++++++++ upb/message/internal/accessors.h | 21 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/upb/message/accessors.h b/upb/message/accessors.h index f812e2da47..723d10d871 100644 --- a/upb/message/accessors.h +++ b/upb/message/accessors.h @@ -68,11 +68,9 @@ UPB_API_INLINE bool upb_Message_SetExtension(upb_Message* msg, const upb_MiniTableExtension* e, const void* val, upb_Arena* a); -UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( - const upb_Message* message, const upb_MiniTableField* oneof_field) { - UPB_ASSUME(upb_MiniTableField_IsInOneof(oneof_field)); - return UPB_PRIVATE(_upb_Message_GetOneofCase)(message, oneof_field); -} +UPB_API_INLINE void upb_Message_ClearOneof(upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField* f); // NOTE: The default_val is only used for fields that support presence. // For repeated/map fields, the resulting upb_Array*/upb_Map* can be NULL if a diff --git a/upb/message/accessors_test.cc b/upb/message/accessors_test.cc index 5b0dd3638c..524e5fb655 100644 --- a/upb/message/accessors_test.cc +++ b/upb/message/accessors_test.cc @@ -477,5 +477,28 @@ TEST(GeneratedCode, EnumClosedCheck) { EXPECT_TRUE(upb_MiniTableField_IsClosedEnum(closedEnumField)); upb_Arena_Free(arena); } +TEST(GeneratedCode, OneofClear) { + upb_Arena* arena = upb_Arena_New(); + + protobuf_test_messages_proto2_TestAllTypesProto2* msg = + protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); + + const upb_MiniTable* table = + &protobuf_0test_0messages__proto2__TestAllTypesProto2_msg_init; + + // oneof_uint32 + const upb_MiniTableField* oneofField = + upb_MiniTable_FindFieldByNumber(table, 111); + EXPECT_TRUE(upb_MiniTableField_IsInOneof(oneofField)); + protobuf_test_messages_proto2_TestAllTypesProto2_set_oneof_uint32(msg, 522); + EXPECT_TRUE( + protobuf_test_messages_proto2_TestAllTypesProto2_has_oneof_uint32(msg)); + + upb_Message_ClearOneof((upb_Message*)msg, table, oneofField); + EXPECT_FALSE( + protobuf_test_messages_proto2_TestAllTypesProto2_has_oneof_uint32(msg)); + + upb_Arena_Free(arena); +} } // namespace diff --git a/upb/message/internal/accessors.h b/upb/message/internal/accessors.h index bfae12e601..1c5a397487 100644 --- a/upb/message/internal/accessors.h +++ b/upb/message/internal/accessors.h @@ -335,6 +335,27 @@ UPB_API_INLINE void upb_Message_ClearExtension( } } +UPB_API_INLINE uint32_t upb_Message_WhichOneofFieldNumber( + const struct upb_Message* message, const upb_MiniTableField* oneof_field) { + UPB_ASSUME(upb_MiniTableField_IsInOneof(oneof_field)); + return UPB_PRIVATE(_upb_Message_GetOneofCase)(message, oneof_field); +} + +UPB_API_INLINE void upb_Message_ClearOneof(struct upb_Message* msg, + const upb_MiniTable* m, + const upb_MiniTableField* f) { + UPB_ASSERT(!upb_Message_IsFrozen(msg)); + uint32_t field_number = upb_Message_WhichOneofFieldNumber(msg, f); + if (field_number == 0) { + // No field in the oneof is set. + return; + } + + const upb_MiniTableField* field = + upb_MiniTable_FindFieldByNumber(m, field_number); + upb_Message_ClearBaseField(msg, field); +} + UPB_INLINE void _upb_Message_AssertMapIsUntagged( const struct upb_Message* msg, const upb_MiniTableField* field) { UPB_UNUSED(msg);