Mini table accessors Part2 (repeated fields).
Introduces upb_FieldValue for array accessor api.

PiperOrigin-RevId: 445491436
diff --git a/BUILD b/BUILD
index 6b57070..97545bf 100644
--- a/BUILD
+++ b/BUILD
@@ -160,6 +160,7 @@
     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 @@
     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 d427b64..6c41f81 100644
--- a/upb/mini_table.h
+++ b/upb/mini_table.h
@@ -40,6 +40,11 @@
 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 86f2f42..8a1b891 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 @@
   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 d5279fe..dddaba6 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_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 c2f84f4..04ac5c3 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 @@
       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);
 }