From 923a051ed013636301674105bb166c29bfa0f5e1 Mon Sep 17 00:00:00 2001 From: ump45nose <52391318+ump45nose@users.noreply.github.com> Date: Sat, 24 Oct 2026 13:09:19 +0800 Subject: [PATCH] feat(ipc): Support run-end encoded arrays in the IPC reader The IPC encoder already wrote the RunEndEncoded type, but the decoder rejected it with ENOTSUP. The RunEndEncoded type table has no parameters and the array has no buffers of its own, only the run_ends and values children, so map it to the "+r" format and let the existing child and buffer handling do the rest. Closes #833. --- src/nanoarrow/ipc/decoder.c | 19 +++++++++++++++++-- src/nanoarrow/ipc/decoder_test.cc | 4 ++++ src/nanoarrow/ipc/files_test.cc | 2 +- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/nanoarrow/ipc/decoder.c b/src/nanoarrow/ipc/decoder.c index e02390745..e47a652e4 100644 --- a/src/nanoarrow/ipc/decoder.c +++ b/src/nanoarrow/ipc/decoder.c @@ -1203,6 +1203,22 @@ static int ArrowIpcDecoderSetTypeUnion(struct ArrowSchema* schema, return ArrowIpcDecoderSetTypeSimpleNested(schema, union_types_str, error); } +static int ArrowIpcDecoderSetTypeRunEndEncoded(struct ArrowSchema* schema, + int64_t n_children, + struct ArrowError* error) { + // The RunEndEncoded type table has no parameters: the run ends and values + // types are carried by its two children (run_ends, then values) + if (n_children != 2) { + ArrowErrorSet(error, + "Expected RunEndEncoded field to have exactly two children but found " + "%" PRId64, + n_children); + return EINVAL; + } + + return ArrowIpcDecoderSetTypeSimpleNested(schema, "+r", error); +} + static int ArrowIpcDecoderSetType(struct ArrowSchema* schema, ns(Field_table_t) field, int64_t n_children, struct ArrowError* error) { ns(Type_union_type_t) type_type = ns(Field_type_type(field)); @@ -1266,8 +1282,7 @@ static int ArrowIpcDecoderSetType(struct ArrowSchema* schema, ns(Field_table_t) case ns(Type_Union): return ArrowIpcDecoderSetTypeUnion(schema, type, n_children, error); case ns(Type_RunEndEncoded): - ArrowErrorSet(error, "RunEndEncoded not yet supported in IPC reader"); - return ENOTSUP; + return ArrowIpcDecoderSetTypeRunEndEncoded(schema, n_children, error); default: ArrowErrorSet(error, "Unrecognized Field type with value %d", type_type); return EINVAL; diff --git a/src/nanoarrow/ipc/decoder_test.cc b/src/nanoarrow/ipc/decoder_test.cc index 8f89acc6f..17de84d44 100644 --- a/src/nanoarrow/ipc/decoder_test.cc +++ b/src/nanoarrow/ipc/decoder_test.cc @@ -2039,6 +2039,10 @@ INSTANTIATE_TEST_SUITE_P( arrow::dense_union({arrow::field("col1", arrow::int32()), arrow::field("col2", arrow::utf8())}, {126, 127}), + // Run-end encoded + arrow::run_end_encoded(arrow::int16(), arrow::utf8()), + arrow::run_end_encoded(arrow::int32(), arrow::int64()), + arrow::run_end_encoded(arrow::int64(), arrow::float64()), // Type with nested metadata arrow::list(arrow::field("some_custom_name", arrow::int32(), diff --git a/src/nanoarrow/ipc/files_test.cc b/src/nanoarrow/ipc/files_test.cc index cc15a5251..501b92495 100644 --- a/src/nanoarrow/ipc/files_test.cc +++ b/src/nanoarrow/ipc/files_test.cc @@ -620,7 +620,7 @@ INSTANTIATE_TEST_SUITE_P( TestFile::OK("cpp-21.0.0/generated_nested_dictionary.stream"), TestFile::NotSupported("cpp-21.0.0/generated_list_view.stream"), TestFile::NotSupported("cpp-21.0.0/generated_binary_view.stream"), - TestFile::NotSupported("cpp-21.0.0/generated_run_end_encoded.stream") + TestFile::OK("cpp-21.0.0/generated_run_end_encoded.stream") // Comment to keep line from wrapping ));