This is an automated email from the ASF dual-hosted git repository.

pitrou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new a1d23e58810 GH-50936: [C++][Integration] Replace RapidJSON with 
simdjson (#50937)
a1d23e58810 is described below

commit a1d23e588103ecd3a5c4d9cc301c560ea332ef90
Author: Aaditya Srinivasan <[email protected]>
AuthorDate: Thu Aug 27 17:03:16 2026 +0530

    GH-50936: [C++][Integration] Replace RapidJSON with simdjson (#50937)
    
    ### Rationale for this change
    
    This PR continues the simdjson migration by replacing the RapidJSON usage 
in the C++ JSON integration implementation with **simdjson's DOM API** and 
Arrow's existing `JsonWriter`.
    
    ### Changes
    
    - Replace RapidJSON DOM parsing with simdjson's DOM API.
    - Update the integration JSON reader and internal parsing helpers to use 
`simdjson::dom` types.
    - Replace RapidJSON JSON serialization with Arrow's existing `JsonWriter`.
    - Handle optional JSON array members without creating an invalid simdjson 
array.
    - Remove the unused RapidJSON dependencies from the CMake and Meson 
integration test targets.
    - Update remaining RapidJSON-specific implementation references.
    
    Fixes: #50936
    * GitHub Issue: #50936
    
    Authored-by: Aaditya Srinivasan <[email protected]>
    Signed-off-by: Antoine Pitrou <[email protected]>
---
 cpp/src/arrow/integration/CMakeLists.txt           |   6 +-
 cpp/src/arrow/integration/json_integration.cc      |  39 +-
 cpp/src/arrow/integration/json_integration.h       |   4 +-
 cpp/src/arrow/integration/json_integration_test.cc |  30 +-
 cpp/src/arrow/integration/json_internal.cc         | 518 ++++++++++++---------
 cpp/src/arrow/integration/json_internal.h          |  56 +--
 cpp/src/arrow/integration/meson.build              |   7 +-
 7 files changed, 334 insertions(+), 326 deletions(-)

diff --git a/cpp/src/arrow/integration/CMakeLists.txt 
b/cpp/src/arrow/integration/CMakeLists.txt
index 8374d6de10e..dfbf8f8309f 100644
--- a/cpp/src/arrow/integration/CMakeLists.txt
+++ b/cpp/src/arrow/integration/CMakeLists.txt
@@ -21,16 +21,12 @@ arrow_install_all_headers("arrow/integration")
 # - an executable that can be called to answer integration test requests
 # - a self-(unit)test for the C++ side of integration testing
 if(ARROW_BUILD_TESTS)
-  add_arrow_test(json_integration_test
-                 EXTRA_LINK_LIBS
-                 RapidJSON
-                 simdjson::simdjson
+  add_arrow_test(json_integration_test EXTRA_LINK_LIBS simdjson::simdjson
                  ${GFLAGS_LIBRARIES})
   add_dependencies(arrow-integration arrow-json-integration-test)
 elseif(ARROW_BUILD_INTEGRATION)
   add_executable(arrow-json-integration-test json_integration_test.cc)
   target_link_libraries(arrow-json-integration-test
-                        RapidJSON
                         simdjson::simdjson
                         ${ARROW_TEST_LINK_LIBS}
                         ${GFLAGS_LIBRARIES}
diff --git a/cpp/src/arrow/integration/json_integration.cc 
b/cpp/src/arrow/integration/json_integration.cc
index f4c33336648..f978e1da541 100644
--- a/cpp/src/arrow/integration/json_integration.cc
+++ b/cpp/src/arrow/integration/json_integration.cc
@@ -21,7 +21,9 @@
 #include <cstdint>
 #include <memory>
 #include <string>
+#include <string_view>
 #include <utility>
+#include <vector>
 
 #include "arrow/buffer.h"
 #include "arrow/integration/json_internal.h"
@@ -33,6 +35,7 @@
 #include "arrow/status.h"
 #include "arrow/type.h"
 #include "arrow/util/logging_internal.h"
+#include "arrow/util/simdjson_internal.h"
 
 using arrow::ipc::DictionaryFieldMapper;
 using arrow::ipc::DictionaryMemo;
@@ -125,44 +128,46 @@ Status IntegrationJsonWriter::WriteRecordBatch(const 
RecordBatch& batch) {
 class IntegrationJsonReader::Impl {
  public:
   Impl(MemoryPool* pool, const std::shared_ptr<Buffer>& data)
-      : pool_(pool), data_(data), record_batches_(nullptr) {}
+      : pool_(pool), data_(data) {}
 
   Status ParseAndReadSchema() {
-    doc_.Parse(reinterpret_cast<const rj::Document::Ch*>(data_->data()),
-               static_cast<size_t>(data_->size()));
-    if (doc_.HasParseError()) {
-      return Status::IOError("JSON parsing failed");
-    }
+    ARROW_ASSIGN_OR_RAISE(doc_,
+                          internal::ResolveSimdjsonResult(
+                              parser_.parse(reinterpret_cast<const 
char*>(data_->data()),
+                                            
static_cast<size_t>(data_->size())),
+                              "Failed to parse JSON"));
 
     ARROW_ASSIGN_OR_RAISE(schema_, json::ReadSchema(doc_, pool_, 
&dictionary_memo_));
 
-    auto it = std::as_const(doc_).FindMember("batches");
-    RETURN_NOT_ARRAY("batches", it, doc_);
-    record_batches_ = &it->value;
+    ARROW_ASSIGN_OR_RAISE(auto batches,
+                          
internal::ResolveSimdjsonResult(doc_["batches"].get_array(),
+                                                          "Failed to get 
batches"));
+
+    batches.get_values(record_batches_);
 
     return Status::OK();
   }
 
   Result<std::shared_ptr<RecordBatch>> ReadRecordBatch(int i) {
-    if (i < 0 || i >= static_cast<int>(record_batches_->GetArray().Size())) {
+    if (i < 0 || i >= static_cast<int>(record_batches_.size())) {
       return Status::IndexError("record batch index ", i, " out of bounds");
     }
-    return json::ReadRecordBatch(record_batches_->GetArray()[i], schema_,
-                                 &dictionary_memo_, pool_);
+
+    return json::ReadRecordBatch(record_batches_[i], schema_, 
&dictionary_memo_, pool_);
   }
 
   std::shared_ptr<Schema> schema() const { return schema_; }
 
-  int num_record_batches() const {
-    return static_cast<int>(record_batches_->GetArray().Size());
-  }
+  int num_record_batches() const { return 
static_cast<int>(record_batches_.size()); }
 
  private:
   MemoryPool* pool_;
   std::shared_ptr<Buffer> data_;
-  rj::Document doc_;
 
-  const rj::Value* record_batches_;
+  simdjson::dom::parser parser_;
+  JsonValue doc_;
+  std::vector<JsonValue> record_batches_;
+
   std::shared_ptr<Schema> schema_;
   DictionaryMemo dictionary_memo_;
 };
diff --git a/cpp/src/arrow/integration/json_integration.h 
b/cpp/src/arrow/integration/json_integration.h
index 13abfae095a..1097a941e2c 100644
--- a/cpp/src/arrow/integration/json_integration.h
+++ b/cpp/src/arrow/integration/json_integration.h
@@ -55,7 +55,7 @@ class ARROW_EXPORT IntegrationJsonWriter {
  private:
   explicit IntegrationJsonWriter(const std::shared_ptr<Schema>& schema);
 
-  // Hide RapidJSON details from public API
+  // Hide JSON implementation details from public API
   class Impl;
   std::unique_ptr<Impl> impl_;
 };
@@ -106,7 +106,7 @@ class ARROW_EXPORT IntegrationJsonReader {
  private:
   IntegrationJsonReader(MemoryPool* pool, std::shared_ptr<Buffer> data);
 
-  // Hide RapidJSON details from public API
+  // Hide JSON implementation details from public API
   class Impl;
   std::unique_ptr<Impl> impl_;
 };
diff --git a/cpp/src/arrow/integration/json_integration_test.cc 
b/cpp/src/arrow/integration/json_integration_test.cc
index 477ef932d24..700551c23b7 100644
--- a/cpp/src/arrow/integration/json_integration_test.cc
+++ b/cpp/src/arrow/integration/json_integration_test.cc
@@ -49,6 +49,7 @@
 #include "arrow/type.h"
 #include "arrow/type_fwd.h"
 #include "arrow/util/io_util.h"
+#include "arrow/util/simdjson_internal.h"
 
 DEFINE_string(arrow, "", "Arrow file name");
 DEFINE_string(json, "", "JSON file name");
@@ -734,10 +735,10 @@ void TestSchemaRoundTrip(const std::shared_ptr<Schema>& 
schema) {
 
   ASSERT_OK_AND_ASSIGN(std::string_view json_schema, writer.GetString());
 
-  rj::Document d;
-  // Pass explicit size to avoid ASAN issues with
-  // SIMD loads in RapidJson.
-  d.Parse(json_schema.data(), json_schema.size());
+  simdjson::dom::parser parser;
+  ASSERT_OK_AND_ASSIGN(auto d, internal::ResolveSimdjsonResult(
+                                   parser.parse(json_schema.data(), 
json_schema.size()),
+                                   "Failed to parse JSON"));
 
   DictionaryMemo in_memo;
   ASSERT_OK_AND_ASSIGN(auto result_schema,
@@ -754,14 +755,11 @@ void TestArrayRoundTrip(const Array& array) {
 
   ASSERT_OK_AND_ASSIGN(std::string_view array_as_json, writer.GetString());
 
-  rj::Document d;
-  // Pass explicit size to avoid ASAN issues with
-  // SIMD loads in RapidJson.
-  d.Parse(array_as_json.data(), array_as_json.size());
-  if (d.HasParseError()) {
-    FAIL() << "JSON parsing failed";
-  }
-
+  simdjson::dom::parser parser;
+  ASSERT_OK_AND_ASSIGN(auto d,
+                       internal::ResolveSimdjsonResult(
+                           parser.parse(array_as_json.data(), 
array_as_json.size()),
+                           "Failed to parse JSON"));
   ASSERT_OK_AND_ASSIGN(
       auto result_array,
       json::ReadArray(default_memory_pool(), d, ::arrow::field(name, 
array.type())));
@@ -1111,10 +1109,10 @@ TEST(TestJsonFileReadWrite, JsonExample6) {
 }
 
 static void AssertInvalidBinaryViewJson(const std::string& json_array) {
-  rj::Document d;
-  // Pass explicit size to avoid ASAN issues with SIMD loads in RapidJson.
-  d.Parse(json_array.data(), json_array.size());
-  ASSERT_FALSE(d.HasParseError());
+  simdjson::dom::parser parser;
+  ASSERT_OK_AND_ASSIGN(auto d, internal::ResolveSimdjsonResult(
+                                   parser.parse(json_array.data(), 
json_array.size()),
+                                   "Failed to parse JSON"));
 
   ASSERT_RAISES(Invalid,
                 json::ReadArray(default_memory_pool(), d, field("f", 
binary_view())));
diff --git a/cpp/src/arrow/integration/json_internal.cc 
b/cpp/src/arrow/integration/json_internal.cc
index d0baad67e1e..abf48b9df76 100644
--- a/cpp/src/arrow/integration/json_internal.cc
+++ b/cpp/src/arrow/integration/json_internal.cc
@@ -51,6 +51,7 @@
 #include "arrow/util/key_value_metadata.h"
 #include "arrow/util/logging_internal.h"
 #include "arrow/util/range.h"
+#include "arrow/util/simdjson_internal.h"
 #include "arrow/util/string.h"
 #include "arrow/util/value_parsing.h"
 #include "arrow/visit_array_inline.h"
@@ -111,11 +112,11 @@ std::string GetTimeUnitName(TimeUnit::type unit) {
   return "UNKNOWN";
 }
 
-Result<std::string_view> GetStringView(const rj::Value& str) {
-  if (!str.IsString()) {
-    return Status::Invalid("field was not a string");
-  }
-  return std::string_view{str.GetString(), str.GetStringLength()};
+Result<std::string_view> GetStringView(const JsonValue& value) {
+  ARROW_ASSIGN_OR_RAISE(
+      auto string_view,
+      internal::ResolveSimdjsonResult(value.get_string(), "field was not a 
string"));
+  return string_view;
 }
 
 class SchemaWriter {
@@ -880,48 +881,47 @@ Result<TimeUnit::type> GetUnitFromString(const 
std::string& unit_str) {
 }
 
 template <typename IntType = int>
-Result<IntType> GetMemberInt(const RjObject& obj, const std::string& key) {
-  const auto& it = obj.FindMember(key);
-  RETURN_NOT_INT(key, it, obj);
-  return static_cast<IntType>(it->value.GetInt64());
+Result<IntType> GetMemberInt(const JsonObject& obj, std::string_view key) {
+  ARROW_ASSIGN_OR_RAISE(
+      auto value, internal::ResolveSimdjsonResult(obj[key], "Failed to get 
JSON field"));
+  ARROW_ASSIGN_OR_RAISE(auto integer, internal::GetJsonInt(value, key, "an 
integer"));
+  return static_cast<IntType>(integer);
 }
 
-Result<bool> GetMemberBool(const RjObject& obj, const std::string& key) {
-  const auto& it = obj.FindMember(key);
-  RETURN_NOT_BOOL(key, it, obj);
-  return it->value.GetBool();
+Result<bool> GetMemberBool(const JsonObject& obj, std::string_view key) {
+  ARROW_ASSIGN_OR_RAISE(
+      auto value, internal::ResolveSimdjsonResult(obj[key], "Failed to get 
JSON field"));
+  return internal::ResolveSimdjsonResult(value.get_bool(), "field was not a 
boolean");
 }
 
-Result<std::string> GetMemberString(const RjObject& obj, const std::string& 
key) {
-  const auto& it = obj.FindMember(key);
-  RETURN_NOT_STRING(key, it, obj);
-  return it->value.GetString();
+Result<std::string> GetMemberString(const JsonObject& obj, std::string_view 
key) {
+  ARROW_ASSIGN_OR_RAISE(
+      auto value, internal::ResolveSimdjsonResult(obj[key], "Failed to get 
JSON field"));
+  ARROW_ASSIGN_OR_RAISE(
+      auto string_view,
+      internal::ResolveSimdjsonResult(value.get_string(), "field was not a 
string"));
+  return std::string(string_view);
 }
 
-Result<const RjObject> GetMemberObject(const RjObject& obj, const std::string& 
key) {
-  const auto& it = obj.FindMember(key);
-  RETURN_NOT_OBJECT(key, it, obj);
-  return it->value.GetObject();
+Result<JsonObject> GetMemberObject(const JsonObject& obj, std::string_view 
key) {
+  ARROW_ASSIGN_OR_RAISE(
+      auto value, internal::ResolveSimdjsonResult(obj[key], "Failed to get 
JSON field"));
+  return internal::ResolveSimdjsonResult(value.get_object(), "field was not an 
object");
 }
 
-Result<const RjArray> GetMemberArray(const RjObject& obj, const std::string& 
key,
-                                     bool allow_absent = false) {
-  static const auto empty_array = rj::Value(rj::kArrayType);
+Result<JsonArray> GetMemberArray(const JsonObject& obj, std::string_view key) {
+  ARROW_ASSIGN_OR_RAISE(
+      auto value, internal::ResolveSimdjsonResult(obj[key], "Failed to get 
JSON field"));
 
-  const auto& it = obj.FindMember(key);
-  if (allow_absent && it == obj.MemberEnd()) {
-    return empty_array.GetArray();
-  }
-  RETURN_NOT_ARRAY(key, it, obj);
-  return it->value.GetArray();
+  return internal::GetJsonArray(value, key);
 }
 
-Result<TimeUnit::type> GetMemberTimeUnit(const RjObject& obj, const 
std::string& key) {
+Result<TimeUnit::type> GetMemberTimeUnit(const JsonObject& obj, 
std::string_view key) {
   ARROW_ASSIGN_OR_RAISE(const auto unit_str, GetMemberString(obj, key));
   return GetUnitFromString(unit_str);
 }
 
-Result<std::shared_ptr<DataType>> GetInteger(const rj::Value::ConstObject& 
json_type) {
+Result<std::shared_ptr<DataType>> GetInteger(const JsonObject& json_type) {
   ARROW_ASSIGN_OR_RAISE(const bool is_signed, GetMemberBool(json_type, 
"isSigned"));
   ARROW_ASSIGN_OR_RAISE(const int bit_width, GetMemberInt<int>(json_type, 
"bitWidth"));
 
@@ -938,7 +938,7 @@ Result<std::shared_ptr<DataType>> GetInteger(const 
rj::Value::ConstObject& json_
   return Status::Invalid("Invalid bit width: ", bit_width);
 }
 
-Result<std::shared_ptr<DataType>> GetFloatingPoint(const RjObject& json_type) {
+Result<std::shared_ptr<DataType>> GetFloatingPoint(const JsonObject& 
json_type) {
   ARROW_ASSIGN_OR_RAISE(const auto precision, GetMemberString(json_type, 
"precision"));
 
   if (precision == "DOUBLE") {
@@ -951,7 +951,7 @@ Result<std::shared_ptr<DataType>> GetFloatingPoint(const 
RjObject& json_type) {
   return Status::Invalid("Invalid precision: ", precision);
 }
 
-Result<std::shared_ptr<DataType>> GetMap(const RjObject& json_type,
+Result<std::shared_ptr<DataType>> GetMap(const JsonObject& json_type,
                                          const FieldVector& children) {
   if (children.size() != 1) {
     return Status::Invalid("Map must have exactly one child");
@@ -961,13 +961,13 @@ Result<std::shared_ptr<DataType>> GetMap(const RjObject& 
json_type,
   return MapType::Make(children[0], keys_sorted);
 }
 
-Result<std::shared_ptr<DataType>> GetFixedSizeBinary(const RjObject& 
json_type) {
+Result<std::shared_ptr<DataType>> GetFixedSizeBinary(const JsonObject& 
json_type) {
   ARROW_ASSIGN_OR_RAISE(const int32_t byte_width,
                         GetMemberInt<int32_t>(json_type, "byteWidth"));
   return fixed_size_binary(byte_width);
 }
 
-Result<std::shared_ptr<DataType>> GetFixedSizeList(const RjObject& json_type,
+Result<std::shared_ptr<DataType>> GetFixedSizeList(const JsonObject& json_type,
                                                    const FieldVector& 
children) {
   if (children.size() != 1) {
     return Status::Invalid("FixedSizeList must have exactly one child");
@@ -978,7 +978,7 @@ Result<std::shared_ptr<DataType>> GetFixedSizeList(const 
RjObject& json_type,
   return fixed_size_list(children[0], list_size);
 }
 
-Result<std::shared_ptr<DataType>> GetDecimal(const RjObject& json_type) {
+Result<std::shared_ptr<DataType>> GetDecimal(const JsonObject& json_type) {
   ARROW_ASSIGN_OR_RAISE(const int32_t precision,
                         GetMemberInt<int32_t>(json_type, "precision"));
   ARROW_ASSIGN_OR_RAISE(const int32_t scale, GetMemberInt<int32_t>(json_type, 
"scale"));
@@ -1003,7 +1003,7 @@ Result<std::shared_ptr<DataType>> GetDecimal(const 
RjObject& json_type) {
                          bit_width);
 }
 
-Result<std::shared_ptr<DataType>> GetDate(const RjObject& json_type) {
+Result<std::shared_ptr<DataType>> GetDate(const JsonObject& json_type) {
   ARROW_ASSIGN_OR_RAISE(const auto unit_str, GetMemberString(json_type, 
"unit"));
 
   if (unit_str == "DAY") {
@@ -1014,7 +1014,7 @@ Result<std::shared_ptr<DataType>> GetDate(const RjObject& 
json_type) {
   return Status::Invalid("Invalid date unit: ", unit_str);
 }
 
-Result<std::shared_ptr<DataType>> GetTime(const RjObject& json_type) {
+Result<std::shared_ptr<DataType>> GetTime(const JsonObject& json_type) {
   ARROW_ASSIGN_OR_RAISE(const auto unit_str, GetMemberString(json_type, 
"unit"));
   ARROW_ASSIGN_OR_RAISE(const int bit_width, GetMemberInt<int>(json_type, 
"bitWidth"));
 
@@ -1039,24 +1039,28 @@ Result<std::shared_ptr<DataType>> GetTime(const 
RjObject& json_type) {
   return type;
 }
 
-Result<std::shared_ptr<DataType>> GetDuration(const RjObject& json_type) {
+Result<std::shared_ptr<DataType>> GetDuration(const JsonObject& json_type) {
   ARROW_ASSIGN_OR_RAISE(const TimeUnit::type unit, 
GetMemberTimeUnit(json_type, "unit"));
   return duration(unit);
 }
 
-Result<std::shared_ptr<DataType>> GetTimestamp(const RjObject& json_type) {
+Result<std::shared_ptr<DataType>> GetTimestamp(const JsonObject& json_type) {
   ARROW_ASSIGN_OR_RAISE(const TimeUnit::type unit, 
GetMemberTimeUnit(json_type, "unit"));
 
-  const auto& it_tz = json_type.FindMember("timezone");
-  if (it_tz == json_type.MemberEnd()) {
+  ARROW_ASSIGN_OR_RAISE(auto timezone,
+                        internal::GetOptionalJsonField(json_type, "timezone"));
+
+  if (!timezone.has_value()) {
     return timestamp(unit);
-  } else {
-    RETURN_NOT_STRING("timezone", it_tz, json_type);
-    return timestamp(unit, it_tz->value.GetString());
   }
+
+  ARROW_ASSIGN_OR_RAISE(
+      auto timezone_string,
+      internal::ResolveSimdjsonResult(timezone->get_string(), "field was not a 
string"));
+  return timestamp(unit, std::string(timezone_string));
 }
 
-Result<std::shared_ptr<DataType>> GetInterval(const RjObject& json_type) {
+Result<std::shared_ptr<DataType>> GetInterval(const JsonObject& json_type) {
   ARROW_ASSIGN_OR_RAISE(const auto unit_str, GetMemberString(json_type, 
"unit"));
 
   if (unit_str == kDayTime) {
@@ -1069,7 +1073,7 @@ Result<std::shared_ptr<DataType>> GetInterval(const 
RjObject& json_type) {
   return Status::Invalid("Invalid interval unit: " + unit_str);
 }
 
-Result<std::shared_ptr<DataType>> GetUnion(const RjObject& json_type,
+Result<std::shared_ptr<DataType>> GetUnion(const JsonObject& json_type,
                                            const FieldVector& children) {
   ARROW_ASSIGN_OR_RAISE(const auto mode_str, GetMemberString(json_type, 
"mode"));
 
@@ -1082,15 +1086,18 @@ Result<std::shared_ptr<DataType>> GetUnion(const 
RjObject& json_type,
     return Status::Invalid("Invalid union mode: ", mode_str);
   }
 
-  ARROW_ASSIGN_OR_RAISE(const auto json_type_codes, GetMemberArray(json_type, 
"typeIds"));
+  ARROW_ASSIGN_OR_RAISE(
+      auto type_id_value,
+      internal::ResolveSimdjsonResult(json_type["typeIds"], "Failed to get 
JSON field"));
+
+  ARROW_ASSIGN_OR_RAISE(auto json_type_codes,
+                        internal::GetJsonIntArray(type_id_value, "typeIds"));
 
   std::vector<int8_t> type_codes;
-  type_codes.reserve(json_type_codes.Size());
-  for (const rj::Value& val : json_type_codes) {
-    if (!val.IsInt()) {
-      return Status::Invalid("Union type codes must be integers");
-    }
-    type_codes.push_back(static_cast<int8_t>(val.GetInt()));
+  type_codes.reserve(json_type_codes.size());
+
+  for (auto type_code : json_type_codes) {
+    type_codes.push_back(static_cast<int8_t>(type_code));
   }
 
   if (mode == UnionMode::SPARSE) {
@@ -1100,7 +1107,7 @@ Result<std::shared_ptr<DataType>> GetUnion(const 
RjObject& json_type,
   }
 }
 
-Result<std::shared_ptr<DataType>> GetRunEndEncoded(const RjObject& json_type,
+Result<std::shared_ptr<DataType>> GetRunEndEncoded(const JsonObject& json_type,
                                                    const FieldVector& 
children) {
   if (children.size() != 2) {
     return Status::Invalid("Run-end encoded array must have exactly 2 fields, 
but got ",
@@ -1128,7 +1135,7 @@ Result<std::shared_ptr<DataType>> GetRunEndEncoded(const 
RjObject& json_type,
   return run_end_encoded(children[0]->type(), children[1]->type());
 }
 
-Result<std::shared_ptr<DataType>> GetType(const RjObject& json_type,
+Result<std::shared_ptr<DataType>> GetType(const JsonObject& json_type,
                                           const FieldVector& children) {
   ARROW_ASSIGN_OR_RAISE(const auto type_name, GetMemberString(json_type, 
"name"));
 
@@ -1200,13 +1207,13 @@ Result<std::shared_ptr<DataType>> GetType(const 
RjObject& json_type,
   return Status::Invalid("Unrecognized type name: ", type_name);
 }
 
-Result<std::shared_ptr<Field>> GetField(const rj::Value& obj, FieldPosition 
field_pos,
+Result<std::shared_ptr<Field>> GetField(const JsonValue& obj, FieldPosition 
field_pos,
                                         DictionaryMemo* dictionary_memo);
 
-Result<FieldVector> GetFieldsFromArray(const RjArray& json_fields,
+Result<FieldVector> GetFieldsFromArray(const JsonArray& json_fields,
                                        FieldPosition parent_pos,
                                        DictionaryMemo* dictionary_memo) {
-  FieldVector fields(json_fields.Size());
+  FieldVector fields(json_fields.size());
   for (auto [json_field, field, i] : Zip(json_fields, fields, Enumerate<int>)) 
{
     ARROW_ASSIGN_OR_RAISE(field,
                           GetField(json_field, parent_pos.child(i), 
dictionary_memo));
@@ -1214,7 +1221,7 @@ Result<FieldVector> GetFieldsFromArray(const RjArray& 
json_fields,
   return fields;
 }
 
-Status ParseDictionary(const RjObject& obj, int64_t* id, bool* is_ordered,
+Status ParseDictionary(const JsonObject& obj, int64_t* id, bool* is_ordered,
                        std::shared_ptr<DataType>* index_type) {
   ARROW_ASSIGN_OR_RAISE(*id, GetMemberInt<int64_t>(obj, "id"));
   ARROW_ASSIGN_OR_RAISE(*is_ordered, GetMemberBool(obj, "isOrdered"));
@@ -1232,34 +1239,37 @@ template <typename FieldOrStruct>
 Result<std::shared_ptr<KeyValueMetadata>> GetKeyValueMetadata(
     const FieldOrStruct& field_or_struct) {
   auto metadata = std::make_shared<KeyValueMetadata>();
-  auto it = field_or_struct.FindMember("metadata");
-  if (it == field_or_struct.MemberEnd() || it->value.IsNull()) {
+
+  ARROW_ASSIGN_OR_RAISE(auto metadata_value,
+                        internal::GetOptionalJsonField(field_or_struct, 
"metadata"));
+
+  if (!metadata_value || metadata_value->is_null()) {
     return metadata;
   }
-  if (!it->value.IsArray()) {
-    return Status::Invalid("Metadata was not a JSON array");
-  }
 
-  for (const auto& val : it->value.GetArray()) {
-    if (!val.IsObject()) {
-      return Status::Invalid("Metadata KeyValue was not a JSON object");
-    }
-    const auto& key_value_pair = val.GetObject();
+  ARROW_ASSIGN_OR_RAISE(auto metadata_array,
+                        internal::GetJsonArray(*metadata_value, "metadata"));
+
+  for (const auto& val : metadata_array) {
+    ARROW_ASSIGN_OR_RAISE(
+        auto key_value_pair,
+        internal::ResolveSimdjsonResult(val.get_object(),
+                                        "Metadata KeyValue was not a JSON 
object"));
 
     ARROW_ASSIGN_OR_RAISE(const auto key, GetMemberString(key_value_pair, 
"key"));
     ARROW_ASSIGN_OR_RAISE(const auto value, GetMemberString(key_value_pair, 
"value"));
 
     metadata->Append(std::move(key), std::move(value));
   }
+
   return metadata;
 }
 
-Result<std::shared_ptr<Field>> GetField(const rj::Value& obj, FieldPosition 
field_pos,
+Result<std::shared_ptr<Field>> GetField(const JsonValue& obj, FieldPosition 
field_pos,
                                         DictionaryMemo* dictionary_memo) {
-  if (!obj.IsObject()) {
-    return Status::Invalid("Field was not a JSON object");
-  }
-  const auto& json_field = obj.GetObject();
+  ARROW_ASSIGN_OR_RAISE(
+      auto json_field,
+      internal::ResolveSimdjsonResult(obj.get_object(), "Field was not a JSON 
object"));
 
   ARROW_ASSIGN_OR_RAISE(const auto name, GetMemberString(json_field, "name"));
   ARROW_ASSIGN_OR_RAISE(const bool nullable, GetMemberBool(json_field, 
"nullable"));
@@ -1277,18 +1287,24 @@ Result<std::shared_ptr<Field>> GetField(const 
rj::Value& obj, FieldPosition fiel
   // Is it a dictionary type?
   int64_t dictionary_id = -1;
   std::shared_ptr<DataType> dict_value_type;
-  const auto& it_dictionary = json_field.FindMember("dictionary");
-  if (dictionary_memo != nullptr && it_dictionary != json_field.MemberEnd()) {
-    // Parse dictionary id in JSON and add dictionary field to the
-    // memo, and parse the dictionaries later
-    RETURN_NOT_OBJECT("dictionary", it_dictionary, json_field);
-    bool is_ordered{};
-    std::shared_ptr<DataType> index_type;
-    RETURN_NOT_OK(ParseDictionary(it_dictionary->value.GetObject(), 
&dictionary_id,
-                                  &is_ordered, &index_type));
 
-    dict_value_type = type;
-    type = ::arrow::dictionary(index_type, type, is_ordered);
+  if (dictionary_memo != nullptr) {
+    ARROW_ASSIGN_OR_RAISE(auto dictionary_value,
+                          internal::GetOptionalJsonField(json_field, 
"dictionary"));
+
+    if (dictionary_value) {
+      ARROW_ASSIGN_OR_RAISE(
+          auto dictionary_object,
+          internal::ResolveSimdjsonResult(dictionary_value->get_object(),
+                                          "dictionary was not a JSON object"));
+
+      bool is_ordered{};
+      std::shared_ptr<DataType> index_type;
+      RETURN_NOT_OK(
+          ParseDictionary(dictionary_object, &dictionary_id, &is_ordered, 
&index_type));
+      dict_value_type = type;
+      type = ::arrow::dictionary(index_type, type, is_ordered);
+    }
   }
 
   // Is it an extension type?
@@ -1324,41 +1340,46 @@ Result<std::shared_ptr<Field>> GetField(const 
rj::Value& obj, FieldPosition fiel
 }
 
 template <typename T>
-enable_if_boolean<T, bool> UnboxValue(const rj::Value& val) {
-  DCHECK(val.IsBool());
-  return val.GetBool();
+enable_if_boolean<T, Result<bool>> UnboxValue(const JsonValue& val) {
+  return internal::ResolveSimdjsonResult(val.get_bool(), "Expected boolean 
value");
 }
 
 template <typename T, typename CType = typename T::c_type>
-enable_if_t<is_physical_integer_type<T>::value && sizeof(CType) != 
sizeof(int64_t), CType>
-UnboxValue(const rj::Value& val) {
-  DCHECK(val.IsInt64());
-  return static_cast<CType>(val.GetInt64());
+enable_if_t<is_physical_integer_type<T>::value && sizeof(CType) != 
sizeof(int64_t),
+            Result<CType>>
+UnboxValue(const JsonValue& val) {
+  ARROW_ASSIGN_OR_RAISE(auto integer, internal::GetJsonInt(val, "value", "an 
integer"));
+  return static_cast<CType>(integer);
 }
 
 template <typename T, typename CType = typename T::c_type>
-enable_if_t<is_physical_integer_type<T>::value && sizeof(CType) == 
sizeof(int64_t), CType>
-UnboxValue(const rj::Value& val) {
-  DCHECK(val.IsString());
+enable_if_t<is_physical_integer_type<T>::value && sizeof(CType) == 
sizeof(int64_t),
+            Result<CType>>
+UnboxValue(const JsonValue& val) {
+  ARROW_ASSIGN_OR_RAISE(auto string, internal::ResolveSimdjsonResult(
+                                         val.get_string(), "Expected string 
value"));
 
   CType out;
-  bool success = ::arrow::internal::ParseValue<typename 
CTypeTraits<CType>::ArrowType>(
-      val.GetString(), val.GetStringLength(), &out);
-
-  DCHECK(success);
+  if (!::arrow::internal::ParseValue<typename CTypeTraits<CType>::ArrowType>(
+          string.data(), string.size(), &out)) {
+    return Status::Invalid("Failed to parse integer value");
+  }
   return out;
 }
 
 template <typename T>
-enable_if_physical_floating_point<T, typename T::c_type> UnboxValue(
-    const rj::Value& val) {
-  DCHECK(val.IsFloat());
-  return static_cast<typename T::c_type>(val.GetDouble());
+enable_if_physical_floating_point<T, Result<typename T::c_type>> UnboxValue(
+    const JsonValue& val) {
+  ARROW_ASSIGN_OR_RAISE(
+      auto floating_point,
+      internal::ResolveSimdjsonResult(val.get_double(), "Expected floating 
point value"));
+  return static_cast<typename T::c_type>(floating_point);
 }
 
 class ArrayReader {
  public:
-  ArrayReader(const RjObject& obj, MemoryPool* pool, const 
std::shared_ptr<Field>& field)
+  ArrayReader(const JsonObject& obj, MemoryPool* pool,
+              const std::shared_ptr<Field>& field)
       : obj_(obj), pool_(pool), field_(field), type_(field->type()) {}
 
   template <typename BuilderType>
@@ -1369,13 +1390,14 @@ class ArrayReader {
     return Status::OK();
   }
 
-  Result<const RjArray> GetDataArray(const RjObject& obj,
-                                     const std::string& key = kData) {
+  Result<JsonArray> GetDataArray(const JsonObject& obj, std::string_view key = 
kData) {
     ARROW_ASSIGN_OR_RAISE(const auto json_data_arr, GetMemberArray(obj, key));
-    if (static_cast<int32_t>(json_data_arr.Size()) != length_) {
-      return Status::Invalid("JSON ", key, " array size ", 
json_data_arr.Size(),
+
+    if (static_cast<int32_t>(json_data_arr.size()) != length_) {
+      return Status::Invalid("JSON ", key, " array size ", 
json_data_arr.size(),
                              " differs from advertised array length ", 
length_);
     }
+
     return json_data_arr;
   }
 
@@ -1385,19 +1407,23 @@ class ArrayReader {
 
     ARROW_ASSIGN_OR_RAISE(const auto json_data_arr, GetDataArray(obj_));
     for (auto [is_valid, val] : Zip(is_valid_, json_data_arr)) {
-      RETURN_NOT_OK(is_valid ? builder.Append(UnboxValue<T>(val)) : 
builder.AppendNull());
+      if (is_valid) {
+        ARROW_ASSIGN_OR_RAISE(auto value, UnboxValue<T>(val));
+        RETURN_NOT_OK(builder.Append(value));
+      } else {
+        RETURN_NOT_OK(builder.AppendNull());
+      }
     }
     return FinishBuilder(&builder);
   }
 
-  int64_t ParseOffset(const rj::Value& json_offset) {
-    DCHECK(json_offset.IsInt() || json_offset.IsInt64() || 
json_offset.IsString());
-
-    if (json_offset.IsInt64()) {
-      return json_offset.GetInt64();
-    } else {
-      return UnboxValue<Int64Type>(json_offset);
+  Result<int64_t> ParseOffset(const JsonValue& json_offset) {
+    auto integer_result = json_offset.get_int64();
+    if (integer_result.error() == simdjson::SUCCESS) {
+      return internal::ResolveSimdjsonResult(integer_result, "Expected integer 
offset");
     }
+
+    return UnboxValue<Int64Type>(json_offset);
   }
 
   template <typename T>
@@ -1407,21 +1433,27 @@ class ArrayReader {
 
     ARROW_ASSIGN_OR_RAISE(const auto json_data_arr, GetDataArray(obj_));
     ARROW_ASSIGN_OR_RAISE(const auto json_offsets, GetMemberArray(obj_, 
"OFFSET"));
-    if (static_cast<int32_t>(json_offsets.Size()) != (length_ + 1)) {
+    if (static_cast<int32_t>(json_offsets.size()) != (length_ + 1)) {
       return Status::Invalid(
           "JSON OFFSET array size differs from advertised array length + 1");
     }
 
-    for (auto [i, is_valid, json_val] :
-         Zip(Enumerate<rj::SizeType>, is_valid_, json_data_arr)) {
+    auto offset_it = json_offsets.begin();
+
+    for (auto [is_valid, json_val] : Zip(is_valid_, json_data_arr)) {
+      auto offset_start_json = *offset_it;
+      ++offset_it;
+      auto offset_end_json = *offset_it;
+
       if (!is_valid) {
         RETURN_NOT_OK(builder.AppendNull());
         continue;
       }
+
       ARROW_ASSIGN_OR_RAISE(auto val, GetStringView(json_val));
 
-      int64_t offset_start = ParseOffset(json_offsets[i]);
-      int64_t offset_end = ParseOffset(json_offsets[i + 1]);
+      ARROW_ASSIGN_OR_RAISE(auto offset_start, ParseOffset(offset_start_json));
+      ARROW_ASSIGN_OR_RAISE(auto offset_end, ParseOffset(offset_end_json));
       DCHECK_GE(offset_end, offset_start);
       auto val_len = static_cast<size_t>(offset_end - offset_start);
 
@@ -1430,7 +1462,7 @@ class ArrayReader {
           return Status::Invalid("Value ", std::quoted(val),
                                  " differs from advertised length ", val_len);
         }
-        RETURN_NOT_OK(builder.Append(json_val.GetString()));
+        RETURN_NOT_OK(builder.Append(val));
       } else {
         if (val.size() % 2 != 0) {
           return Status::Invalid("Expected base16 hex string");
@@ -1463,7 +1495,7 @@ class ArrayReader {
     using internal::Zip;
 
     BufferVector buffers;
-    buffers.resize(json_variadic_bufs.Size() + 2);
+    buffers.resize(json_variadic_bufs.size() + 2);
     for (auto [json_buf, buf] : Zip(json_variadic_bufs, 
std::span{buffers}.subspan(2))) {
       ARROW_ASSIGN_OR_RAISE(auto hex_string, GetStringView(json_buf));
       ARROW_ASSIGN_OR_RAISE(
@@ -1492,51 +1524,44 @@ class ArrayReader {
         continue;
       }
 
-      DCHECK(json_view.IsObject());
-      const auto& json_view_obj = json_view.GetObject();
+      ARROW_ASSIGN_OR_RAISE(auto json_view_obj, 
internal::ResolveSimdjsonResult(
+                                                    json_view.get_object(),
+                                                    "Binary view was not a 
JSON object"));
 
-      auto json_size = json_view_obj.FindMember("SIZE");
-      RETURN_NOT_INT("SIZE", json_size, json_view_obj);
-      auto size = json_size->value.GetInt();
+      ARROW_ASSIGN_OR_RAISE(const int size, GetMemberInt<int>(json_view_obj, 
"SIZE"));
       if (size < 0) {
         return Status::Invalid("Invalid binary view SIZE: ", size,
                                ". Expected a non-negative value");
       }
 
       if (size <= BinaryViewType::kInlineSize) {
-        auto json_inlined = json_view_obj.FindMember("INLINED");
-        RETURN_NOT_STRING("INLINED", json_inlined, json_view_obj);
+        ARROW_ASSIGN_OR_RAISE(const auto inlined,
+                              GetMemberString(json_view_obj, "INLINED"));
+
         out_view.inlined = {size, {}};
 
         if constexpr (ViewType::is_utf8) {
-          if (json_inlined->value.GetStringLength() != 
static_cast<rj::SizeType>(size)) {
-            return Status::Invalid("Invalid binary view INLINED length: ",
-                                   json_inlined->value.GetStringLength(),
+          if (static_cast<int>(inlined.size()) != size) {
+            return Status::Invalid("Invalid binary view INLINED length: ", 
inlined.size(),
                                    ". Expected exactly ", size, " bytes");
           }
-          memcpy(&out_view.inlined.data, json_inlined->value.GetString(), 
size);
+          memcpy(&out_view.inlined.data, inlined.data(), size);
         } else {
-          if (json_inlined->value.GetStringLength() !=
-              static_cast<rj::SizeType>(size * 2)) {
-            return Status::Invalid("Invalid binary view INLINED hex length: ",
-                                   json_inlined->value.GetStringLength(),
-                                   ". Expected exactly ", size * 2, " 
characters");
+          if (static_cast<int>(inlined.size()) != size * 2) {
+            return Status::Invalid(
+                "Invalid binary view INLINED hex length: ", inlined.size(),
+                ". Expected exactly ", size * 2, " characters");
           }
-          ARROW_ASSIGN_OR_RAISE(auto inlined, 
GetStringView(json_inlined->value));
           RETURN_NOT_OK(ParseHexValues(inlined, out_view.inlined.data.data()));
         }
         continue;
       }
 
-      auto json_prefix = json_view_obj.FindMember("PREFIX_HEX");
-      auto json_buffer_index = json_view_obj.FindMember("BUFFER_INDEX");
-      auto json_offset = json_view_obj.FindMember("OFFSET");
-      RETURN_NOT_STRING("PREFIX_HEX", json_prefix, json_view_obj);
-      RETURN_NOT_INT("BUFFER_INDEX", json_buffer_index, json_view_obj);
-      RETURN_NOT_INT("OFFSET", json_offset, json_view_obj);
-
-      const auto buffer_index = json_buffer_index->value.GetInt();
-      const auto offset = json_offset->value.GetInt();
+      ARROW_ASSIGN_OR_RAISE(const auto prefix,
+                            GetMemberString(json_view_obj, "PREFIX_HEX"));
+      ARROW_ASSIGN_OR_RAISE(const int buffer_index,
+                            GetMemberInt<int>(json_view_obj, "BUFFER_INDEX"));
+      ARROW_ASSIGN_OR_RAISE(const int offset, GetMemberInt<int>(json_view_obj, 
"OFFSET"));
       if (buffer_index < 0) {
         return Status::Invalid("Invalid binary view BUFFER_INDEX: ", 
buffer_index,
                                ". Expected a non-negative value");
@@ -1545,9 +1570,8 @@ class ArrayReader {
         return Status::Invalid("Invalid binary view OFFSET: ", offset,
                                ". Expected a non-negative value");
       }
-      if (json_prefix->value.GetStringLength() != BinaryViewType::kPrefixSize 
* 2) {
-        return Status::Invalid("Invalid binary view PREFIX_HEX length: ",
-                               json_prefix->value.GetStringLength(),
+      if (prefix.size() != BinaryViewType::kPrefixSize * 2) {
+        return Status::Invalid("Invalid binary view PREFIX_HEX length: ", 
prefix.size(),
                                ". Expected exactly ", 
BinaryViewType::kPrefixSize * 2,
                                " characters");
       }
@@ -1573,7 +1597,6 @@ class ArrayReader {
           offset,
       };
 
-      ARROW_ASSIGN_OR_RAISE(auto prefix, GetStringView(json_prefix->value));
       RETURN_NOT_OK(ParseHexValues(prefix, out_view.ref.prefix.data()));
     }
 
@@ -1591,10 +1614,14 @@ class ArrayReader {
         RETURN_NOT_OK(builder.AppendNull());
         continue;
       }
-      DCHECK(val.IsObject());
+      ARROW_ASSIGN_OR_RAISE(
+          auto object, internal::ResolveSimdjsonResult(
+                           val.get_object(), "Interval value was not a JSON 
object"));
+
       DayTimeIntervalType::DayMilliseconds dm;
-      dm.days = val[kDays].GetInt();
-      dm.milliseconds = val[kMilliseconds].GetInt();
+      ARROW_ASSIGN_OR_RAISE(dm.days, GetMemberInt<int32_t>(object, kDays));
+      ARROW_ASSIGN_OR_RAISE(dm.milliseconds,
+                            GetMemberInt<int32_t>(object, kMilliseconds));
       RETURN_NOT_OK(builder.Append(dm));
     }
     return FinishBuilder(&builder);
@@ -1610,11 +1637,14 @@ class ArrayReader {
         RETURN_NOT_OK(builder.AppendNull());
         continue;
       }
-      DCHECK(val.IsObject());
+      ARROW_ASSIGN_OR_RAISE(
+          auto object, internal::ResolveSimdjsonResult(
+                           val.get_object(), "Interval value was not a JSON 
object"));
+
       MonthDayNanoIntervalType::MonthDayNanos mdn;
-      mdn.months = val[kMonths].GetInt();
-      mdn.days = val[kDays].GetInt();
-      mdn.nanoseconds = val[kNanoseconds].GetInt64();
+      ARROW_ASSIGN_OR_RAISE(mdn.months, GetMemberInt<int32_t>(object, 
kMonths));
+      ARROW_ASSIGN_OR_RAISE(mdn.days, GetMemberInt<int32_t>(object, kDays));
+      ARROW_ASSIGN_OR_RAISE(mdn.nanoseconds, GetMemberInt<int64_t>(object, 
kNanoseconds));
       RETURN_NOT_OK(builder.Append(mdn));
     }
     return FinishBuilder(&builder);
@@ -1639,10 +1669,11 @@ class ArrayReader {
         continue;
       }
 
-      DCHECK(json_val.IsString())
-          << "Found non-string JSON value when parsing FixedSizeBinary value";
-
-      std::string_view val = json_val.GetString();
+      ARROW_ASSIGN_OR_RAISE(
+          auto val,
+          internal::ResolveSimdjsonResult(
+              json_val.get_string(),
+              "Found non-string JSON value when parsing FixedSizeBinary 
value"));
       if (static_cast<int32_t>(val.size()) != byte_width * 2) {
         DCHECK(false) << "Expected size: " << byte_width * 2 << " got: " << 
val.size();
       }
@@ -1660,8 +1691,8 @@ class ArrayReader {
     typename TypeTraits<T>::BuilderType builder(type_, pool_);
 
     ARROW_ASSIGN_OR_RAISE(const auto json_data_arr, GetDataArray(obj_));
-    if (static_cast<rj::SizeType>(length_) != json_data_arr.Size()) {
-      return Status::Invalid("Integer array had unexpected length ", 
json_data_arr.Size(),
+    if (static_cast<int64_t>(json_data_arr.size()) != length_) {
+      return Status::Invalid("Integer array had unexpected length ", 
json_data_arr.size(),
                              " (expected ", length_, ")");
     }
 
@@ -1671,13 +1702,14 @@ class ArrayReader {
         continue;
       }
 
-      DCHECK(val.IsString())
-          << "Found non-string JSON value when parsing Decimal128 value";
-      DCHECK_GT(val.GetStringLength(), 0)
-          << "Empty string found when parsing Decimal128 value";
+      ARROW_ASSIGN_OR_RAISE(auto string,
+                            internal::ResolveSimdjsonResult(
+                                val.get_string(), "Expected decimal value as 
string"));
+
+      DCHECK_GT(string.size(), 0) << "Empty string found when parsing 
Decimal128 value";
 
       using Value = typename TypeTraits<T>::ScalarType::ValueType;
-      ARROW_ASSIGN_OR_RAISE(Value decimal_val, 
Value::FromString(val.GetString()));
+      ARROW_ASSIGN_OR_RAISE(Value decimal_val, Value::FromString(string));
       RETURN_NOT_OK(builder.Append(decimal_val));
     }
 
@@ -1685,10 +1717,10 @@ class ArrayReader {
   }
 
   template <typename T>
-  Status GetIntArray(const RjArray& json_array, const int32_t length,
+  Status GetIntArray(const JsonArray& json_array, const int32_t length,
                      std::shared_ptr<Buffer>* out) {
-    if (static_cast<rj::SizeType>(length) != json_array.Size()) {
-      return Status::Invalid("Integer array had unexpected length ", 
json_array.Size(),
+    if (static_cast<int32_t>(json_array.size()) != length) {
+      return Status::Invalid("Integer array had unexpected length ", 
json_array.size(),
                              " (expected ", length, ")");
     }
 
@@ -1696,24 +1728,21 @@ class ArrayReader {
 
     T* values = reinterpret_cast<T*>(buffer->mutable_data());
 
-    for (auto [i, val] : Zip(Enumerate<rj::SizeType>, json_array)) {
+    for (auto [i, val] : Zip(Enumerate<size_t>, json_array)) {
       if constexpr (sizeof(T) < sizeof(int64_t)) {
-        DCHECK(val.IsInt() || val.IsInt64());
-        if (val.IsInt()) {
-          values[i] = static_cast<T>(val.GetInt());
-        } else {
-          values[i] = static_cast<T>(val.GetInt64());
-        }
+        ARROW_ASSIGN_OR_RAISE(auto integer,
+                              internal::GetJsonInt(val, "value", "an 
integer"));
+        values[i] = static_cast<T>(integer);
       } else {
         // Read 64-bit integers as strings, as JSON numbers cannot represent
         // them exactly.
-        DCHECK(val.IsString());
+        ARROW_ASSIGN_OR_RAISE(auto string,
+                              internal::ResolveSimdjsonResult(
+                                  val.get_string(), "Expected integer value as 
string"));
 
         using ArrowType = typename CTypeTraits<T>::ArrowType;
-        if (!ParseValue<ArrowType>(val.GetString(), val.GetStringLength(), 
&values[i])) {
-          return Status::Invalid("Failed to parse integer: '",
-                                 std::string(val.GetString(), 
val.GetStringLength()),
-                                 "'");
+        if (!ParseValue<ArrowType>(string.data(), string.size(), &values[i])) {
+          return Status::Invalid("Failed to parse integer: '", 
std::string(string), "'");
         }
       }
     }
@@ -1868,24 +1897,36 @@ class ArrayReader {
 
     return Status::OK();
   }
-  Status GetChildren(const RjObject& obj, const DataType& type) {
+
+  Status GetChildren(const JsonObject& obj, const DataType& type) {
+    ARROW_ASSIGN_OR_RAISE(auto children_value,
+                          internal::GetOptionalJsonField(obj, "children"));
+
+    if (!children_value) {
+      if (type.num_fields() == 0) {
+        data_->child_data.clear();
+        return Status::OK();
+      }
+      return Status::Invalid("Expected ", type.num_fields(), " children, but 
got 0");
+    }
+
     ARROW_ASSIGN_OR_RAISE(const auto json_children,
-                          GetMemberArray(obj, "children", 
/*allow_absent=*/true));
+                          internal::GetJsonArray(*children_value, "children"));
 
-    if (type.num_fields() != static_cast<int>(json_children.Size())) {
+    if (type.num_fields() != static_cast<int>(json_children.size())) {
       return Status::Invalid("Expected ", type.num_fields(), " children, but 
got ",
-                             json_children.Size());
+                             json_children.size());
     }
 
     data_->child_data.resize(type.num_fields());
     for (auto [json_child, child_field, child_data] :
          Zip(json_children, type.fields(), data_->child_data)) {
-      DCHECK(json_child.IsObject());
-      const auto& child_obj = json_child.GetObject();
+      ARROW_ASSIGN_OR_RAISE(
+          auto child_obj, 
internal::ResolveSimdjsonResult(json_child.get_object(),
+                                                          "Child was not a 
JSON object"));
 
-      auto it = json_child.FindMember("name");
-      RETURN_NOT_STRING("name", it, json_child);
-      DCHECK_EQ(it->value.GetString(), child_field->name());
+      ARROW_ASSIGN_OR_RAISE(const auto name, GetMemberString(child_obj, 
"name"));
+      DCHECK_EQ(name, child_field->name());
 
       ArrayReader child_reader(child_obj, pool_, child_field);
       ARROW_ASSIGN_OR_RAISE(child_data, child_reader.Parse());
@@ -1896,13 +1937,15 @@ class ArrayReader {
 
   Status ParseValidityBitmap() {
     ARROW_ASSIGN_OR_RAISE(const auto json_validity, GetMemberArray(obj_, 
"VALIDITY"));
-    if (static_cast<int>(json_validity.Size()) != length_) {
+    if (static_cast<int>(json_validity.size()) != length_) {
       return Status::Invalid("JSON VALIDITY size differs from advertised array 
length");
     }
-    is_valid_.reserve(json_validity.Size());
-    for (const rj::Value& val : json_validity) {
-      DCHECK(val.IsInt());
-      is_valid_.push_back(val.GetInt() != 0);
+
+    is_valid_.reserve(json_validity.size());
+    for (const auto& value : json_validity) {
+      ARROW_ASSIGN_OR_RAISE(auto integer,
+                            internal::GetJsonInt(value, "VALIDITY value", "an 
integer"));
+      is_valid_.push_back(integer != 0);
     }
     return Status::OK();
   }
@@ -1920,7 +1963,7 @@ class ArrayReader {
   }
 
  private:
-  const RjObject& obj_;
+  JsonObject obj_;
   MemoryPool* pool_;
   std::shared_ptr<Field> field_;
   std::shared_ptr<DataType> type_;
@@ -1932,17 +1975,17 @@ class ArrayReader {
 };
 
 Result<std::shared_ptr<ArrayData>> ReadArrayData(MemoryPool* pool,
-                                                 const rj::Value& json_array,
+                                                 const JsonValue& json_array,
                                                  const std::shared_ptr<Field>& 
field) {
-  if (!json_array.IsObject()) {
-    return Status::Invalid("Array element was not a JSON object");
-  }
-  auto obj = json_array.GetObject();
+  ARROW_ASSIGN_OR_RAISE(
+      auto obj, internal::ResolveSimdjsonResult(json_array.get_object(),
+                                                "Array element was not a JSON 
object"));
+
   ArrayReader parser(obj, pool, field);
   return parser.Parse();
 }
 
-Status ReadDictionary(const RjObject& obj, MemoryPool* pool,
+Status ReadDictionary(const JsonObject& obj, MemoryPool* pool,
                       DictionaryMemo* dictionary_memo) {
   ARROW_ASSIGN_OR_RAISE(int64_t dictionary_id, GetMemberInt<int64_t>(obj, 
"id"));
 
@@ -1954,12 +1997,16 @@ Status ReadDictionary(const RjObject& obj, MemoryPool* 
pool,
   ARROW_ASSIGN_OR_RAISE(const int64_t num_rows,
                         GetMemberInt<int64_t>(batch_obj, "count"));
   ARROW_ASSIGN_OR_RAISE(const auto json_columns, GetMemberArray(batch_obj, 
"columns"));
-  if (json_columns.Size() != 1) {
+  if (json_columns.size() != 1) {
     return Status::Invalid("Dictionary batch must contain only one column");
   }
 
+  ARROW_ASSIGN_OR_RAISE(
+      auto column, internal::ResolveSimdjsonResult(json_columns.at(0),
+                                                   "Failed to get dictionary 
column"));
+
   ARROW_ASSIGN_OR_RAISE(auto dict_data,
-                        ReadArrayData(pool, json_columns[0], field("dummy", 
value_type)));
+                        ReadArrayData(pool, column, field("dummy", 
value_type)));
   if (num_rows != dict_data->length) {
     return Status::Invalid("Dictionary batch length mismatch: advertised (", 
num_rows,
                            ") != actual (", dict_data->length, ")");
@@ -1967,31 +2014,40 @@ Status ReadDictionary(const RjObject& obj, MemoryPool* 
pool,
   return dictionary_memo->AddDictionary(dictionary_id, dict_data);
 }
 
-Status ReadDictionaries(const rj::Value& doc, MemoryPool* pool,
+Status ReadDictionaries(const JsonValue& doc, MemoryPool* pool,
                         DictionaryMemo* dictionary_memo) {
-  auto it = doc.FindMember("dictionaries");
-  if (it == doc.MemberEnd()) {
-    // No dictionaries
+  ARROW_ASSIGN_OR_RAISE(
+      auto obj, internal::ResolveSimdjsonResult(doc.get_object(),
+                                                "JSON document was not an 
object"));
+
+  ARROW_ASSIGN_OR_RAISE(auto dictionaries_value,
+                        internal::GetOptionalJsonField(obj, "dictionaries"));
+
+  if (!dictionaries_value) {
     return Status::OK();
   }
+  ARROW_ASSIGN_OR_RAISE(auto dictionary_array,
+                        internal::GetJsonArray(*dictionaries_value, 
"dictionaries"));
 
-  RETURN_NOT_ARRAY("dictionaries", it, doc);
-  const auto& dictionary_array = it->value.GetArray();
-
-  for (const rj::Value& val : dictionary_array) {
-    DCHECK(val.IsObject());
-    RETURN_NOT_OK(ReadDictionary(val.GetObject(), pool, dictionary_memo));
+  for (const auto& value : dictionary_array) {
+    ARROW_ASSIGN_OR_RAISE(auto dictionary_object,
+                          internal::ResolveSimdjsonResult(
+                              value.get_object(), "Dictionary was not a JSON 
object"));
+    RETURN_NOT_OK(ReadDictionary(dictionary_object, pool, dictionary_memo));
   }
   return Status::OK();
 }
 
 }  // namespace
 
-Result<std::shared_ptr<Schema>> ReadSchema(const rj::Value& json_schema, 
MemoryPool* pool,
+Result<std::shared_ptr<Schema>> ReadSchema(const JsonValue& json_schema, 
MemoryPool* pool,
                                            DictionaryMemo* dictionary_memo) {
-  DCHECK(json_schema.IsObject());
+  ARROW_ASSIGN_OR_RAISE(auto schema_document,
+                        
internal::ResolveSimdjsonResult(json_schema.get_object(),
+                                                        "JSON schema was not 
an object"));
+
   ARROW_ASSIGN_OR_RAISE(const auto obj_schema,
-                        GetMemberObject(json_schema.GetObject(), "schema"));
+                        GetMemberObject(schema_document, "schema"));
 
   ARROW_ASSIGN_OR_RAISE(const auto json_fields, GetMemberArray(obj_schema, 
"fields"));
 
@@ -1999,31 +2055,31 @@ Result<std::shared_ptr<Schema>> ReadSchema(const 
rj::Value& json_schema, MemoryP
   ARROW_ASSIGN_OR_RAISE(
       FieldVector fields,
       GetFieldsFromArray(json_fields, FieldPosition(), dictionary_memo));
-  // Read the dictionaries (if any) and cache in the memo
+
   RETURN_NOT_OK(ReadDictionaries(json_schema, pool, dictionary_memo));
 
   return ::arrow::schema(fields, metadata);
-  return Status::OK();
 }
 
-Result<std::shared_ptr<Array>> ReadArray(MemoryPool* pool, const rj::Value& 
json_array,
+Result<std::shared_ptr<Array>> ReadArray(MemoryPool* pool, const JsonValue& 
json_array,
                                          const std::shared_ptr<Field>& field) {
   ARROW_ASSIGN_OR_RAISE(auto data, ReadArrayData(pool, json_array, field));
   return MakeArray(data);
 }
 
 Result<std::shared_ptr<RecordBatch>> ReadRecordBatch(
-    const rj::Value& json_obj, const std::shared_ptr<Schema>& schema,
+    const JsonValue& json_obj, const std::shared_ptr<Schema>& schema,
     DictionaryMemo* dictionary_memo, MemoryPool* pool) {
-  DCHECK(json_obj.IsObject());
-  const auto& batch_obj = json_obj.GetObject();
+  ARROW_ASSIGN_OR_RAISE(auto batch_obj,
+                        internal::ResolveSimdjsonResult(
+                            json_obj.get_object(), "Record batch was not a 
JSON object"));
 
   ARROW_ASSIGN_OR_RAISE(const int64_t num_rows,
                         GetMemberInt<int64_t>(batch_obj, "count"));
 
   ARROW_ASSIGN_OR_RAISE(const auto json_columns, GetMemberArray(batch_obj, 
"columns"));
 
-  ArrayDataVector columns(json_columns.Size());
+  ArrayDataVector columns(json_columns.size());
   for (auto [column, json_column, field] : Zip(columns, json_columns, 
schema->fields())) {
     ARROW_ASSIGN_OR_RAISE(column, ReadArrayData(pool, json_column, field));
   }
diff --git a/cpp/src/arrow/integration/json_internal.h 
b/cpp/src/arrow/integration/json_internal.h
index b87c102ca9b..b61d5b57460 100644
--- a/cpp/src/arrow/integration/json_internal.h
+++ b/cpp/src/arrow/integration/json_internal.h
@@ -21,63 +21,21 @@
 #include <memory>
 #include <string>
 
-#include "arrow/json/rapidjson_defs.h"  // IWYU pragma: keep
-
-#include <rapidjson/document.h>      // IWYU pragma: export
-#include <rapidjson/encodings.h>     // IWYU pragma: export
-#include <rapidjson/error/en.h>      // IWYU pragma: export
-#include <rapidjson/rapidjson.h>     // IWYU pragma: export
-#include <rapidjson/stringbuffer.h>  // IWYU pragma: export
-#include <rapidjson/writer.h>        // IWYU pragma: export
+#include <simdjson.h>
 
 #include "arrow/ipc/type_fwd.h"
 #include "arrow/result.h"
 #include "arrow/type_fwd.h"
 #include "arrow/util/visibility.h"
 
-namespace rj = arrow::rapidjson;
-using RjObject = rj::Value::ConstObject;
-using RjArray = rj::Value::ConstArray;
+using JsonValue = simdjson::dom::element;
+using JsonObject = simdjson::dom::object;
+using JsonArray = simdjson::dom::array;
 
 namespace arrow::json {
 class JsonWriter;
 }  // namespace arrow::json
 
-#define RETURN_NOT_FOUND(TOK, NAME, PARENT)              \
-  if (NAME == (PARENT).MemberEnd()) {                    \
-    return Status::Invalid("field ", TOK, " not found"); \
-  }
-
-#define RETURN_NOT_STRING(TOK, NAME, PARENT)                          \
-  RETURN_NOT_FOUND(TOK, NAME, PARENT);                                \
-  if (!NAME->value.IsString()) {                                      \
-    return Status::Invalid("field was not a string line ", __LINE__); \
-  }
-
-#define RETURN_NOT_BOOL(TOK, NAME, PARENT)                             \
-  RETURN_NOT_FOUND(TOK, NAME, PARENT);                                 \
-  if (!NAME->value.IsBool()) {                                         \
-    return Status::Invalid("field was not a boolean line ", __LINE__); \
-  }
-
-#define RETURN_NOT_INT(TOK, NAME, PARENT)                           \
-  RETURN_NOT_FOUND(TOK, NAME, PARENT);                              \
-  if (!NAME->value.IsInt()) {                                       \
-    return Status::Invalid("field was not an int line ", __LINE__); \
-  }
-
-#define RETURN_NOT_ARRAY(TOK, NAME, PARENT)                           \
-  RETURN_NOT_FOUND(TOK, NAME, PARENT);                                \
-  if (!NAME->value.IsArray()) {                                       \
-    return Status::Invalid("field was not an array line ", __LINE__); \
-  }
-
-#define RETURN_NOT_OBJECT(TOK, NAME, PARENT)                           \
-  RETURN_NOT_FOUND(TOK, NAME, PARENT);                                 \
-  if (!NAME->value.IsObject()) {                                       \
-    return Status::Invalid("field was not an object line ", __LINE__); \
-  }
-
 namespace arrow::internal::integration::json {
 
 /// \brief Append integration test Schema format to JSON writer
@@ -96,17 +54,17 @@ ARROW_EXPORT
 Status WriteArray(const std::string& name, const Array& array, 
arrow::json::JsonWriter*);
 
 ARROW_EXPORT
-Result<std::shared_ptr<Schema>> ReadSchema(const rj::Value& json_obj, 
MemoryPool* pool,
+Result<std::shared_ptr<Schema>> ReadSchema(const JsonValue& json_obj, 
MemoryPool* pool,
                                            ipc::DictionaryMemo* 
dictionary_memo);
 
 ARROW_EXPORT
 Result<std::shared_ptr<RecordBatch>> ReadRecordBatch(
-    const rj::Value& json_obj, const std::shared_ptr<Schema>& schema,
+    const JsonValue& json_obj, const std::shared_ptr<Schema>& schema,
     ipc::DictionaryMemo* dict_memo, MemoryPool* pool);
 
 // NOTE: Doesn't work with dictionary arrays, use ReadRecordBatch instead.
 ARROW_EXPORT
-Result<std::shared_ptr<Array>> ReadArray(MemoryPool* pool, const rj::Value& 
json_obj,
+Result<std::shared_ptr<Array>> ReadArray(MemoryPool* pool, const JsonValue& 
json_obj,
                                          const std::shared_ptr<Field>& field);
 
 }  // namespace arrow::internal::integration::json
diff --git a/cpp/src/arrow/integration/meson.build 
b/cpp/src/arrow/integration/meson.build
index 17b6ea74495..ab0b3b3653f 100644
--- a/cpp/src/arrow/integration/meson.build
+++ b/cpp/src/arrow/integration/meson.build
@@ -20,12 +20,7 @@ install_headers(['json_integration.h'])
 exc = executable(
     'arrow-json-integration-test',
     sources: ['json_integration_test.cc'],
-    dependencies: [
-        arrow_test_dep_no_main,
-        rapidjson_dep,
-        simdjson_dep,
-        gflags_dep,
-    ],
+    dependencies: [arrow_test_dep_no_main, simdjson_dep, gflags_dep],
 )
 
 arrow_c_data_integration_lib = library(

Reply via email to