diff --git a/BUILD b/BUILD index 6b57070b6d..97545bf591 100644 --- a/BUILD +++ b/BUILD @@ -160,6 +160,7 @@ cc_library( copts = UPB_DEFAULT_COPTS, visibility = ["//video/youtube/utils/elements/javascript/client/proto/upb/native:__pkg__"], deps = [ + ":collections", ":mini_table", ":mini_table_internal", ":port", @@ -184,6 +185,7 @@ cc_test( name = "mini_table_accessors_test", srcs = ["upb/mini_table_accessors_test.cc"], deps = [ + ":collections", ":mini_table", ":mini_table_accessors", ":mini_table_internal", diff --git a/upb/mini_table.h b/upb/mini_table.h index d427b64dfe..6c41f810eb 100644 --- a/upb/mini_table.h +++ b/upb/mini_table.h @@ -40,6 +40,11 @@ extern "C" { const upb_MiniTable_Field* upb_MiniTable_FindFieldByNumber( const upb_MiniTable* table, uint32_t number); +UPB_INLINE const upb_MiniTable* upb_MiniTable_GetSubMessageTable( + const upb_MiniTable* mini_table, const upb_MiniTable_Field* field) { + return mini_table->subs[field->submsg_index].submsg; +} + UPB_INLINE bool upb_MiniTable_Enum_CheckValue(const upb_MiniTable_Enum* e, int32_t val) { uint32_t uval = (uint32_t)val; diff --git a/upb/mini_table_accessors.c b/upb/mini_table_accessors.c index 86f2f42d5f..8a1b891325 100644 --- a/upb/mini_table_accessors.c +++ b/upb/mini_table_accessors.c @@ -28,7 +28,6 @@ #include "upb/mini_table_accessors.h" #include "upb/mini_table.h" -#include "upb/mini_table_accessors_internal.h" #include "upb/msg_internal.h" // Must be last. @@ -59,11 +58,6 @@ size_t upb_MiniTable_Field_GetSize(const upb_MiniTable_Field* f) { return upb_IsRepeatedOrMap(f) ? sizeof(void*) : sizes[f->descriptortype]; } -UPB_INLINE upb_Message* upb_MiniTable_GetMessage( - const upb_Message* msg, const upb_MiniTable_Field* field) { - return UPB_PTR_AT(msg, field->offset, upb_Message); -} - bool upb_MiniTable_HasField(const upb_Message* msg, const upb_MiniTable_Field* field) { if (_upb_MiniTable_Field_InOneOf(field)) { diff --git a/upb/mini_table_accessors.h b/upb/mini_table_accessors.h index d5279feee0..dddaba63ad 100644 --- a/upb/mini_table_accessors.h +++ b/upb/mini_table_accessors.h @@ -28,6 +28,7 @@ #ifndef UPB_MINI_TABLE_ACCESSORS_H_ #define UPB_MINI_TABLE_ACCESSORS_H_ +#include "upb/collections.h" #include "upb/mini_table_accessors_internal.h" #include "upb/msg_internal.h" @@ -38,36 +39,36 @@ extern "C" { #endif -bool upb_MiniTable_HasField(const upb_Message *msg, - const upb_MiniTable_Field *field); +bool upb_MiniTable_HasField(const upb_Message* msg, + const upb_MiniTable_Field* field); -void upb_MiniTable_ClearField(upb_Message *msg, - const upb_MiniTable_Field *field); +void upb_MiniTable_ClearField(upb_Message* msg, + const upb_MiniTable_Field* field); -UPB_INLINE bool upb_MiniTable_GetBool(const upb_Message *msg, - const upb_MiniTable_Field *field) { +UPB_INLINE bool upb_MiniTable_GetBool(const upb_Message* msg, + const upb_MiniTable_Field* field) { UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bool); return *UPB_PTR_AT(msg, field->offset, bool); } -UPB_INLINE void upb_MiniTable_SetBool(upb_Message *msg, - const upb_MiniTable_Field *field, +UPB_INLINE void upb_MiniTable_SetBool(upb_Message* msg, + const upb_MiniTable_Field* field, bool value) { UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bool); _upb_MiniTable_SetPresence(msg, field); *UPB_PTR_AT(msg, field->offset, bool) = value; } -UPB_INLINE int32_t upb_MiniTable_GetInt32(const upb_Message *msg, - const upb_MiniTable_Field *field) { +UPB_INLINE int32_t upb_MiniTable_GetInt32(const upb_Message* msg, + const upb_MiniTable_Field* field) { UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int32 || field->descriptortype == kUpb_FieldType_SInt32 || field->descriptortype == kUpb_FieldType_SFixed32); return *UPB_PTR_AT(msg, field->offset, int32_t); } -UPB_INLINE void upb_MiniTable_SetInt32(upb_Message *msg, - const upb_MiniTable_Field *field, +UPB_INLINE void upb_MiniTable_SetInt32(upb_Message* msg, + const upb_MiniTable_Field* field, int32_t value) { UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int32 || field->descriptortype == kUpb_FieldType_SInt32 || @@ -76,7 +77,151 @@ UPB_INLINE void upb_MiniTable_SetInt32(upb_Message *msg, *UPB_PTR_AT(msg, field->offset, int32_t) = value; } -// TODO(ferhat): Add accessors for all proto field types. +UPB_INLINE uint32_t upb_MiniTable_GetUInt32(const upb_Message* msg, + const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt32 || + field->descriptortype == kUpb_FieldType_Fixed32); + return *UPB_PTR_AT(msg, field->offset, uint32_t); +} + +UPB_INLINE void upb_MiniTable_SetUInt32(upb_Message* msg, + const upb_MiniTable_Field* field, + uint32_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt32 || + field->descriptortype == kUpb_FieldType_Fixed32); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, uint32_t) = value; +} + +UPB_INLINE int32_t upb_MiniTable_GetEnum(const upb_Message* msg, + const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); + return *UPB_PTR_AT(msg, field->offset, int32_t); +} + +UPB_INLINE void upb_MiniTable_SetEnum(upb_Message* msg, + const upb_MiniTable_Field* field, + int32_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Enum); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, int32_t) = value; +} + +UPB_INLINE int64_t upb_MiniTable_GetInt64(const upb_Message* msg, + const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 || + field->descriptortype == kUpb_FieldType_SInt64 || + field->descriptortype == kUpb_FieldType_SFixed64); + return *UPB_PTR_AT(msg, field->offset, int64_t); +} + +UPB_INLINE void upb_MiniTable_SetInt64(upb_Message* msg, + const upb_MiniTable_Field* field, + int64_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Int64 || + field->descriptortype == kUpb_FieldType_SInt64 || + field->descriptortype == kUpb_FieldType_SFixed64); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, int64_t) = value; +} + +UPB_INLINE uint64_t upb_MiniTable_GetUInt64(const upb_Message* msg, + const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 || + field->descriptortype == kUpb_FieldType_Fixed64); + return *UPB_PTR_AT(msg, field->offset, uint64_t); +} + +UPB_INLINE void upb_MiniTable_SetUInt64(upb_Message* msg, + const upb_MiniTable_Field* field, + uint64_t value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_UInt64 || + field->descriptortype == kUpb_FieldType_Fixed64); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, uint64_t) = value; +} + +UPB_INLINE float upb_MiniTable_GetFloat(const upb_Message* msg, + const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float); + return *UPB_PTR_AT(msg, field->offset, float); +} + +UPB_INLINE void upb_MiniTable_SetFloat(upb_Message* msg, + const upb_MiniTable_Field* field, + float value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Float); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, float) = value; +} + +UPB_INLINE double upb_MiniTable_GetDouble(const upb_Message* msg, + const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double); + return *UPB_PTR_AT(msg, field->offset, double); +} + +UPB_INLINE void upb_MiniTable_SetDouble(upb_Message* msg, + const upb_MiniTable_Field* field, + double value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Double); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, double) = value; +} + +UPB_INLINE upb_StringView upb_MiniTable_GetString( + const upb_Message* msg, const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes || + field->descriptortype == kUpb_FieldType_String); + return *UPB_PTR_AT(msg, field->offset, upb_StringView); +} + +UPB_INLINE void upb_MiniTable_SetString(upb_Message* msg, + const upb_MiniTable_Field* field, + upb_StringView value) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Bytes || + field->descriptortype == kUpb_FieldType_String); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, upb_StringView) = value; +} + +UPB_INLINE const upb_Message* upb_MiniTable_GetMessage( + const upb_Message* msg, const upb_MiniTable_Field* field) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message); + return *UPB_PTR_AT(msg, field->offset, const upb_Message*); +} + +UPB_INLINE void upb_MiniTable_SetMessage(upb_Message* msg, + const upb_MiniTable_Field* field, + upb_Message* sub_message) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message); + _upb_MiniTable_SetPresence(msg, field); + *UPB_PTR_AT(msg, field->offset, const upb_Message*) = sub_message; +} + +UPB_INLINE upb_Message* upb_MiniTable_GetMutableMessage( + upb_Message* msg, const upb_MiniTable* mini_table, + const upb_MiniTable_Field* field, upb_Arena* arena) { + UPB_ASSERT(field->descriptortype == kUpb_FieldType_Message); + upb_Message* sub_message = *UPB_PTR_AT(msg, field->offset, upb_Message*); + if (!sub_message) { + sub_message = + _upb_Message_New(mini_table->subs[field->submsg_index].submsg, arena); + } + return sub_message; +} + +UPB_INLINE const upb_Array* upb_MiniTable_GetArray( + const upb_Message* msg, const upb_MiniTable_Field* field) { + return (const upb_Array*)*UPB_PTR_AT(msg, field->offset, upb_Array*); +} + +UPB_INLINE upb_Array* upb_MiniTable_GetMutableArray( + upb_Message* msg, const upb_MiniTable_Field* field) { + return (upb_Array*)*UPB_PTR_AT(msg, field->offset, upb_Array*); +} + +// TODO(ferhat): Add support for extensions. #ifdef __cplusplus } /* extern "C" */ diff --git a/upb/mini_table_accessors_test.cc b/upb/mini_table_accessors_test.cc index c2f84f4f56..04ac5c34b2 100644 --- a/upb/mini_table_accessors_test.cc +++ b/upb/mini_table_accessors_test.cc @@ -36,20 +36,35 @@ #include "gtest/gtest.h" #include "src/google/protobuf/test_messages_proto2.upb.h" #include "src/google/protobuf/test_messages_proto3.upb.h" +#include "upb/collections.h" #include "upb/mini_table.h" namespace { -// Proto Field numbers used for reflective access. +// Proto2 test messages field numbers used for reflective access. const uint32_t kFieldOptionalInt32 = 1; +const uint32_t kFieldOptionalUInt32 = 3; const uint32_t kFieldOptionalBool = 13; const uint32_t kFieldOptionalString = 14; const uint32_t kFieldOptionalNestedMessage = 18; +const uint32_t kFieldOptionalRepeatedInt32 = 31; +const uint32_t kFieldOptionalNestedMessageA = 1; const uint32_t kFieldOptionalOneOfUInt32 = 111; const uint32_t kFieldOptionalOneOfString = 113; -const char kTestStr1[] = "Hello"; +const uint32_t kFieldProto3OptionalInt64 = 2; +const uint32_t kFieldProto3OptionalUInt64 = 4; + +const char kTestStr1[] = "Hello1"; +const char kTestStr2[] = "Hello2"; const int32_t kTestInt32 = 567; +const int32_t kTestUInt32 = 0xF1234567; +const uint64_t kTestUInt64 = 0xFEDCBAFF87654321; + +const upb_MiniTable_Field* find_proto3_field(int field_number) { + return upb_MiniTable_FindFieldByNumber( + &protobuf_test_messages_proto3_TestAllTypesProto3_msginit, field_number); +} const upb_MiniTable_Field* find_proto2_field(int field_number) { return upb_MiniTable_FindFieldByNumber( @@ -148,6 +163,196 @@ TEST(GeneratedCode, ScalarsProto2) { kTestInt32, protobuf_test_messages_proto2_TestAllTypesProto2_optional_int32(msg)); + const upb_MiniTable_Field* optional_uint32_field = + find_proto2_field(kFieldOptionalUInt32); + + EXPECT_EQ( + 0, protobuf_test_messages_proto2_TestAllTypesProto2_optional_uint32(msg)); + EXPECT_EQ(0, upb_MiniTable_GetUInt32(msg, optional_uint32_field)); + upb_MiniTable_SetUInt32(msg, optional_uint32_field, kTestUInt32); + EXPECT_EQ(kTestUInt32, upb_MiniTable_GetUInt32(msg, optional_uint32_field)); + EXPECT_EQ( + kTestUInt32, + protobuf_test_messages_proto2_TestAllTypesProto2_optional_uint32(msg)); + + upb_Arena_Free(arena); +} + +TEST(GeneratedCode, ScalarProto3) { + upb_Arena* arena = upb_Arena_New(); + protobuf_test_messages_proto3_TestAllTypesProto3* msg = + protobuf_test_messages_proto3_TestAllTypesProto3_new(arena); + + const upb_MiniTable_Field* optional_int64_field = + find_proto3_field(kFieldProto3OptionalInt64); + const upb_MiniTable_Field* optional_uint64_field = + find_proto3_field(kFieldProto3OptionalUInt64); + + EXPECT_EQ( + 0, protobuf_test_messages_proto3_TestAllTypesProto3_optional_int64(msg)); + upb_MiniTable_SetInt64(msg, optional_int64_field, -1); + EXPECT_EQ( + -1, protobuf_test_messages_proto3_TestAllTypesProto3_optional_int64(msg)); + EXPECT_EQ(-1, upb_MiniTable_GetInt64(msg, optional_int64_field)); + + EXPECT_EQ( + 0, protobuf_test_messages_proto3_TestAllTypesProto3_optional_uint64(msg)); + upb_MiniTable_SetUInt64(msg, optional_uint64_field, kTestUInt64); + EXPECT_EQ( + kTestUInt64, + protobuf_test_messages_proto3_TestAllTypesProto3_optional_uint64(msg)); + EXPECT_EQ(kTestUInt64, upb_MiniTable_GetUInt64(msg, optional_uint64_field)); + + upb_Arena_Free(arena); +} + +TEST(GeneratedCode, Strings) { + upb_Arena* arena = upb_Arena_New(); + protobuf_test_messages_proto2_TestAllTypesProto2* msg = + protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); + + const upb_MiniTable_Field* optional_string_field = + find_proto2_field(kFieldOptionalString); + + // Test default. + EXPECT_EQ(false, upb_MiniTable_HasField(msg, optional_string_field)); + // Test read after write using C. + protobuf_test_messages_proto2_TestAllTypesProto2_set_optional_string( + msg, upb_StringView_FromString(kTestStr1)); + EXPECT_EQ(true, upb_MiniTable_HasField(msg, optional_string_field)); + upb_StringView value = upb_MiniTable_GetString(msg, optional_string_field); + std::string read_value = std::string(value.data, value.size); + EXPECT_EQ(kTestStr1, read_value); + // Clear. + upb_MiniTable_ClearField(msg, optional_string_field); + EXPECT_EQ(false, upb_MiniTable_HasField(msg, optional_string_field)); + EXPECT_EQ( + false, + protobuf_test_messages_proto2_TestAllTypesProto2_has_optional_string( + msg)); + upb_MiniTable_SetString(msg, optional_string_field, + upb_StringView_FromString(kTestStr2)); + EXPECT_EQ(true, upb_MiniTable_HasField(msg, optional_string_field)); + EXPECT_EQ( + true, + protobuf_test_messages_proto2_TestAllTypesProto2_has_optional_string( + msg)); + value = protobuf_test_messages_proto2_TestAllTypesProto2_optional_string(msg); + read_value = std::string(value.data, value.size); + EXPECT_EQ(kTestStr2, read_value); + + upb_Arena_Free(arena); +} + +TEST(GeneratedCode, SubMessage) { + upb_Arena* arena = upb_Arena_New(); + protobuf_test_messages_proto2_TestAllTypesProto2* msg = + protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); + + const upb_MiniTable_Field* optional_message_field = + find_proto2_field(kFieldOptionalNestedMessage); + + const upb_Message* test_message = + upb_MiniTable_GetMessage(msg, optional_message_field); + EXPECT_EQ(NULL, test_message); + + EXPECT_EQ(false, upb_MiniTable_HasField(msg, optional_message_field)); + + // Get mutable using C API. + protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage* nested_message = + protobuf_test_messages_proto2_TestAllTypesProto2_mutable_optional_nested_message( + msg, arena); + EXPECT_EQ(true, nested_message != nullptr); + EXPECT_EQ(true, upb_MiniTable_HasField(msg, optional_message_field)); + protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_set_a( + nested_message, 5); + + // Read back using mini table API. + const upb_Message* sub_message = + upb_MiniTable_GetMessage(msg, optional_message_field); + EXPECT_EQ(true, sub_message != NULL); + + const upb_MiniTable_Field* nested_message_a_field = + upb_MiniTable_FindFieldByNumber( + &protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_msginit, + kFieldOptionalNestedMessageA); + EXPECT_EQ(5, upb_MiniTable_GetInt32(sub_message, nested_message_a_field)); + + upb_MiniTable_ClearField(msg, optional_message_field); + EXPECT_EQ( + NULL, + protobuf_test_messages_proto2_TestAllTypesProto2_optional_nested_message( + msg)); + EXPECT_EQ(false, upb_MiniTable_HasField(msg, optional_message_field)); + + upb_Message* new_nested_message = + protobuf_test_messages_proto2_TestAllTypesProto2_NestedMessage_new(arena); + upb_MiniTable_SetInt32(new_nested_message, nested_message_a_field, 123); + upb_MiniTable_SetMessage(msg, optional_message_field, new_nested_message); + + upb_Message* mutable_message = upb_MiniTable_GetMutableMessage( + msg, &protobuf_test_messages_proto2_TestAllTypesProto2_msginit, + optional_message_field, arena); + EXPECT_EQ( + true, + protobuf_test_messages_proto2_TestAllTypesProto2_optional_nested_message( + msg) != NULL); + EXPECT_EQ(true, upb_MiniTable_HasField(msg, optional_message_field)); + EXPECT_EQ(123, + upb_MiniTable_GetInt32(mutable_message, nested_message_a_field)); + + upb_Arena_Free(arena); +} + +TEST(GeneratedCode, RepeatedScalar) { + upb_Arena* arena = upb_Arena_New(); + protobuf_test_messages_proto2_TestAllTypesProto2* msg = + protobuf_test_messages_proto2_TestAllTypesProto2_new(arena); + + const upb_MiniTable_Field* repeated_int32_field = + find_proto2_field(kFieldOptionalRepeatedInt32); + + size_t len; + const int32_t* arr = + protobuf_test_messages_proto2_TestAllTypesProto2_repeated_int32(msg, + &len); + // Test Get/Set Array values, validate with C API. + EXPECT_EQ(0, len); + EXPECT_EQ(NULL, arr); + EXPECT_EQ(NULL, upb_MiniTable_GetArray(msg, repeated_int32_field)); + protobuf_test_messages_proto2_TestAllTypesProto2_resize_repeated_int32( + msg, 10, arena); + int32_t* mutable_values = + protobuf_test_messages_proto2_TestAllTypesProto2_mutable_repeated_int32( + msg, &len); + mutable_values[5] = 123; + const upb_Array* readonly_arr = + upb_MiniTable_GetArray(msg, repeated_int32_field); + EXPECT_EQ(123, upb_Array_Get(readonly_arr, 5).int32_val); + + upb_MessageValue new_value; + new_value.int32_val = 567; + upb_Array* mutable_array = + upb_MiniTable_GetMutableArray(msg, repeated_int32_field); + upb_Array_Set(mutable_array, 5, new_value); + EXPECT_EQ(new_value.int32_val, + protobuf_test_messages_proto2_TestAllTypesProto2_repeated_int32( + msg, &len)[5]); + + // Test resize. + bool result = upb_Array_Resize(mutable_array, 20, arena); + EXPECT_EQ(true, result); + upb_Array_Set(mutable_array, 19, new_value); + EXPECT_EQ(new_value.int32_val, + protobuf_test_messages_proto2_TestAllTypesProto2_repeated_int32( + msg, &len)[19]); + upb_Array_Resize(mutable_array, 0, arena); + const int32_t* zero_length_array = + protobuf_test_messages_proto2_TestAllTypesProto2_repeated_int32(msg, + &len); + EXPECT_EQ(0, len); + EXPECT_EQ(true, zero_length_array != NULL); + upb_Arena_Free(arena); }