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

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


The following commit(s) were added to refs/heads/main by this push:
     new 3e02822  refactor: Improve syntax for implementing `ArrowArrayStream` 
from C++ (#336)
3e02822 is described below

commit 3e02822e232c10abe97f126165c4891f02706b4a
Author: Dewey Dunnington <[email protected]>
AuthorDate: Tue Dec 19 12:40:07 2023 -0400

    refactor: Improve syntax for implementing `ArrowArrayStream` from C++ (#336)
    
    An early commit implemented `nanoarrow::EmptyArrayStream` and
    `nanoarrow::VectorArrayStream` in the nanoarrow.hpp C++ helpers. The
    intention at the time was to make it "easy"/idiomatic to use a C++
    object to back an `ArrowArrayStream`; however, it was in practice
    difficult to actually make work (I tried briefly and gave up when
    writing a [dummy ADBC
    
driver](https://github.com/voltrondata-labs/blog-posts-code/blob/main/2023-08-nanoarrow-adbc/simple_csv_reader.cc#L52-L177)
    for [this blog
    
post](https://voltrondata.com/resources/nanoarrow-lightweight-embeddable-arrow-implementation-data-pipelines).
    
    This PR deprecates the original syntax and migrates it to the following.
    
    Implementation:
    
    ```cpp
    class StreamImpl {
     public:
      // Public methods (e.g., constructor) used from C++ to initialize 
relevant data
    
      // Idiomatic exporter to move data + lifecycle responsibility to an 
instance
      // managed by the ArrowArrayStream callbacks
      void ToArrayStream(struct ArrowArrayStream* out) {
        ArrayStreamFactory<StreamImpl>::InitArrayStream(new StreamImpl(...), 
out);
      }
    
     private:
      // Make relevant methods available to the ArrayStreamFactory
      friend class ArrayStreamFactory<StreamImpl>;
    
      // Method implementations (called from C, not normally interacted with 
from C++)
      int GetSchema(struct ArrowSchema* schema) { return ENOTSUP; }
      int GetNext(struct ArrowArray* array) { return ENOTSUP; }
      const char* GetLastError() { nullptr; }
    };
    ```
    
    Usage:
    
    ```cpp
    // Call constructor and/or public methods to initialize relevant data
    StreamImpl impl;
    
    // Export to ArrowArrayStream after data are finalized
    UniqueArrayStream stream;
    impl.ToArrayStream(stream.get());
    ```
    
    I'm open to suggestions on how to make that better! It might be that the
    `ToArrayStream()` bit is confusing (i.e., just use
    `ArrayStreamFactory<>::InitArrayStream(new StreamImpl())` directory) but
    it also seemed better to keep the lines where a raw pointer was floating
    around to be entirely contained within the `StreamImpl` class.
    
    It also fixes an issue with the `XXX_pointer()` functions, which because
    of the way they were declared, required that `nanoarrow.hpp` be
    confusingly included *after* `nanoarrow_ipc.hpp`. The correct way to do
    this (I think) was to declare the template and add implementations
    (rather than use overloads).
---
 .../nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc.hpp  |  28 ++-
 src/nanoarrow/nanoarrow.hpp                        | 278 ++++++++++++++++-----
 src/nanoarrow/nanoarrow_hpp_test.cc                |  25 +-
 3 files changed, 242 insertions(+), 89 deletions(-)

diff --git a/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc.hpp 
b/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc.hpp
index 505f827..e52fddb 100644
--- a/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc.hpp
+++ b/extensions/nanoarrow_ipc/src/nanoarrow/nanoarrow_ipc.hpp
@@ -15,40 +15,46 @@
 // specific language governing permissions and limitations
 // under the License.
 
-#include "nanoarrow_ipc.h"
-
 #ifndef NANOARROW_IPC_HPP_INCLUDED
 #define NANOARROW_IPC_HPP_INCLUDED
 
+#include "nanoarrow.hpp"
+#include "nanoarrow_ipc.h"
+
 namespace nanoarrow {
 
 namespace internal {
 
-static inline void init_pointer(struct ArrowIpcDecoder* data) {
+template <>
+inline void init_pointer(struct ArrowIpcDecoder* data) {
   data->private_data = nullptr;
 }
 
-static inline void move_pointer(struct ArrowIpcDecoder* src,
-                                struct ArrowIpcDecoder* dst) {
+template <>
+inline void move_pointer(struct ArrowIpcDecoder* src, struct ArrowIpcDecoder* 
dst) {
   memcpy(dst, src, sizeof(struct ArrowIpcDecoder));
   src->private_data = nullptr;
 }
 
-static inline void release_pointer(struct ArrowIpcDecoder* data) {
+template <>
+inline void release_pointer(struct ArrowIpcDecoder* data) {
   ArrowIpcDecoderReset(data);
 }
 
-static inline void init_pointer(struct ArrowIpcInputStream* data) {
+template <>
+inline void init_pointer(struct ArrowIpcInputStream* data) {
   data->release = nullptr;
 }
 
-static inline void move_pointer(struct ArrowIpcInputStream* src,
-                                struct ArrowIpcInputStream* dst) {
+template <>
+inline void move_pointer(struct ArrowIpcInputStream* src,
+                         struct ArrowIpcInputStream* dst) {
   memcpy(dst, src, sizeof(struct ArrowIpcInputStream));
   src->release = nullptr;
 }
 
-static inline void release_pointer(struct ArrowIpcInputStream* data) {
+template <>
+inline void release_pointer(struct ArrowIpcInputStream* data) {
   if (data->release != nullptr) {
     data->release(data);
   }
@@ -57,8 +63,6 @@ static inline void release_pointer(struct 
ArrowIpcInputStream* data) {
 }  // namespace internal
 }  // namespace nanoarrow
 
-#include "nanoarrow.hpp"
-
 namespace nanoarrow {
 
 namespace ipc {
diff --git a/src/nanoarrow/nanoarrow.hpp b/src/nanoarrow/nanoarrow.hpp
index 2638769..15914ce 100644
--- a/src/nanoarrow/nanoarrow.hpp
+++ b/src/nanoarrow/nanoarrow.hpp
@@ -88,70 +88,108 @@ namespace internal {
 ///
 /// @{
 
-static inline void init_pointer(struct ArrowSchema* data) { data->release = 
nullptr; }
+template <typename T>
+static inline void init_pointer(T* data);
+
+template <typename T>
+static inline void move_pointer(T* src, T* dst);
+
+template <typename T>
+static inline void release_pointer(T* data);
+
+template <>
+inline void init_pointer(struct ArrowSchema* data) {
+  data->release = nullptr;
+}
 
-static inline void move_pointer(struct ArrowSchema* src, struct ArrowSchema* 
dst) {
+template <>
+inline void move_pointer(struct ArrowSchema* src, struct ArrowSchema* dst) {
   ArrowSchemaMove(src, dst);
 }
 
-static inline void release_pointer(struct ArrowSchema* data) {
+template <>
+inline void release_pointer(struct ArrowSchema* data) {
   if (data->release != nullptr) {
     data->release(data);
   }
 }
 
-static inline void init_pointer(struct ArrowArray* data) { data->release = 
nullptr; }
+template <>
+inline void init_pointer(struct ArrowArray* data) {
+  data->release = nullptr;
+}
 
-static inline void move_pointer(struct ArrowArray* src, struct ArrowArray* 
dst) {
+template <>
+inline void move_pointer(struct ArrowArray* src, struct ArrowArray* dst) {
   ArrowArrayMove(src, dst);
 }
 
-static inline void release_pointer(struct ArrowArray* data) {
+template <>
+inline void release_pointer(struct ArrowArray* data) {
   if (data->release != nullptr) {
     data->release(data);
   }
 }
 
-static inline void init_pointer(struct ArrowArrayStream* data) {
+template <>
+inline void init_pointer(struct ArrowArrayStream* data) {
   data->release = nullptr;
 }
 
-static inline void move_pointer(struct ArrowArrayStream* src,
-                                struct ArrowArrayStream* dst) {
+template <>
+inline void move_pointer(struct ArrowArrayStream* src, struct 
ArrowArrayStream* dst) {
   ArrowArrayStreamMove(src, dst);
 }
 
-static inline void release_pointer(ArrowArrayStream* data) {
+template <>
+inline void release_pointer(ArrowArrayStream* data) {
   if (data->release != nullptr) {
     data->release(data);
   }
 }
 
-static inline void init_pointer(struct ArrowBuffer* data) { 
ArrowBufferInit(data); }
+template <>
+inline void init_pointer(struct ArrowBuffer* data) {
+  ArrowBufferInit(data);
+}
 
-static inline void move_pointer(struct ArrowBuffer* src, struct ArrowBuffer* 
dst) {
+template <>
+inline void move_pointer(struct ArrowBuffer* src, struct ArrowBuffer* dst) {
   ArrowBufferMove(src, dst);
 }
 
-static inline void release_pointer(struct ArrowBuffer* data) { 
ArrowBufferReset(data); }
+template <>
+inline void release_pointer(struct ArrowBuffer* data) {
+  ArrowBufferReset(data);
+}
 
-static inline void init_pointer(struct ArrowBitmap* data) { 
ArrowBitmapInit(data); }
+template <>
+inline void init_pointer(struct ArrowBitmap* data) {
+  ArrowBitmapInit(data);
+}
 
-static inline void move_pointer(struct ArrowBitmap* src, struct ArrowBitmap* 
dst) {
+template <>
+inline void move_pointer(struct ArrowBitmap* src, struct ArrowBitmap* dst) {
   ArrowBitmapMove(src, dst);
 }
 
-static inline void release_pointer(struct ArrowBitmap* data) { 
ArrowBitmapReset(data); }
+template <>
+inline void release_pointer(struct ArrowBitmap* data) {
+  ArrowBitmapReset(data);
+}
 
-static inline void init_pointer(struct ArrowArrayView* data) {
+template <>
+inline void init_pointer(struct ArrowArrayView* data) {
   ArrowArrayViewInitFromType(data, NANOARROW_TYPE_UNINITIALIZED);
 }
 
-static inline void move_pointer(struct ArrowArrayView* src, struct 
ArrowArrayView* dst) {
+template <>
+inline void move_pointer(struct ArrowArrayView* src, struct ArrowArrayView* 
dst) {
   ArrowArrayViewMove(src, dst);
 }
 
-static inline void release_pointer(struct ArrowArrayView* data) {
+template <>
+inline void release_pointer(struct ArrowArrayView* data) {
   ArrowArrayViewReset(data);
 }
 
@@ -231,28 +269,124 @@ using UniqueArrayView = internal::Unique<struct 
ArrowArrayView>;
 
 /// \defgroup nanoarrow_hpp-array-stream ArrayStream helpers
 ///
-/// These classes provide simple struct ArrowArrayStream implementations that
+/// These classes provide simple ArrowArrayStream implementations that
 /// can be extended to help simplify the process of creating a valid
 /// ArrowArrayStream implementation or used as-is for testing.
 ///
 /// @{
 
+/// @brief Export an ArrowArrayStream from a standard C++ class
+/// @tparam T A class with methods `int GetSchema(ArrowSchema*)`, `int
+/// GetNext(ArrowArray*)`, and `const char* GetLastError()`
+///
+/// This class allows a standard C++ class to be exported to a generic 
ArrowArrayStream
+/// consumer by mapping C callback invocations to method calls on an instance 
of the
+/// object whose lifecycle is owned by the ArrowArrayStream. See 
VectorArrayStream for
+/// minimal useful example of this pattern.
+///
+/// The methods must be accessible to the ArrayStreamFactory, either as public 
methods or
+/// by declaring ArrayStreamFactory<ImplClass> a friend. Implementors are 
encouraged (but
+/// not required) to implement a ToArrayStream(ArrowArrayStream*) that creates 
a new
+/// instance owned by the ArrowArrayStream and moves the relevant data to that 
instance.
+///
+/// An example implementation might be:
+///
+/// \code
+/// class StreamImpl {
+///  public:
+///   // Public methods (e.g., constructor) used from C++ to initialize 
relevant data
+///
+///   // Idiomatic exporter to move data + lifecycle responsibility to an 
instance
+///   // managed by the ArrowArrayStream callbacks
+///   void ToArrayStream(struct ArrowArrayStream* out) {
+///     ArrayStreamFactory<StreamImpl>::InitArrayStream(new StreamImpl(...), 
out);
+///   }
+///
+///  private:
+///   // Make relevant methods available to the ArrayStreamFactory
+///   friend class ArrayStreamFactory<StreamImpl>;
+///
+///   // Method implementations (called from C, not normally interacted with 
from C++)
+///   int GetSchema(struct ArrowSchema* schema) { return ENOTSUP; }
+///   int GetNext(struct ArrowArray* array) { return ENOTSUP; }
+///   const char* GetLastError() { nullptr; }
+/// };
+/// \endcode
+///
+/// An example usage might be:
+///
+/// \code
+/// // Call constructor and/or public methods to initialize relevant data
+/// StreamImpl impl;
+///
+/// // Export to ArrowArrayStream after data are finalized
+/// UniqueArrayStream stream;
+/// impl.ToArrayStream(stream.get());
+/// \endcode
+template <typename T>
+class ArrayStreamFactory {
+ public:
+  /// \brief Take ownership of instance and populate callbacks of out
+  static void InitArrayStream(T* instance, struct ArrowArrayStream* out) {
+    out->get_schema = &get_schema_wrapper;
+    out->get_next = &get_next_wrapper;
+    out->get_last_error = &get_last_error_wrapper;
+    out->release = &release_wrapper;
+    out->private_data = instance;
+  }
+
+ private:
+  static int get_schema_wrapper(struct ArrowArrayStream* stream,
+                                struct ArrowSchema* schema) {
+    return reinterpret_cast<T*>(stream->private_data)->GetSchema(schema);
+  }
+
+  static int get_next_wrapper(struct ArrowArrayStream* stream, struct 
ArrowArray* array) {
+    return reinterpret_cast<T*>(stream->private_data)->GetNext(array);
+  }
+
+  static const char* get_last_error_wrapper(struct ArrowArrayStream* stream) {
+    return reinterpret_cast<T*>(stream->private_data)->GetLastError();
+  }
+
+  static void release_wrapper(struct ArrowArrayStream* stream) {
+    delete reinterpret_cast<T*>(stream->private_data);
+    stream->release = nullptr;
+    stream->private_data = nullptr;
+  }
+};
+
 /// \brief An empty array stream
 ///
-/// This class can be constructed from an enum ArrowType or
-/// struct ArrowSchema and implements a default get_next() method that
-/// always marks the output ArrowArray as released. This class can
-/// be extended with an implementation of get_next() for a custom
-/// source.
+/// This class can be constructed from an struct ArrowSchema and implements a 
default
+/// get_next() method that always marks the output ArrowArray as released.
+///
+/// DEPRECATED (0.4.0): Early versions of nanoarrow allowed subclasses to 
override
+/// get_schema(), get_next(), and get_last_error(). This functionality will be 
removed
+/// in a future release: use the pattern documented in ArrayStreamFactory to 
create
+/// custom ArrowArrayStream implementations.
 class EmptyArrayStream {
  public:
+  /// \brief Create an EmptyArrayStream from an ArrowSchema
+  ///
+  /// Takes ownership of schema.
+  EmptyArrayStream(struct ArrowSchema* schema) : schema_(schema) {
+    ArrowErrorInit(&error_);
+  }
+
+  /// \brief Export to ArrowArrayStream
+  void ToArrayStream(struct ArrowArrayStream* out) {
+    EmptyArrayStream* impl = new EmptyArrayStream(schema_.get());
+    ArrayStreamFactory<EmptyArrayStream>::InitArrayStream(impl, out);
+  }
+
   /// \brief Create an empty UniqueArrayStream from a struct ArrowSchema
   ///
-  /// This object takes ownership of the schema and marks the source schema
-  /// as released.
+  /// DEPRECATED (0.4.0): Use the constructor + ToArrayStream() to export an
+  /// EmptyArrayStream to an ArrowArrayStream consumer.
   static UniqueArrayStream MakeUnique(struct ArrowSchema* schema) {
     UniqueArrayStream stream;
-    (new EmptyArrayStream(schema))->MakeStream(stream.get());
+    EmptyArrayStream(schema).ToArrayStream(stream.get());
     return stream;
   }
 
@@ -262,17 +396,7 @@ class EmptyArrayStream {
   UniqueSchema schema_;
   struct ArrowError error_;
 
-  EmptyArrayStream(struct ArrowSchema* schema) : schema_(schema) {
-    error_.message[0] = '\0';
-  }
-
-  void MakeStream(struct ArrowArrayStream* stream) {
-    stream->get_schema = &get_schema_wrapper;
-    stream->get_next = &get_next_wrapper;
-    stream->get_last_error = &get_last_error_wrapper;
-    stream->release = &release_wrapper;
-    stream->private_data = this;
-  }
+  void MakeStream(struct ArrowArrayStream* stream) { ToArrayStream(stream); }
 
   virtual int get_schema(struct ArrowSchema* schema) {
     return ArrowSchemaDeepCopy(schema_.get(), schema);
@@ -286,54 +410,72 @@ class EmptyArrayStream {
   virtual const char* get_last_error() { return error_.message; }
 
  private:
-  static int get_schema_wrapper(struct ArrowArrayStream* stream,
-                                struct ArrowSchema* schema) {
-    return 
reinterpret_cast<EmptyArrayStream*>(stream->private_data)->get_schema(schema);
-  }
+  friend class ArrayStreamFactory<EmptyArrayStream>;
 
-  static int get_next_wrapper(struct ArrowArrayStream* stream, struct 
ArrowArray* array) {
-    return 
reinterpret_cast<EmptyArrayStream*>(stream->private_data)->get_next(array);
-  }
+  int GetSchema(struct ArrowSchema* schema) { return get_schema(schema); }
 
-  static const char* get_last_error_wrapper(struct ArrowArrayStream* stream) {
-    return 
reinterpret_cast<EmptyArrayStream*>(stream->private_data)->get_last_error();
-  }
+  int GetNext(struct ArrowArray* array) { return get_next(array); }
 
-  static void release_wrapper(struct ArrowArrayStream* stream) {
-    delete reinterpret_cast<EmptyArrayStream*>(stream->private_data);
-    stream->release = nullptr;
-    stream->private_data = nullptr;
-  }
+  const char* GetLastError() { return get_last_error(); }
 };
 
-/// \brief Implementation of an ArrowArrayStream backed by a vector of 
ArrowArray objects
-class VectorArrayStream : public EmptyArrayStream {
+/// \brief Implementation of an ArrowArrayStream backed by a vector of 
UniqueArray objects
+class VectorArrayStream {
  public:
+  /// \brief Create a VectorArrayStream from an ArrowSchema + vector of 
UniqueArray
+  ///
+  /// Takes ownership of schema and moves arrays if possible.
+  VectorArrayStream(struct ArrowSchema* schema, std::vector<UniqueArray> 
arrays)
+      : offset_(0), schema_(schema), arrays_(std::move(arrays)) {}
+
+  /// \brief Create a one-shot VectorArrayStream from an ArrowSchema + 
ArrowArray
+  ///
+  /// Takes ownership of schema and array.
+  VectorArrayStream(struct ArrowSchema* schema, struct ArrowArray* array)
+      : offset_(0), schema_(schema) {
+    arrays_.emplace_back(array);
+  }
+
+  /// \brief Export to ArrowArrayStream
+  void ToArrayStream(struct ArrowArrayStream* out) {
+    VectorArrayStream* impl = new VectorArrayStream(schema_.get(), 
std::move(arrays_));
+    ArrayStreamFactory<VectorArrayStream>::InitArrayStream(impl, out);
+  }
+
   /// \brief Create a UniqueArrowArrayStream from an existing array
   ///
-  /// Takes ownership of the schema and the array.
+  /// DEPRECATED (0.4.0): Use the constructors + ToArrayStream() to export a
+  /// VectorArrayStream to an ArrowArrayStream consumer.
   static UniqueArrayStream MakeUnique(struct ArrowSchema* schema,
                                       struct ArrowArray* array) {
-    std::vector<UniqueArray> arrays;
-    arrays.emplace_back(array);
-    return MakeUnique(schema, std::move(arrays));
+    UniqueArrayStream stream;
+    VectorArrayStream(schema, array).ToArrayStream(stream.get());
+    return stream;
   }
 
   /// \brief Create a UniqueArrowArrayStream from existing arrays
   ///
-  /// This object takes ownership of the schema and arrays.
+  /// DEPRECATED (0.4.0): Use the constructor + ToArrayStream() to export a
+  /// VectorArrayStream to an ArrowArrayStream consumer.
   static UniqueArrayStream MakeUnique(struct ArrowSchema* schema,
                                       std::vector<UniqueArray> arrays) {
     UniqueArrayStream stream;
-    (new VectorArrayStream(schema, 
std::move(arrays)))->MakeStream(stream.get());
+    VectorArrayStream(schema, std::move(arrays)).ToArrayStream(stream.get());
     return stream;
   }
 
- protected:
-  VectorArrayStream(struct ArrowSchema* schema, std::vector<UniqueArray> 
arrays)
-      : EmptyArrayStream(schema), arrays_(std::move(arrays)), offset_(0) {}
+ private:
+  int64_t offset_;
+  UniqueSchema schema_;
+  std::vector<UniqueArray> arrays_;
+
+  friend class ArrayStreamFactory<VectorArrayStream>;
 
-  int get_next(struct ArrowArray* array) {
+  int GetSchema(struct ArrowSchema* schema) {
+    return ArrowSchemaDeepCopy(schema_.get(), schema);
+  }
+
+  int GetNext(struct ArrowArray* array) {
     if (offset_ < static_cast<int64_t>(arrays_.size())) {
       arrays_[offset_++].move(array);
     } else {
@@ -343,9 +485,7 @@ class VectorArrayStream : public EmptyArrayStream {
     return NANOARROW_OK;
   }
 
- private:
-  std::vector<UniqueArray> arrays_;
-  int64_t offset_;
+  const char* GetLastError() { return ""; }
 };
 
 /// @}
diff --git a/src/nanoarrow/nanoarrow_hpp_test.cc 
b/src/nanoarrow/nanoarrow_hpp_test.cc
index 5eef4d5..fd6733c 100644
--- a/src/nanoarrow/nanoarrow_hpp_test.cc
+++ b/src/nanoarrow/nanoarrow_hpp_test.cc
@@ -191,7 +191,9 @@ TEST(NanoarrowHppTest, NanoarrowHppEmptyArrayStreamTest) {
 
   nanoarrow::UniqueSchema schema_in;
   EXPECT_EQ(ArrowSchemaInitFromType(schema_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
-  auto array_stream = nanoarrow::EmptyArrayStream::MakeUnique(schema_in.get());
+
+  nanoarrow::UniqueArrayStream array_stream;
+  
nanoarrow::EmptyArrayStream(schema_in.get()).ToArrayStream(array_stream.get());
 
   EXPECT_EQ(array_stream->get_schema(array_stream.get(), schema.get()), 
NANOARROW_OK);
   EXPECT_STREQ(schema->format, "i");
@@ -201,10 +203,6 @@ TEST(NanoarrowHppTest, NanoarrowHppEmptyArrayStreamTest) {
 }
 
 TEST(NanoarrowHppTest, NanoarrowHppVectorArrayStreamTest) {
-  nanoarrow::UniqueSchema schema;
-  nanoarrow::UniqueArray array;
-  nanoarrow::UniqueArrayView array_view;
-
   nanoarrow::UniqueArray array_in;
   EXPECT_EQ(ArrowArrayInitFromType(array_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
   EXPECT_EQ(ArrowArrayStartAppending(array_in.get()), NANOARROW_OK);
@@ -214,15 +212,26 @@ TEST(NanoarrowHppTest, NanoarrowHppVectorArrayStreamTest) 
{
   nanoarrow::UniqueSchema schema_in;
   EXPECT_EQ(ArrowSchemaInitFromType(schema_in.get(), NANOARROW_TYPE_INT32), 
NANOARROW_OK);
 
-  auto array_stream =
-      nanoarrow::VectorArrayStream::MakeUnique(schema_in.get(), 
array_in.get());
+  nanoarrow::UniqueArrayStream array_stream;
+  nanoarrow::VectorArrayStream(schema_in.get(), array_in.get())
+      .ToArrayStream(array_stream.get());
+
+  nanoarrow::UniqueSchema schema;
+  ASSERT_EQ(array_stream->get_schema(array_stream.get(), schema.get()), 
NANOARROW_OK);
+
+  nanoarrow::UniqueArrayView array_view;
+  ASSERT_EQ(ArrowArrayViewInitFromSchema(array_view.get(), schema.get(), 
nullptr),
+            NANOARROW_OK);
 
+  nanoarrow::UniqueArray array;
   EXPECT_EQ(array_stream->get_next(array_stream.get(), array.get()), 
NANOARROW_OK);
-  ArrowArrayViewInitFromType(array_view.get(), NANOARROW_TYPE_INT32);
+
   ASSERT_EQ(ArrowArrayViewSetArray(array_view.get(), array.get(), nullptr), 
NANOARROW_OK);
   EXPECT_EQ(ArrowArrayViewGetIntUnsafe(array_view.get(), 0), 1234);
   array.reset();
 
   EXPECT_EQ(array_stream->get_next(array_stream.get(), array.get()), 
NANOARROW_OK);
   EXPECT_EQ(array->release, nullptr);
+
+  EXPECT_STREQ(array_stream->get_last_error(array_stream.get()), "");
 }

Reply via email to