Skip to content

Commit acfc939

Browse files
committed
Add binding validations for passing std::any around
1 parent c9c887c commit acfc939

14 files changed

Lines changed: 176 additions & 31 deletions

File tree

c_glib/arrow-glib/file-system.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,42 @@ garrow_file_system_create(const gchar *uri, GError **error)
640640
}
641641
}
642642

643+
/**
644+
* garrow_file_system_example_accept_options:
645+
* @string_value: A string option value.
646+
* @int_value: An integer option value.
647+
* @typed_value: An integer used to build a typed option value.
648+
* @error: (nullable): Return location for a #GError or %NULL.
649+
*
650+
* This is a showcase demonstrating that backend-specific options, stored
651+
* as `std::any` in #arrow::fs::FileSystemFactoryOptions, can be built from
652+
* the C GLib bindings and consumed by Arrow C++.
653+
*
654+
* Returns: (nullable) (transfer full): A string describing the options
655+
* received by Arrow C++, or %NULL on error.
656+
*
657+
* Since: 25.0.0
658+
*/
659+
gchar *
660+
garrow_file_system_example_accept_options(const gchar *string_value,
661+
gint int_value,
662+
gint typed_value,
663+
GError **error)
664+
{
665+
arrow::fs::FileSystemFactoryOptions options = {
666+
{"example_option_string", std::any{std::string(string_value)}},
667+
{"example_option_int", std::any{static_cast<int>(int_value)}},
668+
{"example_option_typed_var",
669+
std::any{arrow::fs::ExampleOption(static_cast<int>(typed_value))}},
670+
};
671+
auto result = arrow::fs::ExampleAcceptOptions(options);
672+
if (garrow::check(error, result, "[file-system][example-accept-options]")) {
673+
return g_strdup(result->c_str());
674+
} else {
675+
return NULL;
676+
}
677+
}
678+
643679
/**
644680
* garrow_file_system_get_type_name:
645681
* @file_system: A #GArrowFileSystem.

c_glib/arrow-glib/file-system.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,13 @@ struct _GArrowFileSystemClass
100100
GObjectClass parent_class;
101101
};
102102

103+
GARROW_AVAILABLE_IN_25_0
104+
gchar *
105+
garrow_file_system_example_accept_options(const gchar *string_value,
106+
gint int_value,
107+
gint typed_value,
108+
GError **error);
109+
103110
GARROW_AVAILABLE_IN_3_0
104111
GArrowFileSystem *
105112
garrow_file_system_create(const gchar *uri, GError **error);

c_glib/test/test-mock-file-system.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@ def setup
2727
def test_type_name
2828
assert_equal("mock", @fs.type_name)
2929
end
30+
31+
def test_example_accept_options
32+
assert_equal("example_option_string=str(hi);" +
33+
"example_option_int=int(42);" +
34+
"example_option_typed_var=typed(7);",
35+
Arrow::FileSystem.example_accept_options("hi", 42, 7))
36+
end
3037
end

cpp/src/arrow/filesystem/filesystem.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,23 @@ Result<std::shared_ptr<FileSystem>> FileSystemFromUriReal(
964964

965965
} // namespace
966966

967+
Result<std::string> ExampleAcceptOptions(const FileSystemFactoryOptions& options) {
968+
if (options.empty()) return Status::Invalid("no options");
969+
std::string out;
970+
for (const auto& [key, value] : options) {
971+
if (const auto* s = std::any_cast<std::string>(&value)) {
972+
out += key + "=str(" + *s + ");";
973+
} else if (const auto* i = std::any_cast<int>(&value)) {
974+
out += key + "=int(" + std::to_string(*i) + ");";
975+
} else if (const auto* t = std::any_cast<ExampleOption>(&value)) {
976+
out += key + "=typed(" + std::to_string(t->value()) + ");";
977+
} else {
978+
return Status::Invalid("option '", key, "' has unsupported type");
979+
}
980+
}
981+
return out;
982+
}
983+
967984
Result<std::shared_ptr<FileSystem>> FileSystemFromUri(const std::string& uri_string,
968985
std::string* out_path) {
969986
return FileSystemFromUriAndOptions(uri_string, /*options=*/{}, io::default_io_context(),

cpp/src/arrow/filesystem/filesystem.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,18 @@ class ARROW_EXPORT FileSystem
361361

362362
using FileSystemFactoryOptions = std::vector<std::pair<std::string, std::any>>;
363363

364+
class ARROW_EXPORT ExampleOption {
365+
public:
366+
explicit ExampleOption(int value) : value_(value) {}
367+
int value() const { return value_; }
368+
369+
private:
370+
int value_;
371+
};
372+
373+
ARROW_EXPORT
374+
Result<std::string> ExampleAcceptOptions(const FileSystemFactoryOptions& options);
375+
364376
struct FileSystemFactory {
365377
std::function<Result<std::shared_ptr<FileSystem>>(
366378
const Uri& uri, const FileSystemFactoryOptions& options,

python/pyarrow/_fs.pyx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,3 +1651,21 @@ def _copy_files_selector(FileSystem source_fs, FileSelector source_sel,
16511651
destination_fs.unwrap(), c_destination_base_dir,
16521652
c_default_io_context(), chunk_size, use_threads,
16531653
))
1654+
1655+
1656+
def _example_accept_options(str value, int value_int, int value_typed):
1657+
cdef:
1658+
CFSFileSystemFactoryOptions options
1659+
pair[c_string, c_any] entry
1660+
c_string result
1661+
entry.first = tobytes("example_option_string")
1662+
entry.second = <c_string>tobytes(value)
1663+
options.push_back(entry)
1664+
entry.first = tobytes("example_option_int")
1665+
entry.second = <int>value_int
1666+
options.push_back(entry)
1667+
entry.first = tobytes("example_option_typed_var")
1668+
entry.second = CExampleOption(value_typed)
1669+
options.push_back(entry)
1670+
result = GetResultValue(CExampleAcceptOptions(options))
1671+
return frombytes(result)

python/pyarrow/fs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
PyFileSystem,
3434
_copy_files,
3535
_copy_files_selector,
36+
_example_accept_options
3637
)
3738

3839
# For backward compatibility.

python/pyarrow/includes/common.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from libc.stdint cimport *
2121

2222
from libcpp cimport bool as c_bool, nullptr
23+
from libcpp.any cimport any as c_any
2324
from libcpp.functional cimport function
2425
from libcpp.memory cimport (shared_ptr, unique_ptr, make_shared,
2526
static_pointer_cast, dynamic_pointer_cast)

python/pyarrow/includes/libarrow_fs.pxd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ cdef extern from "arrow/filesystem/api.h" namespace "arrow::fs" nogil:
2929
CFileType_File "arrow::fs::FileType::File"
3030
CFileType_Directory "arrow::fs::FileType::Directory"
3131

32+
ctypedef vector[pair[c_string, c_any]] CFSFileSystemFactoryOptions "arrow::fs::FileSystemFactoryOptions"
33+
CResult[c_string] CExampleAcceptOptions "arrow::fs::ExampleAcceptOptions"(const CFSFileSystemFactoryOptions& options)
34+
cdef cppclass CExampleOption "arrow::fs::ExampleOption":
35+
CExampleOption(int value)
36+
int value() const
37+
3238
cdef cppclass CFileInfo "arrow::fs::FileInfo":
3339
CFileInfo()
3440
CFileInfo(CFileInfo)

python/pyarrow/tests/test_fs.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
from pyarrow.fs import (FileType, FileInfo, FileSelector, FileSystem,
3737
LocalFileSystem, SubTreeFileSystem, _MockFileSystem,
3838
FileSystemHandler, PyFileSystem, FSSpecHandler,
39-
copy_files)
39+
copy_files, _example_accept_options)
4040
from pyarrow.util import find_free_port
4141

4242

@@ -2285,3 +2285,10 @@ def test_huggingface_filesystem_from_uri():
22852285
expected_fs = PyFileSystem(FSSpecHandler(HfFileSystem()))
22862286
assert fs == expected_fs
22872287
assert path == "datasets/stanfordnlp/imdb/plain_text/train-00000-of-00001.parquet"
2288+
2289+
2290+
def test_example_accept_options():
2291+
result = _example_accept_options("hi", 42, 7)
2292+
expected = "example_option_string=str(hi);example_option_int=int(42);" + \
2293+
"example_option_typed_var=typed(7);"
2294+
assert result == expected

0 commit comments

Comments
 (0)