You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by yu...@apache.org on 2025/06/27 14:21:03 UTC
(opendal) branch perf-bindings-go updated: 1
This is an automated email from the ASF dual-hosted git repository.
yuchanns pushed a commit to branch perf-bindings-go
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/perf-bindings-go by this push:
new cbbe1f07b 1
cbbe1f07b is described below
commit cbbe1f07b1c0565e31950586d9495a8874d5af73
Author: Hanchin Hsieh <me...@yuchanns.xyz>
AuthorDate: Fri Jun 27 22:20:53 2025 +0800
1
---
bindings/go/Cargo.lock | 1990 ++++++++++++++++++++++
bindings/go/Cargo.toml | 43 +
bindings/go/Makefile | 12 +-
bindings/go/{go.mod => build.rs} | 16 +-
bindings/go/cbindgen.toml | 53 +
bindings/go/error.go | 13 +
bindings/go/ffi.go | 64 +
bindings/go/go.mod | 2 +-
bindings/go/go.sum | 4 +-
bindings/go/include/opendal.h | 162 ++
bindings/go/opendal.go | 36 +-
bindings/go/reader.go | 2 +-
bindings/go/src/error.rs | 75 +
bindings/go/{go.mod => src/lib.rs} | 23 +-
bindings/go/src/operator.rs | 173 ++
bindings/go/src/reader.rs | 77 +
bindings/go/src/result.rs | 53 +
bindings/go/src/types.rs | 99 ++
bindings/go/src/writer.rs | 101 ++
bindings/go/tests/behavior_tests/opendal_test.go | 12 +-
bindings/go/types.go | 7 +-
21 files changed, 2976 insertions(+), 41 deletions(-)
diff --git a/bindings/go/Cargo.lock b/bindings/go/Cargo.lock
new file mode 100644
index 000000000..1eed8f73f
--- /dev/null
+++ b/bindings/go/Cargo.lock
@@ -0,0 +1,1990 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "addr2line"
+version = "0.24.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+dependencies = [
+ "gimli",
+]
+
+[[package]]
+name = "adler2"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
+
+[[package]]
+name = "android-tzdata"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.98"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "backon"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "302eaff5357a264a2c42f127ecb8bac761cf99749fc3dc95677e2743991f99e7"
+dependencies = [
+ "fastrand",
+ "gloo-timers",
+ "tokio",
+]
+
+[[package]]
+name = "backtrace"
+version = "0.3.75"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
+dependencies = [
+ "addr2line",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "base64"
+version = "0.22.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
+
+[[package]]
+name = "bytes"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
+
+[[package]]
+name = "cbindgen"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
+dependencies = [
+ "clap",
+ "heck",
+ "indexmap",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn 1.0.109",
+ "tempfile",
+ "toml",
+]
+
+[[package]]
+name = "cc"
+version = "1.2.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
+dependencies = [
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "chrono"
+version = "0.4.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
+dependencies = [
+ "android-tzdata",
+ "iana-time-zone",
+ "num-traits",
+ "windows-link",
+]
+
+[[package]]
+name = "clap"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
+dependencies = [
+ "atty",
+ "bitflags 1.3.2",
+ "clap_lex",
+ "indexmap",
+ "strsim",
+ "termcolor",
+ "textwrap",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
+[[package]]
+name = "displaydoc"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
+dependencies = [
+ "libc",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "r-efi",
+ "wasi 0.14.2+wasi-0.2.4",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gimli"
+version = "0.31.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "gloo-timers"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "heck"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "http"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "http-body"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
+dependencies = [
+ "bytes",
+ "http",
+]
+
+[[package]]
+name = "http-body-util"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "http",
+ "http-body",
+ "pin-project-lite",
+]
+
+[[package]]
+name = "httparse"
+version = "1.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
+
+[[package]]
+name = "hyper"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
+dependencies = [
+ "bytes",
+ "futures-channel",
+ "futures-util",
+ "http",
+ "http-body",
+ "httparse",
+ "itoa",
+ "pin-project-lite",
+ "smallvec",
+ "tokio",
+ "want",
+]
+
+[[package]]
+name = "hyper-rustls"
+version = "0.27.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
+dependencies = [
+ "http",
+ "hyper",
+ "hyper-util",
+ "rustls",
+ "rustls-pki-types",
+ "tokio",
+ "tokio-rustls",
+ "tower-service",
+ "webpki-roots",
+]
+
+[[package]]
+name = "hyper-util"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "hyper",
+ "ipnet",
+ "libc",
+ "percent-encoding",
+ "pin-project-lite",
+ "socket2",
+ "tokio",
+ "tower-service",
+ "tracing",
+]
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.63"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "icu_collections"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
+dependencies = [
+ "displaydoc",
+ "potential_utf",
+ "yoke",
+ "zerofrom",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_locale_core"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
+dependencies = [
+ "displaydoc",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_normalizer_data",
+ "icu_properties",
+ "icu_provider",
+ "smallvec",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_normalizer_data"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
+
+[[package]]
+name = "icu_properties"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
+dependencies = [
+ "displaydoc",
+ "icu_collections",
+ "icu_locale_core",
+ "icu_properties_data",
+ "icu_provider",
+ "potential_utf",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "icu_properties_data"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
+
+[[package]]
+name = "icu_provider"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
+dependencies = [
+ "displaydoc",
+ "icu_locale_core",
+ "stable_deref_trait",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "zerofrom",
+ "zerotrie",
+ "zerovec",
+]
+
+[[package]]
+name = "idna"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+dependencies = [
+ "idna_adapter",
+ "smallvec",
+ "utf8_iter",
+]
+
+[[package]]
+name = "idna_adapter"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
+dependencies = [
+ "icu_normalizer",
+ "icu_properties",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "ipnet"
+version = "2.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
+
+[[package]]
+name = "iri-string"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "js-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.174"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
+
+[[package]]
+name = "litemap"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
+
+[[package]]
+name = "log"
+version = "0.4.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+
+[[package]]
+name = "lru-slab"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
+
+[[package]]
+name = "md-5"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
+dependencies = [
+ "cfg-if",
+ "digest",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
+dependencies = [
+ "adler2",
+]
+
+[[package]]
+name = "mio"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
+dependencies = [
+ "libc",
+ "wasi 0.11.1+wasi-snapshot-preview1",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "object"
+version = "0.36.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "opendal"
+version = "0.53.3"
+dependencies = [
+ "anyhow",
+ "backon",
+ "base64",
+ "bytes",
+ "chrono",
+ "futures",
+ "getrandom 0.2.16",
+ "http",
+ "http-body",
+ "log",
+ "md-5",
+ "percent-encoding",
+ "quick-xml",
+ "reqwest",
+ "serde",
+ "serde_json",
+ "tokio",
+ "uuid",
+]
+
+[[package]]
+name = "opendal-go"
+version = "0.0.0"
+dependencies = [
+ "bytes",
+ "cbindgen",
+ "opendal",
+ "tokio",
+]
+
+[[package]]
+name = "os_str_bytes"
+version = "6.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "potential_utf"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quick-xml"
+version = "0.37.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
+dependencies = [
+ "memchr",
+ "serde",
+]
+
+[[package]]
+name = "quinn"
+version = "0.11.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8"
+dependencies = [
+ "bytes",
+ "cfg_aliases",
+ "pin-project-lite",
+ "quinn-proto",
+ "quinn-udp",
+ "rustc-hash",
+ "rustls",
+ "socket2",
+ "thiserror",
+ "tokio",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-proto"
+version = "0.11.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e"
+dependencies = [
+ "bytes",
+ "getrandom 0.3.3",
+ "lru-slab",
+ "rand",
+ "ring",
+ "rustc-hash",
+ "rustls",
+ "rustls-pki-types",
+ "slab",
+ "thiserror",
+ "tinyvec",
+ "tracing",
+ "web-time",
+]
+
+[[package]]
+name = "quinn-udp"
+version = "0.5.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970"
+dependencies = [
+ "cfg_aliases",
+ "libc",
+ "once_cell",
+ "socket2",
+ "tracing",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
+dependencies = [
+ "getrandom 0.3.3",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.12.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eabf4c97d9130e2bf606614eb937e86edac8292eaa6f422f995d7e8de1eb1813"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http",
+ "http-body",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tokio-util",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+ "webpki-roots",
+]
+
+[[package]]
+name = "ring"
+version = "0.17.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
+dependencies = [
+ "cc",
+ "cfg-if",
+ "getrandom 0.2.16",
+ "libc",
+ "untrusted",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "rustc-demangle"
+version = "0.1.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
+
+[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
+name = "rustix"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
+dependencies = [
+ "bitflags 2.9.1",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "rustls"
+version = "0.23.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7160e3e10bf4535308537f3c4e1641468cd0e485175d6163087c0393c7d46643"
+dependencies = [
+ "once_cell",
+ "ring",
+ "rustls-pki-types",
+ "rustls-webpki",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-pki-types"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79"
+dependencies = [
+ "web-time",
+ "zeroize",
+]
+
+[[package]]
+name = "rustls-webpki"
+version = "0.103.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435"
+dependencies = [
+ "ring",
+ "rustls-pki-types",
+ "untrusted",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "slab"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "socket2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.104"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "sync_wrapper"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
+dependencies = [
+ "futures-core",
+]
+
+[[package]]
+name = "synstructure"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
+dependencies = [
+ "fastrand",
+ "getrandom 0.3.3",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
+
+[[package]]
+name = "thiserror"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "tinystr"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
+dependencies = [
+ "displaydoc",
+ "zerovec",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "tokio"
+version = "1.45.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
+dependencies = [
+ "backtrace",
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "tokio-rustls"
+version = "0.26.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
+dependencies = [
+ "rustls",
+ "tokio",
+]
+
+[[package]]
+name = "tokio-util"
+version = "0.7.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
+dependencies = [
+ "bytes",
+ "futures-core",
+ "futures-sink",
+ "pin-project-lite",
+ "tokio",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "tower"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
+dependencies = [
+ "futures-core",
+ "futures-util",
+ "pin-project-lite",
+ "sync_wrapper",
+ "tokio",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-http"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
+dependencies = [
+ "bitflags 2.9.1",
+ "bytes",
+ "futures-util",
+ "http",
+ "http-body",
+ "iri-string",
+ "pin-project-lite",
+ "tower",
+ "tower-layer",
+ "tower-service",
+]
+
+[[package]]
+name = "tower-layer"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
+
+[[package]]
+name = "tower-service"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
+
+[[package]]
+name = "tracing"
+version = "0.1.41"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
+dependencies = [
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "try-lock"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
+
+[[package]]
+name = "typenum"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
+[[package]]
+name = "url"
+version = "2.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "utf8_iter"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
+
+[[package]]
+name = "uuid"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
+dependencies = [
+ "getrandom 0.3.3",
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "want"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
+dependencies = [
+ "try-lock",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
+dependencies = [
+ "bumpalo",
+ "log",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.50"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "once_cell",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "wasm-streams"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "web-time"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webpki-roots"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8782dd5a41a24eed3a4f40b606249b3e236ca61adf1f25ea4d45c73de122b502"
+dependencies = [
+ "rustls-pki-types",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-core"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
+
+[[package]]
+name = "windows-result"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.2",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
+ "windows_i686_gnullvm 0.52.6",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
+dependencies = [
+ "windows_aarch64_gnullvm 0.53.0",
+ "windows_aarch64_msvc 0.53.0",
+ "windows_i686_gnu 0.53.0",
+ "windows_i686_gnullvm 0.53.0",
+ "windows_i686_msvc 0.53.0",
+ "windows_x86_64_gnu 0.53.0",
+ "windows_x86_64_gnullvm 0.53.0",
+ "windows_x86_64_msvc 0.53.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
+
+[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags 2.9.1",
+]
+
+[[package]]
+name = "writeable"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
+
+[[package]]
+name = "yoke"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+ "yoke-derive",
+ "zerofrom",
+]
+
+[[package]]
+name = "yoke-derive"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+ "synstructure",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
+
+[[package]]
+name = "zerofrom"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
+dependencies = [
+ "zerofrom-derive",
+]
+
+[[package]]
+name = "zerofrom-derive"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+ "synstructure",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
+
+[[package]]
+name = "zerotrie"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
+name = "zerovec"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
+dependencies = [
+ "yoke",
+ "zerofrom",
+ "zerovec-derive",
+]
+
+[[package]]
+name = "zerovec-derive"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.104",
+]
diff --git a/bindings/go/Cargo.toml b/bindings/go/Cargo.toml
new file mode 100644
index 000000000..15e36f649
--- /dev/null
+++ b/bindings/go/Cargo.toml
@@ -0,0 +1,43 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+[package]
+name = "opendal-go"
+publish = false
+
+authors = ["Apache OpenDAL <de...@opendal.apache.org>"]
+edition = "2021"
+homepage = "https://opendal.apache.org/"
+license = "Apache-2.0"
+repository = "https://github.com/apache/opendal"
+rust-version = "1.80"
+
+[lib]
+crate-type = ["cdylib", "staticlib"]
+doc = false
+
+[build-dependencies]
+cbindgen = "0.26.0"
+
+[dependencies]
+bytes = "1.4.0"
+# this crate won't be published, we always use the local version
+opendal = { version = ">=0", path = "../../core", features = ["blocking"] }
+tokio = { version = "1.27", features = ["fs", "macros", "rt-multi-thread"] }
+
+[features]
+default = []
diff --git a/bindings/go/Makefile b/bindings/go/Makefile
index 74e62df10..d4e0c2f5e 100644
--- a/bindings/go/Makefile
+++ b/bindings/go/Makefile
@@ -54,17 +54,17 @@ VERSION := latest
MATRIX := '{"build": [{"target":"$(OS)", "goos":"$(OS)", "goarch": "$(ARCH)"}], "service": ["$(SERVICE)"]}'
# Define library file paths
-C_LIB_FILE := opendal/bindings/c/target/debug/libopendal_c.$(LIB_EXT)
+C_LIB_FILE := opendal/bindings/go/target/debug/libopendal_go.$(LIB_EXT)
SERVICE_PKG := $(shell echo $(SERVICE) | tr '-' '_')
FINAL_LIB_FILE := $(GITHUB_WORKSPACE)/$(SERVICE_PKG)/libopendal_c.$(OS).$(ARCH).$(LIB_EXT).zst
# Build C library only when source files change
-$(C_LIB_FILE): opendal/bindings/c/src/*.rs opendal/bindings/c/Cargo.toml
+$(C_LIB_FILE): opendal/bindings/go/src/*.rs opendal/bindings/go/Cargo.toml
@echo "Building C library for service: $(SERVICE)"
- cd opendal/bindings/c && cargo build --features "opendal/services-$(shell echo $(SERVICE) | tr '_' '-')"
+ cd opendal/bindings/go && cargo build --features "opendal/services-$(shell echo $(SERVICE) | tr '_' '-')"
ifeq ($(OS),windows)
- @echo "Renaming opendal_c.$(LIB_EXT) to libopendal_c.$(LIB_EXT) on Windows"
- mv opendal/bindings/c/target/debug/opendal_c.$(LIB_EXT) opendal/bindings/c/target/debug/libopendal_c.$(LIB_EXT)
+ @echo "Renaming opendal_go.$(LIB_EXT) to libopendal_go.$(LIB_EXT) on Windows"
+ mv opendal/bindings/go/target/debug/opendal_go.$(LIB_EXT) opendal/bindings/go/target/debug/libopendal_go.$(LIB_EXT)
endif
# Create compressed library and generate Go services
@@ -151,7 +151,7 @@ tests: check-env run-tests
# Clean all generated files
clean:
@echo "Cleaning all generated files..."
- rm -rf opendal/bindings/c/target
+ rm -rf opendal/bindings/go/target
rm -rf opendal-go-services/*/libopendal_c.*
rm -rf opendal-go-services/*/opendal_c.*
rm -rf opendal-go-services/libopendal_c_*
diff --git a/bindings/go/go.mod b/bindings/go/build.rs
similarity index 77%
copy from bindings/go/go.mod
copy to bindings/go/build.rs
index 02eea0ae5..47b27812a 100644
--- a/bindings/go/go.mod
+++ b/bindings/go/build.rs
@@ -15,14 +15,14 @@
// specific language governing permissions and limitations
// under the License.
-module github.com/apache/opendal/bindings/go
+extern crate cbindgen;
-go 1.22.4
+use std::path::Path;
-toolchain go1.22.5
+fn main() {
+ let header_file = Path::new("include").join("opendal.h");
-require (
- github.com/ebitengine/purego v0.8.4
- github.com/jupiterrider/ffi v0.5.0
- golang.org/x/sys v0.24.0
-)
+ cbindgen::generate(".")
+ .expect("Unable to generate bindings")
+ .write_to_file(header_file);
+}
diff --git a/bindings/go/cbindgen.toml b/bindings/go/cbindgen.toml
new file mode 100644
index 000000000..66296943c
--- /dev/null
+++ b/bindings/go/cbindgen.toml
@@ -0,0 +1,53 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# See https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml
+# for detailed documentation of every option here.
+
+cpp_compat = true
+documentation_style = "doxy"
+header = """
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+"""
+include_guard = "_OPENDAL_H"
+language = "C"
+no_includes = true
+sys_includes = ["stdint.h", "stddef.h", "stdbool.h"]
+
+[parse]
+include = ["opendal"]
+parse_deps = true
+
+[fn]
+deprecated_with_note = "__attribute__((deprecated({})))"
diff --git a/bindings/go/error.go b/bindings/go/error.go
index 348fb58ef..7f37bbcc3 100644
--- a/bindings/go/error.go
+++ b/bindings/go/error.go
@@ -21,6 +21,7 @@ package opendal
import (
"fmt"
+ "unsafe"
)
// ErrorCode is all kinds of ErrorCode of opendal
@@ -82,3 +83,15 @@ func (e *Error) Code() ErrorCode {
func (e *Error) Message() string {
return e.message
}
+
+func parseError(e uintptr) error {
+ if e == 0 {
+ return nil
+ }
+ err := (*opendalError)(unsafe.Pointer(&e))
+ p := (*byte)(unsafe.Pointer(&err.message))
+ return &Error{
+ code: ErrorCode(err.code),
+ message: BytePtrToString(p),
+ }
+}
diff --git a/bindings/go/ffi.go b/bindings/go/ffi.go
new file mode 100644
index 000000000..aed60574a
--- /dev/null
+++ b/bindings/go/ffi.go
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package opendal
+
+import (
+ "reflect"
+
+ "github.com/ebitengine/purego"
+ "github.com/iancoleman/strcase"
+)
+
+type ffi struct {
+ OpendalOperatorNew func(scheme *byte, options uintptr) uintptr
+ OpendalOperatorFree func(op uintptr)
+
+ OpendalOperatorOptionsNew func() uintptr
+ OpendalOperatorOptionsFree func(options uintptr)
+ OpendalOperatorOptionsSet func(options uintptr, key *byte, value *byte)
+
+ OpendalWriterNew func(op uintptr, path *byte) uintptr
+ OpendalWriterFree func(writer uintptr)
+ OpendalWriterWrite func(writer uintptr, data *byte, size uintptr) uintptr
+ OpendalWriterClose func(writer uintptr) uintptr
+
+ OpendalReaderNew func(op uintptr, path *byte) uintptr
+ OpendalReaderFree func(reader uintptr)
+ OpendalReaderRead func(reader uintptr, data *byte, size uintptr) uintptr
+}
+
+func initFFI(path string) (f *ffi, err error) {
+ lib, err := LoadLibrary(path)
+ if err != nil {
+ return
+ }
+
+ f = &ffi{}
+
+ t := reflect.TypeOf(*f)
+ v := reflect.ValueOf(f).Elem()
+ for i := range t.NumField() {
+ symbol := strcase.ToSnake(t.Field(i).Name)
+ fieldAddr := v.Field(i).Addr().Interface()
+ purego.RegisterLibFunc(fieldAddr, lib, symbol)
+ }
+
+ return
+}
diff --git a/bindings/go/go.mod b/bindings/go/go.mod
index 02eea0ae5..62625ee8e 100644
--- a/bindings/go/go.mod
+++ b/bindings/go/go.mod
@@ -23,6 +23,6 @@ toolchain go1.22.5
require (
github.com/ebitengine/purego v0.8.4
- github.com/jupiterrider/ffi v0.5.0
+ github.com/iancoleman/strcase v0.3.0
golang.org/x/sys v0.24.0
)
diff --git a/bindings/go/go.sum b/bindings/go/go.sum
index 5fc43b052..c66908afb 100644
--- a/bindings/go/go.sum
+++ b/bindings/go/go.sum
@@ -1,6 +1,6 @@
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
-github.com/jupiterrider/ffi v0.5.0 h1:j2nSgpabbV1JOwgP4Kn449sJUHq3cVLAZVBoOYn44V8=
-github.com/jupiterrider/ffi v0.5.0/go.mod h1:x7xdNKo8h0AmLuXfswDUBxUsd2OqUP4ekC8sCnsmbvo=
+github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI=
+github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
diff --git a/bindings/go/include/opendal.h b/bindings/go/include/opendal.h
new file mode 100644
index 000000000..c0228bf20
--- /dev/null
+++ b/bindings/go/include/opendal.h
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+#ifndef _OPENDAL_H
+#define _OPENDAL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+/**
+ * \brief The configuration for the initialization of opendal_operator.
+ *
+ * \note This is also a heap-allocated struct, please free it after you use it
+ *
+ * @see opendal_operator_new has an example of using opendal_operator_options
+ * @see opendal_operator_options_new This function construct the operator
+ * @see opendal_operator_options_free This function frees the heap memory of the operator
+ * @see opendal_operator_options_set This function allow you to set the options
+ */
+typedef struct opendal_operator_options opendal_operator_options;
+
+typedef struct opendal_reader opendal_reader;
+
+/**
+ * \brief The result type returned by opendal_reader_read().
+ * The result type contains a size field, which is the size of the data read,
+ * which is zero on error. The error field is the error code and error message.
+ */
+typedef struct opendal_result_reader_read opendal_result_reader_read;
+
+/**
+ * \brief The result type returned by opendal_writer_write().
+ * The result type contains a size field, which is the size of the data written,
+ * which is zero on error. The error field is the error code and error message.
+ */
+typedef struct opendal_result_writer_write opendal_result_writer_write;
+
+/**
+ * \brief The result type returned by opendal's writer operation.
+ * \note The opendal_writer actually owns a pointer to
+ * an opendal::blocking::Writer, which is inside the Rust core code.
+ */
+typedef struct opendal_writer opendal_writer;
+
+/**
+ * \brief Used to access almost all OpenDAL APIs. It represents an
+ * operator that provides the unified interfaces provided by OpenDAL.
+ *
+ * @see opendal_operator_new This function construct the operator
+ * @see opendal_operator_free This function frees the heap memory of the operator
+ *
+ * \note The opendal_operator actually owns a pointer to
+ * an opendal::blocking::Operator, which is inside the Rust core code.
+ *
+ * \remark You may use the field `ptr` to check whether this is a NULL
+ * operator.
+ */
+typedef struct opendal_operator {
+ void *inner;
+ void *error;
+} opendal_operator;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+struct opendal_operator *opendal_operator_new(const char *scheme,
+ const struct opendal_operator_options *options);
+
+void opendal_operator_free(const struct opendal_operator *ptr);
+
+struct opendal_writer *opendal_writer_new(const struct opendal_operator *operator_,
+ const char *path);
+
+struct opendal_reader *opendal_reader_new(const struct opendal_operator *operator_,
+ const char *path);
+
+void opendal_reader_free(const struct opendal_reader *reader);
+
+struct opendal_result_reader_read *opendal_reader_read(struct opendal_reader *reader,
+ uint8_t *data,
+ uintptr_t len);
+
+/**
+ * \brief Free the result of opendal_writer_write().
+ */
+void opendal_result_writer_write_free(const struct opendal_result_writer_write *result);
+
+/**
+ * \brief Free the result of opendal_reader_read().
+ */
+void opendal_result_reader_read_free(const struct opendal_result_reader_read *result);
+
+/**
+ * \brief Construct a heap-allocated opendal_operator_options
+ *
+ * @return An empty opendal_operator_option, which could be set by
+ * opendal_operator_option_set().
+ *
+ * @see opendal_operator_option_set
+ */
+struct opendal_operator_options *opendal_operator_options_new(void);
+
+/**
+ * \brief Free the allocated memory used by [`opendal_operator_options`]
+ */
+void opendal_operator_options_free(struct opendal_operator_options *options);
+
+/**
+ * \brief Set a Key-Value pair inside opendal_operator_options
+ *
+ * # Safety
+ *
+ * This function is unsafe because it dereferences and casts the raw pointers
+ * Make sure the pointer of `key` and `value` point to a valid string.
+ *
+ * # Example
+ *
+ * ```C
+ * opendal_operator_options *options = opendal_operator_options_new();
+ * opendal_operator_options_set(options, "root", "/myroot");
+ *
+ * // .. use your opendal_operator_options
+ *
+ * opendal_operator_options_free(options);
+ * ```
+ */
+void opendal_operator_options_set(struct opendal_operator_options *options,
+ const char *key,
+ const char *value);
+
+void opendal_writer_free(const struct opendal_writer *writer);
+
+struct opendal_result_writer_write *opendal_writer_write(struct opendal_writer *writer,
+ const uint8_t *data,
+ uintptr_t size);
+
+struct opendal_result_writer_write *opendal_writer_close(struct opendal_writer *writer);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
+
+#endif /* _OPENDAL_H */
diff --git a/bindings/go/opendal.go b/bindings/go/opendal.go
index 3f345bbed..55331bf0b 100644
--- a/bindings/go/opendal.go
+++ b/bindings/go/opendal.go
@@ -58,7 +58,7 @@
package opendal
import (
- "context"
+ "unsafe"
)
// Scheme defines the interface for storage scheme implementations.
@@ -148,9 +148,9 @@ type OperatorOptions map[string]string
//
// Refer to the individual method documentation for detailed usage information.
type Operator struct {
- cancel context.CancelFunc
+ ffi *ffi
- inner *opendalOperator
+ inner uintptr
}
// NewOperator creates and initializes a new Operator for the specified storage scheme.
@@ -165,7 +165,33 @@ type Operator struct {
//
// Note: Remember to call Close() on the returned Operator when it's no longer needed.
func NewOperator(scheme Scheme, opts OperatorOptions) (op *Operator, err error) {
- panic("not implemented")
+ err = scheme.LoadOnce()
+ if err != nil {
+ return
+ }
+ ffi, err := initFFI(scheme.Path())
+ if err != nil {
+ return
+ }
+
+ options := ffi.OpendalOperatorOptionsNew()
+ for k, v := range opts {
+ ffi.OpendalOperatorOptionsSet(options, &[]byte(k)[0], &[]byte(v)[0])
+ }
+ defer ffi.OpendalOperatorOptionsFree(options)
+
+ inner := ffi.OpendalOperatorNew(&[]byte(scheme.Name())[0], options)
+ inner += 8
+ e := (*opendalError)(unsafe.Pointer(&inner))
+ if e != nil {
+ err = parseError(inner)
+ return
+ }
+ op = &Operator{
+ ffi: ffi,
+ inner: inner,
+ }
+ return
}
// Close releases all resources associated with the Operator.
@@ -175,5 +201,5 @@ func NewOperator(scheme Scheme, opts OperatorOptions) (op *Operator, err error)
//
// Note: It's recommended to use defer op.Close() immediately after creating an Operator.
func (op *Operator) Close() {
- panic("not implemented")
+ op.ffi.OpendalOperatorFree(op.inner)
}
diff --git a/bindings/go/reader.go b/bindings/go/reader.go
index 48ea30763..7b976018b 100644
--- a/bindings/go/reader.go
+++ b/bindings/go/reader.go
@@ -98,6 +98,7 @@ func (op *Operator) Read(path string) ([]byte, error) {
//
// Note: This example assumes proper error handling and import statements.
func (op *Operator) Reader(path string) (*Reader, error) {
+ op.ffi.OpendalReaderNew(op.inner, &[]byte(path)[0])
panic("not implemented")
}
@@ -200,4 +201,3 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
func (r *Reader) Close() error {
panic("not implemented")
}
-
diff --git a/bindings/go/src/error.rs b/bindings/go/src/error.rs
new file mode 100644
index 000000000..2c620eb2a
--- /dev/null
+++ b/bindings/go/src/error.rs
@@ -0,0 +1,75 @@
+use ::opendal as core;
+use std::ffi::c_char;
+
+/// \brief The error code for all opendal APIs in C binding.
+/// \todo The error handling is not complete, the error with error message will be
+/// added in the future.
+#[repr(C)]
+pub enum opendal_code {
+ /// returning it back. For example, s3 returns an internal service error.
+ OPENDAL_UNEXPECTED,
+ /// Underlying service doesn't support this operation.
+ OPENDAL_UNSUPPORTED,
+ /// The config for backend is invalid.
+ OPENDAL_CONFIG_INVALID,
+ /// The given path is not found.
+ OPENDAL_NOT_FOUND,
+ /// The given path doesn't have enough permission for this operation
+ OPENDAL_PERMISSION_DENIED,
+ /// The given path is a directory.
+ OPENDAL_IS_A_DIRECTORY,
+ /// The given path is not a directory.
+ OPENDAL_NOT_A_DIRECTORY,
+ /// The given path already exists thus we failed to the specified operation on it.
+ OPENDAL_ALREADY_EXISTS,
+ /// Requests that sent to this path is over the limit, please slow down.
+ OPENDAL_RATE_LIMITED,
+ /// The given file paths are same.
+ OPENDAL_IS_SAME_FILE,
+ /// The condition of this operation is not match.
+ OPENDAL_CONDITION_NOT_MATCH,
+ /// The range of the content is not satisfied.
+ OPENDAL_RANGE_NOT_SATISFIED,
+}
+
+impl From<core::ErrorKind> for opendal_code {
+ fn from(value: core::ErrorKind) -> Self {
+ match value {
+ core::ErrorKind::Unexpected => opendal_code::OPENDAL_UNEXPECTED,
+ core::ErrorKind::Unsupported => opendal_code::OPENDAL_UNSUPPORTED,
+ core::ErrorKind::ConfigInvalid => opendal_code::OPENDAL_CONFIG_INVALID,
+ core::ErrorKind::NotFound => opendal_code::OPENDAL_NOT_FOUND,
+ core::ErrorKind::PermissionDenied => opendal_code::OPENDAL_PERMISSION_DENIED,
+ core::ErrorKind::IsADirectory => opendal_code::OPENDAL_IS_A_DIRECTORY,
+ core::ErrorKind::NotADirectory => opendal_code::OPENDAL_NOT_A_DIRECTORY,
+ core::ErrorKind::AlreadyExists => opendal_code::OPENDAL_ALREADY_EXISTS,
+ core::ErrorKind::RateLimited => opendal_code::OPENDAL_RATE_LIMITED,
+ core::ErrorKind::IsSameFile => opendal_code::OPENDAL_IS_SAME_FILE,
+ core::ErrorKind::ConditionNotMatch => opendal_code::OPENDAL_CONDITION_NOT_MATCH,
+ core::ErrorKind::RangeNotSatisfied => opendal_code::OPENDAL_RANGE_NOT_SATISFIED,
+ // if this is triggered, check the [`core`] crate and add a
+ // new error code accordingly
+ _ => unimplemented!(
+ "The newly added ErrorKind in core crate is not handled in C bindings"
+ ),
+ }
+ }
+}
+
+#[repr(C)]
+pub struct opendal_error {
+ code: opendal_code,
+ message: *mut c_char,
+}
+
+impl opendal_error {
+ pub fn new(err: core::Error) -> *mut opendal_error {
+ let code = opendal_code::from(err.kind());
+ let message = std::ffi::CString::new(err.to_string()).unwrap();
+
+ Box::into_raw(Box::new(opendal_error {
+ code,
+ message: message.into_raw(),
+ }))
+ }
+}
diff --git a/bindings/go/go.mod b/bindings/go/src/lib.rs
similarity index 67%
copy from bindings/go/go.mod
copy to bindings/go/src/lib.rs
index 02eea0ae5..017c9108b 100644
--- a/bindings/go/go.mod
+++ b/bindings/go/src/lib.rs
@@ -15,14 +15,17 @@
// specific language governing permissions and limitations
// under the License.
-module github.com/apache/opendal/bindings/go
+#![warn(missing_docs)]
+// This crate is the C binding for the OpenDAL project.
+// So it's type node can't meet camel case.
+#![allow(non_camel_case_types)]
+// This crate is the C binding for the OpenDAL project.
+// Nearly all the functions exposed to C FFI are unsafe.
+#![allow(clippy::missing_safety_doc)]
-go 1.22.4
-
-toolchain go1.22.5
-
-require (
- github.com/ebitengine/purego v0.8.4
- github.com/jupiterrider/ffi v0.5.0
- golang.org/x/sys v0.24.0
-)
+mod error;
+mod operator;
+mod reader;
+mod result;
+mod types;
+mod writer;
diff --git a/bindings/go/src/operator.rs b/bindings/go/src/operator.rs
new file mode 100644
index 000000000..642ba0db1
--- /dev/null
+++ b/bindings/go/src/operator.rs
@@ -0,0 +1,173 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use ::opendal as core;
+use std::{
+ collections::HashMap,
+ ffi::{c_char, c_void},
+ str::FromStr,
+ sync::LazyLock,
+};
+
+use crate::{
+ error::opendal_error, reader::opendal_reader, types::opendal_operator_options,
+ writer::opendal_writer,
+};
+
+static RUNTIME: LazyLock<tokio::runtime::Runtime> = LazyLock::new(|| {
+ tokio::runtime::Builder::new_multi_thread()
+ .enable_all()
+ .build()
+ .unwrap()
+});
+
+/// \brief Used to access almost all OpenDAL APIs. It represents an
+/// operator that provides the unified interfaces provided by OpenDAL.
+///
+/// @see opendal_operator_new This function construct the operator
+/// @see opendal_operator_free This function frees the heap memory of the operator
+///
+/// \note The opendal_operator actually owns a pointer to
+/// an opendal::blocking::Operator, which is inside the Rust core code.
+///
+/// \remark You may use the field `ptr` to check whether this is a NULL
+/// operator.
+#[repr(C)]
+pub struct opendal_operator {
+ inner: *mut c_void,
+ error: *mut c_void,
+}
+
+impl opendal_operator {
+ pub(crate) fn deref(&self) -> &opendal::blocking::Operator {
+ // Safety: the inner should never be null once constructed
+ // The use-after-free is undefined behavior
+ unsafe { &*(self.inner as *const opendal::blocking::Operator) }
+ }
+}
+
+fn build_operator(
+ schema: core::Scheme,
+ map: HashMap<String, String>,
+) -> core::Result<core::blocking::Operator> {
+ let op = core::Operator::via_iter(schema, map)?.layer(core::layers::RetryLayer::new());
+
+ let runtime =
+ tokio::runtime::Handle::try_current().unwrap_or_else(|_| RUNTIME.handle().clone());
+ let _guard = runtime.enter();
+ let op = core::blocking::Operator::new(op)?;
+ Ok(op)
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_operator_new(
+ scheme: *const c_char,
+ options: *const opendal_operator_options,
+) -> *mut opendal_operator {
+ assert!(!scheme.is_null());
+ let scheme = std::ffi::CStr::from_ptr(scheme)
+ .to_str()
+ .expect("malformed scheme");
+ let scheme = match core::Scheme::from_str(scheme) {
+ Ok(s) => s,
+ Err(e) => {
+ return Box::into_raw(Box::new(opendal_operator {
+ inner: std::ptr::null_mut(),
+ error: Box::into_raw(Box::new(opendal_error::new(e))) as _,
+ }))
+ }
+ };
+
+ let mut map = HashMap::<String, String>::default();
+ if !options.is_null() {
+ for (k, v) in (*options).deref() {
+ map.insert(k.to_string(), v.to_string());
+ }
+ }
+ match build_operator(scheme, map) {
+ Ok(op) => Box::into_raw(Box::new(opendal_operator {
+ inner: Box::into_raw(Box::new(op)) as _,
+ error: std::ptr::null_mut(),
+ })),
+ Err(e) => Box::into_raw(Box::new(opendal_operator {
+ inner: std::ptr::null_mut(),
+ error: Box::into_raw(Box::new(opendal_error::new(e))) as _,
+ })),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_operator_free(ptr: *const opendal_operator) {
+ if !ptr.is_null() {
+ let op = Box::from_raw(ptr as *mut opendal_operator);
+ if !op.inner.is_null() {
+ drop(Box::from_raw(op.inner as *mut opendal::blocking::Operator));
+ }
+ if !op.error.is_null() {
+ drop(Box::from_raw(op.error as *mut opendal_error));
+ }
+ drop(op);
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_writer_new(
+ operator: *const opendal_operator,
+ path: *const c_char,
+) -> *mut opendal_writer {
+ assert!(!operator.is_null());
+ assert!(!path.is_null());
+ let path = std::ffi::CStr::from_ptr(path)
+ .to_str()
+ .expect("malformed path");
+
+ let operator = &*operator;
+ match operator.deref().writer(path) {
+ Ok(writer) => Box::into_raw(Box::new(opendal_writer {
+ inner: Box::into_raw(Box::new(writer)) as _,
+ error: std::ptr::null_mut(),
+ })),
+ Err(e) => Box::into_raw(Box::new(opendal_writer {
+ inner: std::ptr::null_mut(),
+ error: Box::into_raw(Box::new(opendal_error::new(e))) as _,
+ })),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_reader_new(
+ operator: *const opendal_operator,
+ path: *const c_char,
+) -> *mut opendal_reader {
+ assert!(!operator.is_null());
+ assert!(!path.is_null());
+ let path = std::ffi::CStr::from_ptr(path)
+ .to_str()
+ .expect("malformed path");
+
+ let operator = &*operator;
+ match operator.deref().reader(path) {
+ Ok(reader) => Box::into_raw(Box::new(opendal_reader {
+ inner: Box::into_raw(Box::new(reader)) as _,
+ error: std::ptr::null_mut(),
+ })),
+ Err(e) => Box::into_raw(Box::new(opendal_reader {
+ inner: std::ptr::null_mut(),
+ error: Box::into_raw(Box::new(opendal_error::new(e))) as _,
+ })),
+ }
+}
diff --git a/bindings/go/src/reader.rs b/bindings/go/src/reader.rs
new file mode 100644
index 000000000..70bc7343d
--- /dev/null
+++ b/bindings/go/src/reader.rs
@@ -0,0 +1,77 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use ::opendal as core;
+use std::ffi::c_void;
+
+use crate::{error::opendal_error, result::opendal_result_reader_read};
+
+pub struct opendal_reader {
+ pub(crate) inner: *mut c_void,
+ pub(crate) error: *mut c_void,
+}
+
+impl opendal_reader {
+ fn deref(&self) -> &opendal::blocking::Reader {
+ // Safety: the inner should never be null once constructed
+ // The use-after-free is undefined behavior
+ unsafe { &*(self.inner as *const opendal::blocking::Reader) }
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_reader_free(reader: *const opendal_reader) {
+ if reader.is_null() {
+ return;
+ }
+ let reader = Box::from_raw(reader as *mut opendal_reader);
+ if !reader.inner.is_null() {
+ // Safety: we are freeing the inner pointer
+ drop(Box::from_raw(
+ reader.inner as *mut opendal::blocking::Reader,
+ ));
+ }
+ if !reader.error.is_null() {
+ // Safety: we are freeing the error pointer
+ drop(Box::from_raw(reader.error as *mut core::Error));
+ }
+ drop(reader);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_reader_read(
+ reader: *mut opendal_reader,
+ data: *mut u8,
+ len: usize,
+) -> *mut opendal_result_reader_read {
+ assert!(!reader.is_null());
+ let reader = &mut *reader;
+ let mut buf = std::slice::from_raw_parts_mut(data, len);
+ match reader.deref().read_into(&mut buf, ..len as u64) {
+ Ok(size) => Box::into_raw(Box::new(opendal_result_reader_read {
+ size,
+ error: std::ptr::null_mut(),
+ })),
+ Err(e) => Box::into_raw(Box::new(opendal_result_reader_read {
+ size: 0,
+ error: Box::into_raw(Box::new(opendal_error::new(
+ core::Error::new(core::ErrorKind::Unexpected, "read failed from reader")
+ .set_source(e),
+ ))) as _,
+ })),
+ }
+}
diff --git a/bindings/go/src/result.rs b/bindings/go/src/result.rs
new file mode 100644
index 000000000..a8d0de26b
--- /dev/null
+++ b/bindings/go/src/result.rs
@@ -0,0 +1,53 @@
+use crate::error::opendal_error;
+
+/// \brief The result type returned by opendal_writer_write().
+/// The result type contains a size field, which is the size of the data written,
+/// which is zero on error. The error field is the error code and error message.
+pub struct opendal_result_writer_write {
+ /// The write size if succeed.
+ pub size: usize,
+ /// The error, if ok, it is null
+ pub error: *mut opendal_error,
+}
+
+/// \brief Free the result of opendal_writer_write().
+#[no_mangle]
+pub unsafe extern "C" fn opendal_result_writer_write_free(
+ result: *const opendal_result_writer_write,
+) {
+ if result.is_null() {
+ return;
+ }
+ let result = Box::from_raw(result as *mut opendal_result_writer_write);
+ if !result.error.is_null() {
+ // Safety: we are freeing the error pointer
+ drop(Box::from_raw(result.error as *mut opendal_error));
+ }
+ drop(result);
+}
+
+/// \brief The result type returned by opendal_reader_read().
+/// The result type contains a size field, which is the size of the data read,
+/// which is zero on error. The error field is the error code and error message.
+pub struct opendal_result_reader_read {
+ /// The read size if succeed.
+ pub size: usize,
+ /// The error, if ok, it is null
+ pub error: *mut opendal_error,
+}
+
+/// \brief Free the result of opendal_reader_read().
+#[no_mangle]
+pub unsafe extern "C" fn opendal_result_reader_read_free(
+ result: *const opendal_result_reader_read,
+) {
+ if result.is_null() {
+ return;
+ }
+ let result = Box::from_raw(result as *mut opendal_result_reader_read);
+ if !result.error.is_null() {
+ // Safety: we are freeing the error pointer
+ drop(Box::from_raw(result.error as *mut opendal_error));
+ }
+ drop(result);
+}
diff --git a/bindings/go/src/types.rs b/bindings/go/src/types.rs
new file mode 100644
index 000000000..053959a7a
--- /dev/null
+++ b/bindings/go/src/types.rs
@@ -0,0 +1,99 @@
+use std::{
+ collections::HashMap,
+ ffi::{c_char, c_void},
+};
+
+/// \brief The configuration for the initialization of opendal_operator.
+///
+/// \note This is also a heap-allocated struct, please free it after you use it
+///
+/// @see opendal_operator_new has an example of using opendal_operator_options
+/// @see opendal_operator_options_new This function construct the operator
+/// @see opendal_operator_options_free This function frees the heap memory of the operator
+/// @see opendal_operator_options_set This function allow you to set the options
+pub struct opendal_operator_options {
+ /// The pointer to the HashMap<String, String> in the Rust code.
+ /// Only touch this on judging whether it is NULL.
+ inner: *mut c_void,
+}
+
+impl opendal_operator_options {
+ pub(crate) fn deref(&self) -> &HashMap<String, String> {
+ // Safety: the inner should never be null once constructed
+ // The use-after-free is undefined behavior
+ unsafe { &*(self.inner as *mut HashMap<String, String>) }
+ }
+
+ pub(crate) fn deref_mut(&mut self) -> &mut HashMap<String, String> {
+ // Safety: the inner should never be null once constructed
+ // The use-after-free is undefined behavior
+ unsafe { &mut *(self.inner as *mut HashMap<String, String>) }
+ }
+}
+
+/// \brief Construct a heap-allocated opendal_operator_options
+///
+/// @return An empty opendal_operator_option, which could be set by
+/// opendal_operator_option_set().
+///
+/// @see opendal_operator_option_set
+#[no_mangle]
+pub unsafe extern "C" fn opendal_operator_options_new() -> *mut opendal_operator_options {
+ let options = Box::new(opendal_operator_options {
+ inner: Box::into_raw(Box::new(HashMap::<String, String>::default())) as _,
+ });
+ Box::into_raw(options)
+}
+
+/// \brief Free the allocated memory used by [`opendal_operator_options`]
+#[no_mangle]
+pub unsafe extern "C" fn opendal_operator_options_free(options: *mut opendal_operator_options) {
+ if options.is_null() {
+ return;
+ }
+ let options = Box::from_raw(options);
+ if !options.inner.is_null() {
+ drop(Box::from_raw(options.inner as *mut HashMap<String, String>));
+ }
+ drop(options);
+}
+
+/// \brief Set a Key-Value pair inside opendal_operator_options
+///
+/// # Safety
+///
+/// This function is unsafe because it dereferences and casts the raw pointers
+/// Make sure the pointer of `key` and `value` point to a valid string.
+///
+/// # Example
+///
+/// ```C
+/// opendal_operator_options *options = opendal_operator_options_new();
+/// opendal_operator_options_set(options, "root", "/myroot");
+///
+/// // .. use your opendal_operator_options
+///
+/// opendal_operator_options_free(options);
+/// ```
+#[no_mangle]
+pub unsafe extern "C" fn opendal_operator_options_set(
+ options: *mut opendal_operator_options,
+ key: *const c_char,
+ value: *const c_char,
+) {
+ assert!(!options.is_null());
+ assert!(!key.is_null());
+ assert!(!value.is_null());
+
+ let options = &mut *options;
+ let key = std::ffi::CStr::from_ptr(key)
+ .to_str()
+ .expect("malformed key");
+ let value = std::ffi::CStr::from_ptr(value)
+ .to_str()
+ .expect("malformed value");
+
+ options
+ .deref_mut()
+ .insert(key.to_string(), value.to_string());
+}
diff --git a/bindings/go/src/writer.rs b/bindings/go/src/writer.rs
new file mode 100644
index 000000000..06f8d8c52
--- /dev/null
+++ b/bindings/go/src/writer.rs
@@ -0,0 +1,101 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use ::opendal as core;
+use std::ffi::c_void;
+
+use crate::{error::opendal_error, result::opendal_result_writer_write};
+
+/// \brief The result type returned by opendal's writer operation.
+/// \note The opendal_writer actually owns a pointer to
+/// an opendal::blocking::Writer, which is inside the Rust core code.
+pub struct opendal_writer {
+ pub(crate) inner: *mut c_void,
+ pub(crate) error: *mut c_void,
+}
+
+impl opendal_writer {
+ fn deref_mut(&mut self) -> &mut opendal::blocking::Writer {
+ // Safety: the inner should never be null once constructed
+ // The use-after-free is undefined behavior
+ unsafe { &mut *(self.inner as *mut opendal::blocking::Writer) }
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_writer_free(writer: *const opendal_writer) {
+ if writer.is_null() {
+ return;
+ }
+ let writer = Box::from_raw(writer as *mut opendal_writer);
+ if !writer.inner.is_null() {
+ // Safety: we are freeing the inner pointer
+ drop(Box::from_raw(
+ writer.inner as *mut opendal::blocking::Writer,
+ ));
+ }
+ if !writer.error.is_null() {
+ // Safety: we are freeing the error pointer
+ drop(Box::from_raw(writer.error as *mut opendal_error));
+ }
+ drop(writer);
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_writer_write(
+ writer: *mut opendal_writer,
+ data: *const u8,
+ size: usize,
+) -> *mut opendal_result_writer_write {
+ assert!(!writer.is_null());
+ let bytes = std::slice::from_raw_parts(data, size);
+ let writer = &mut *writer;
+ match writer.deref_mut().write(bytes) {
+ Ok(_) => Box::into_raw(Box::new(opendal_result_writer_write {
+ size,
+ error: std::ptr::null_mut(),
+ })),
+ Err(e) => Box::into_raw(Box::new(opendal_result_writer_write {
+ size: 0,
+ error: opendal_error::new(
+ core::Error::new(core::ErrorKind::Unexpected, "write failed from writer")
+ .set_source(e),
+ ),
+ })),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn opendal_writer_close(
+ writer: *mut opendal_writer,
+) -> *mut opendal_result_writer_write {
+ assert!(!writer.is_null());
+ let writer = &mut *writer;
+ match writer.deref_mut().close() {
+ Ok(_) => Box::into_raw(Box::new(opendal_result_writer_write {
+ size: 0,
+ error: std::ptr::null_mut(),
+ })),
+ Err(e) => Box::into_raw(Box::new(opendal_result_writer_write {
+ size: 0,
+ error: opendal_error::new(
+ core::Error::new(core::ErrorKind::Unexpected, "close failed from writer")
+ .set_source(e),
+ ),
+ })),
+ }
+}
diff --git a/bindings/go/tests/behavior_tests/opendal_test.go b/bindings/go/tests/behavior_tests/opendal_test.go
index 5d00303f7..3711c80ce 100644
--- a/bindings/go/tests/behavior_tests/opendal_test.go
+++ b/bindings/go/tests/behavior_tests/opendal_test.go
@@ -60,13 +60,13 @@ func TestBehavior(t *testing.T) {
var tests []behaviorTest
- tests = append(tests, testsCopy(cap)...)
- tests = append(tests, testsCreateDir(cap)...)
- tests = append(tests, testsDelete(cap)...)
- tests = append(tests, testsList(cap)...)
+ // tests = append(tests, testsCopy(cap)...)
+ // tests = append(tests, testsCreateDir(cap)...)
+ // tests = append(tests, testsDelete(cap)...)
+ // tests = append(tests, testsList(cap)...)
tests = append(tests, testsRead(cap)...)
- tests = append(tests, testsRename(cap)...)
- tests = append(tests, testsStat(cap)...)
+ // tests = append(tests, testsRename(cap)...)
+ // tests = append(tests, testsStat(cap)...)
tests = append(tests, testsWrite(cap)...)
fixture := newFixture(op)
diff --git a/bindings/go/types.go b/bindings/go/types.go
index 96b66df7b..194fa27eb 100644
--- a/bindings/go/types.go
+++ b/bindings/go/types.go
@@ -22,7 +22,10 @@ package opendal
// Internal types used by the OpenDAL Go binding
// These types are stub implementations and do not contain actual functionality
-type opendalOperator struct{}
+type opendalOperator struct {
+ inner uintptr
+ error uintptr
+}
type opendalReader struct{}
@@ -36,5 +39,5 @@ type opendalEntry struct{}
type opendalError struct {
code int32
- message string
+ message uintptr
}