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

Xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git


The following commit(s) were added to refs/heads/main by this push:
     new 4f21e503a chore(deps): bump opendal to 0.56, migrate to reqsign-core 
3.0 (#2401)
4f21e503a is described below

commit 4f21e503afc5363c10fafac917f0febe136c464e
Author: Krisztián Szűcs <[email protected]>
AuthorDate: Fri May 8 14:50:39 2026 +0200

    chore(deps): bump opendal to 0.56, migrate to reqsign-core 3.0 (#2401)
    
    ## Summary
    
    Bumps `opendal` from `0.55` to `0.56`, which is now published on
    crates.io.
    
    The 0.56 release made two breaking API changes that required code
    updates:
    
    - **`opendal::Scheme` was removed.** `OpenDalResolvingStorage` used it
    as the HashMap key for caching per-scheme storage instances. Replaced
    with `&'static str` (e.g. `"s3"`, `"gcs"`), with S3-family aliases
    (`s3a`, `s3n`) and GCS aliases (`gs`) still collapsing to a single
    entry.
    
    - **reqsign was split into focused crates.** The old `reqsign 0.16`
    monolith (with `AwsCredentialLoad` / `reqwest::Client`) was replaced by
    `reqsign-aws-v4` + `reqsign-core` 3.0. `CustomAwsCredentialLoader` now
    wraps any `ProvideCredential<Credential = AwsCredential>` implementation
    instead of `Arc<dyn AwsCredentialLoad>`, which removes the `Arc`
    wrapping at call sites.
---
 Cargo.lock                                         | 563 +++++++++++++++++++--
 Cargo.toml                                         |   2 +-
 crates/storage/opendal/Cargo.toml                  |   7 +-
 crates/storage/opendal/src/lib.rs                  |   6 +-
 crates/storage/opendal/src/resolving.rs            |  51 +-
 crates/storage/opendal/src/s3.rs                   |  46 +-
 crates/storage/opendal/tests/file_io_s3_test.rs    |  29 +-
 .../opendal/tests/resolving_storage_test.rs        |  25 +-
 8 files changed, 591 insertions(+), 138 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock
index c55c10240..350474c24 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -599,6 +599,7 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc"
 dependencies = [
  "aws-lc-sys",
+ "untrusted 0.7.1",
  "zeroize",
 ]
 
@@ -1086,7 +1087,7 @@ version = "3.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c"
 dependencies = [
- "darling 0.20.11",
+ "darling 0.23.0",
  "ident_case",
  "prettyplease",
  "proc-macro2",
@@ -1324,7 +1325,17 @@ version = "3.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd"
+dependencies = [
+ "bytes",
+ "memchr",
 ]
 
 [[package]]
@@ -1549,6 +1560,22 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "ctor"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "424e0138278faeb2b401f174ad17e715c829512d74f3d1e81eb43365c2e0590e"
+dependencies = [
+ "ctor-proc-macro",
+ "dtor",
+]
+
+[[package]]
+name = "ctor-proc-macro"
+version = "0.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
+
 [[package]]
 name = "ctr"
 version = "0.9.2"
@@ -2518,7 +2545,7 @@ dependencies = [
  "libc",
  "option-ext",
  "redox_users",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -2559,6 +2586,21 @@ version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
 
+[[package]]
+name = "dtor"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "404d02eeb088a82cfd873006cb713fe411306c7d182c344905e101fb1167d301"
+dependencies = [
+ "dtor-proc-macro",
+]
+
+[[package]]
+name = "dtor-proc-macro"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
+
 [[package]]
 name = "dunce"
 version = "1.0.5"
@@ -2671,7 +2713,7 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
 dependencies = [
  "libc",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -3282,7 +3324,6 @@ dependencies = [
  "tokio",
  "tokio-rustls",
  "tower-service",
- "webpki-roots 1.0.6",
 ]
 
 [[package]]
@@ -3373,7 +3414,7 @@ dependencies = [
  "pretty_assertions",
  "rand 0.9.4",
  "regex",
- "reqwest",
+ "reqwest 0.12.28",
  "roaring",
  "serde",
  "serde_arrow",
@@ -3452,7 +3493,7 @@ dependencies = [
  "iceberg-catalog-sql",
  "iceberg-storage-opendal",
  "iceberg_test_utils",
- "reqwest",
+ "reqwest 0.12.28",
  "rstest",
  "sqlx",
  "tempfile",
@@ -3470,7 +3511,7 @@ dependencies = [
  "iceberg_test_utils",
  "itertools 0.13.0",
  "mockito",
- "reqwest",
+ "reqwest 0.12.28",
  "serde",
  "serde_derive",
  "serde_json",
@@ -3614,8 +3655,9 @@ dependencies = [
  "iceberg",
  "iceberg_test_utils",
  "opendal",
- "reqsign",
- "reqwest",
+ "reqsign-aws-v4",
+ "reqsign-core",
+ "reqwest 0.12.28",
  "serde",
  "tokio",
  "typetag",
@@ -3869,11 +3911,13 @@ checksum = 
"1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359"
 dependencies = [
  "jiff-static",
  "jiff-tzdb-platform",
+ "js-sys",
  "log",
  "portable-atomic",
  "portable-atomic-util",
  "serde_core",
- "windows-sys 0.59.0",
+ "wasm-bindgen",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -3902,6 +3946,55 @@ dependencies = [
  "jiff-tzdb",
 ]
 
+[[package]]
+name = "jni"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
+dependencies = [
+ "cfg-if",
+ "combine",
+ "jni-macros",
+ "jni-sys",
+ "log",
+ "simd_cesu8",
+ "thiserror 2.0.18",
+ "walkdir",
+ "windows-link",
+]
+
+[[package]]
+name = "jni-macros"
+version = "0.22.4"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "simd_cesu8",
+ "syn",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2"
+dependencies = [
+ "jni-sys-macros",
+]
+
+[[package]]
+name = "jni-sys-macros"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264"
+dependencies = [
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "jobserver"
 version = "0.1.34"
@@ -3924,16 +4017,18 @@ dependencies = [
 
 [[package]]
 name = "jsonwebtoken"
-version = "9.3.1"
+version = "10.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde"
+checksum = "0529410abe238729a60b108898784df8984c87f6054c9c4fcacc47e4803c1ce1"
 dependencies = [
+ "aws-lc-rs",
  "base64",
+ "getrandom 0.2.17",
  "js-sys",
  "pem",
- "ring",
  "serde",
  "serde_json",
+ "signature",
  "simple_asn1",
 ]
 
@@ -4176,6 +4271,15 @@ dependencies = [
  "digest",
 ]
 
+[[package]]
+name = "mea"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "6747f54621d156e1b47eb6b25f39a941b9fc347f98f67d25d8881ff99e8ed832"
+dependencies = [
+ "slab",
+]
+
 [[package]]
 name = "memchr"
 version = "2.8.0"
@@ -4422,7 +4526,7 @@ version = "0.50.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
 dependencies = [
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -4552,7 +4656,7 @@ dependencies = [
  "percent-encoding",
  "quick-xml 0.39.2",
  "rand 0.10.1",
- "reqwest",
+ "reqwest 0.12.28",
  "ring",
  "rustls-pki-types",
  "serde",
@@ -4587,31 +4691,194 @@ checksum = 
"c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
 
 [[package]]
 name = "opendal"
-version = "0.55.0"
+version = "0.56.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "d075ab8a203a6ab4bc1bce0a4b9fe486a72bf8b939037f4b78d95386384bc80a"
+checksum = "97b31d3d8e99a85d83b73ec26647f5607b80578ed9375810b6e44ffa3590a236"
+dependencies = [
+ "ctor",
+ "opendal-core",
+ "opendal-layer-concurrent-limit",
+ "opendal-layer-logging",
+ "opendal-layer-retry",
+ "opendal-layer-timeout",
+ "opendal-service-azdls",
+ "opendal-service-fs",
+ "opendal-service-gcs",
+ "opendal-service-oss",
+ "opendal-service-s3",
+]
+
+[[package]]
+name = "opendal-core"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "1849dd2687e173e776d3af5fce1ba3ae47b9dd37a09d1c4deba850ef45fe00ca"
 dependencies = [
  "anyhow",
- "backon",
  "base64",
  "bytes",
- "crc32c",
  "futures",
- "getrandom 0.2.17",
  "http 1.4.0",
  "http-body 1.0.1",
  "jiff",
  "log",
  "md-5",
+ "mea",
  "percent-encoding",
  "quick-xml 0.38.4",
- "reqsign",
- "reqwest",
+ "reqsign-core",
+ "reqwest 0.13.3",
  "serde",
  "serde_json",
  "tokio",
  "url",
  "uuid",
+ "web-time",
+]
+
+[[package]]
+name = "opendal-layer-concurrent-limit"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "048b1b29c503263bdd80a9afe46a68cd02ea9bd361185b1feab4b151078998e9"
+dependencies = [
+ "futures",
+ "http 1.4.0",
+ "mea",
+ "opendal-core",
+]
+
+[[package]]
+name = "opendal-layer-logging"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "d2645adc988b12eda106e2679ae529facfbbaa868ceb706f6f8125c6af15c47b"
+dependencies = [
+ "log",
+ "opendal-core",
+]
+
+[[package]]
+name = "opendal-layer-retry"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "4eac134ffa4ddda6131a640a84a5315996424b9416c85052f8c64c1a33b70ad4"
+dependencies = [
+ "backon",
+ "log",
+ "opendal-core",
+]
+
+[[package]]
+name = "opendal-layer-timeout"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "619586ab7480c2e3009f6d18eabab18957bc094778fd130bcc38924970a90f4c"
+dependencies = [
+ "opendal-core",
+ "tokio",
+]
+
+[[package]]
+name = "opendal-service-azdls"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "8f9884c2d8cf8ba2bb077d79c877dac5863ba3bab9e2c9c1e41a2e0491404772"
+dependencies = [
+ "bytes",
+ "http 1.4.0",
+ "log",
+ "opendal-core",
+ "opendal-service-azure-common",
+ "quick-xml 0.38.4",
+ "reqsign-azure-storage",
+ "reqsign-core",
+ "reqsign-file-read-tokio",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "opendal-service-azure-common"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "ffb0e45d6c8dcf66ce2da20e241bcb80e6e540e109a4ff20f318f6c9b4c54e0c"
+dependencies = [
+ "http 1.4.0",
+ "opendal-core",
+]
+
+[[package]]
+name = "opendal-service-fs"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "cf0be0417abeeb0053376d816b90fceb9ca98f20dfb54ebf1f2a282729f83663"
+dependencies = [
+ "bytes",
+ "log",
+ "opendal-core",
+ "serde",
+ "tokio",
+ "xattr",
+]
+
+[[package]]
+name = "opendal-service-gcs"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "70a49477a10163431896d106136117f5670717f9c9e49cf6f710528800c6633a"
+dependencies = [
+ "async-trait",
+ "bytes",
+ "http 1.4.0",
+ "log",
+ "opendal-core",
+ "percent-encoding",
+ "quick-xml 0.38.4",
+ "reqsign-core",
+ "reqsign-file-read-tokio",
+ "reqsign-google",
+ "serde",
+ "serde_json",
+ "tokio",
+]
+
+[[package]]
+name = "opendal-service-oss"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "29c8a917829ad06d21b639558532cb0101fe49b040d946d673a73018683fac05"
+dependencies = [
+ "bytes",
+ "http 1.4.0",
+ "log",
+ "opendal-core",
+ "quick-xml 0.38.4",
+ "reqsign-aliyun-oss",
+ "reqsign-core",
+ "reqsign-file-read-tokio",
+ "serde",
+]
+
+[[package]]
+name = "opendal-service-s3"
+version = "0.56.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "9dadddeb9bb50b0d30927dd914c298c4ddca47e4c1cfa7674d311f0cf9b051c8"
+dependencies = [
+ "base64",
+ "bytes",
+ "crc32c",
+ "http 1.4.0",
+ "log",
+ "md-5",
+ "opendal-core",
+ "quick-xml 0.38.4",
+ "reqsign-aws-v4",
+ "reqsign-core",
+ "reqsign-file-read-tokio",
+ "serde",
+ "url",
 ]
 
 [[package]]
@@ -5078,7 +5345,7 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7"
 dependencies = [
  "heck",
- "itertools 0.13.0",
+ "itertools 0.14.0",
  "log",
  "multimap",
  "petgraph",
@@ -5097,7 +5364,7 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b"
 dependencies = [
  "anyhow",
- "itertools 0.13.0",
+ "itertools 0.14.0",
  "proc-macro2",
  "quote",
  "syn",
@@ -5148,16 +5415,6 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "5a651516ddc9168ebd67b24afd085a718be02f8858fe406591b013d101ce2f40"
 
-[[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 = "quick-xml"
 version = "0.38.4"
@@ -5204,6 +5461,7 @@ version = "0.11.14"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098"
 dependencies = [
+ "aws-lc-rs",
  "bytes",
  "getrandom 0.3.4",
  "lru-slab",
@@ -5230,7 +5488,7 @@ dependencies = [
  "once_cell",
  "socket2 0.6.3",
  "tracing",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -5478,33 +5736,114 @@ source = 
"registry+https://github.com/rust-lang/crates.io-index";
 checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6"
 
 [[package]]
-name = "reqsign"
-version = "0.16.5"
+name = "reqsign-aliyun-oss"
+version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index";
-checksum = "43451dbf3590a7590684c25fb8d12ecdcc90ed3ac123433e500447c7d77ed701"
+checksum = "57ac2757f3140aa2e213b554148ae0b52733e624fc6723f0cc6bb3d440176c95"
+dependencies = [
+ "anyhow",
+ "form_urlencoded",
+ "http 1.4.0",
+ "log",
+ "percent-encoding",
+ "reqsign-core",
+ "rust-ini",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "reqsign-aws-v4"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "44eaca382e94505a49f1a4849658d153aebf79d9c1a58e5dd3b10361511e9f43"
+dependencies = [
+ "anyhow",
+ "bytes",
+ "form_urlencoded",
+ "http 1.4.0",
+ "log",
+ "percent-encoding",
+ "quick-xml 0.39.2",
+ "reqsign-core",
+ "rust-ini",
+ "serde",
+ "serde_json",
+ "serde_urlencoded",
+ "sha1",
+]
+
+[[package]]
+name = "reqsign-azure-storage"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "7a321980405d596bd34aaf95c4722a3de4128a67fd19e74a81a83aa3fdf082e6"
 dependencies = [
  "anyhow",
- "async-trait",
  "base64",
- "chrono",
+ "bytes",
  "form_urlencoded",
- "getrandom 0.2.17",
+ "http 1.4.0",
+ "jsonwebtoken",
+ "log",
+ "pem",
+ "percent-encoding",
+ "reqsign-core",
+ "rsa",
+ "serde",
+ "serde_json",
+ "sha1",
+]
+
+[[package]]
+name = "reqsign-core"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "b10302cf0a7d7e7352ba211fc92c3c5bebf1286153e49cc5aa87348078a8e102"
+dependencies = [
+ "anyhow",
+ "base64",
+ "bytes",
+ "form_urlencoded",
+ "futures",
  "hex",
  "hmac",
- "home",
+ "http 1.4.0",
+ "jiff",
+ "log",
+ "percent-encoding",
+ "sha1",
+ "sha2",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "reqsign-file-read-tokio"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "e2d89295b3d17abea31851cc8de55d843d89c52132c864963c38d41920613dc5"
+dependencies = [
+ "anyhow",
+ "reqsign-core",
+ "tokio",
+]
+
+[[package]]
+name = "reqsign-google"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "35cc609b49c69e76ecaceb775a03f792d1ed3e7755ab3548d4534fd801e3242e"
+dependencies = [
+ "form_urlencoded",
  "http 1.4.0",
  "jsonwebtoken",
  "log",
- "once_cell",
  "percent-encoding",
- "quick-xml 0.37.5",
- "rand 0.8.5",
- "reqwest",
+ "reqsign-aws-v4",
+ "reqsign-core",
  "rsa",
- "rust-ini",
  "serde",
  "serde_json",
- "sha1",
  "sha2",
  "tokio",
 ]
@@ -5547,9 +5886,46 @@ dependencies = [
  "url",
  "wasm-bindgen",
  "wasm-bindgen-futures",
- "wasm-streams",
+ "wasm-streams 0.4.2",
+ "web-sys",
+]
+
+[[package]]
+name = "reqwest"
+version = "0.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "62e0021ea2c22aed41653bc7e1419abb2c97e038ff2c33d0e1309e49a97deec0"
+dependencies = [
+ "base64",
+ "bytes",
+ "futures-core",
+ "futures-util",
+ "http 1.4.0",
+ "http-body 1.0.1",
+ "http-body-util",
+ "hyper",
+ "hyper-rustls",
+ "hyper-util",
+ "js-sys",
+ "log",
+ "percent-encoding",
+ "pin-project-lite",
+ "quinn",
+ "rustls",
+ "rustls-pki-types",
+ "rustls-platform-verifier",
+ "sync_wrapper",
+ "tokio",
+ "tokio-rustls",
+ "tokio-util",
+ "tower",
+ "tower-http",
+ "tower-service",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams 0.5.0",
  "web-sys",
- "webpki-roots 1.0.6",
 ]
 
 [[package]]
@@ -5562,7 +5938,7 @@ dependencies = [
  "cfg-if",
  "getrandom 0.2.17",
  "libc",
- "untrusted",
+ "untrusted 0.9.0",
  "windows-sys 0.52.0",
 ]
 
@@ -5693,7 +6069,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -5733,6 +6109,33 @@ dependencies = [
  "zeroize",
 ]
 
+[[package]]
+name = "rustls-platform-verifier"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
+dependencies = [
+ "core-foundation",
+ "core-foundation-sys",
+ "jni",
+ "log",
+ "once_cell",
+ "rustls",
+ "rustls-native-certs",
+ "rustls-platform-verifier-android",
+ "rustls-webpki",
+ "security-framework",
+ "security-framework-sys",
+ "webpki-root-certs",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustls-platform-verifier-android"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
+
 [[package]]
 name = "rustls-webpki"
 version = "0.103.13"
@@ -5742,7 +6145,7 @@ dependencies = [
  "aws-lc-rs",
  "ring",
  "rustls-pki-types",
- "untrusted",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -6149,6 +6552,16 @@ version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
 
+[[package]]
+name = "simd_cesu8"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33"
+dependencies = [
+ "rustc_version",
+ "simdutf8",
+]
+
 [[package]]
 name = "simdutf8"
 version = "0.1.5"
@@ -6656,7 +7069,7 @@ dependencies = [
  "getrandom 0.4.2",
  "once_cell",
  "rustix",
- "windows-sys 0.59.0",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -7215,6 +7628,12 @@ version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
 
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
 [[package]]
 name = "untrusted"
 version = "0.9.0"
@@ -7486,6 +7905,19 @@ dependencies = [
  "web-sys",
 ]
 
+[[package]]
+name = "wasm-streams"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb"
+dependencies = [
+ "futures-util",
+ "js-sys",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
 [[package]]
 name = "wasmparser"
 version = "0.244.0"
@@ -7518,6 +7950,15 @@ dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "webpki-root-certs"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c"
+dependencies = [
+ "rustls-pki-types",
+]
+
 [[package]]
 name = "webpki-roots"
 version = "0.26.11"
@@ -7552,7 +7993,7 @@ version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -7957,6 +8398,16 @@ version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index";
 checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
 
+[[package]]
+name = "xattr"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index";
+checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
+dependencies = [
+ "libc",
+ "rustix",
+]
+
 [[package]]
 name = "xmlparser"
 version = "0.13.6"
diff --git a/Cargo.toml b/Cargo.toml
index 7f612c44b..793bb49d8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -103,7 +103,7 @@ mockito = "1"
 motore-macros = "0.4.3"
 murmur3 = "0.5.2"
 once_cell = "1.20"
-opendal = "0.55.0"
+opendal = "0.56"
 ordered-float = "4"
 parquet = "58"
 pilota = "0.11.10"
diff --git a/crates/storage/opendal/Cargo.toml 
b/crates/storage/opendal/Cargo.toml
index 84f7e1147..80eeaa3d0 100644
--- a/crates/storage/opendal/Cargo.toml
+++ b/crates/storage/opendal/Cargo.toml
@@ -35,7 +35,7 @@ opendal-fs = ["opendal/services-fs"]
 opendal-gcs = ["opendal/services-gcs"]
 opendal-memory = ["opendal/services-memory"]
 opendal-oss = ["opendal/services-oss"]
-opendal-s3 = ["opendal/services-s3", "reqsign"]
+opendal-s3 = ["opendal/services-s3", "reqsign-aws-v4", "reqsign-core"]
 
 [dependencies]
 anyhow = { workspace = true }
@@ -44,8 +44,8 @@ iceberg = { workspace = true }
 opendal = { workspace = true }
 async-trait = { workspace = true }
 bytes = { workspace = true }
-reqsign = { version = "0.16.3", optional = true, default-features = false }
-reqwest = { workspace = true }
+reqsign-aws-v4 = { version = "3.0.0", optional = true }
+reqsign-core = { version = "3.0.0", optional = true }
 serde = { workspace = true }
 typetag = { workspace = true }
 url = { workspace = true }
@@ -54,6 +54,5 @@ futures = { workspace = true }
 [dev-dependencies]
 async-trait = { workspace = true }
 iceberg_test_utils = { path = "../../test_utils", features = ["tests"] }
-reqsign = { version = "0.16.3", default-features = false }
 reqwest = { workspace = true }
 tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
diff --git a/crates/storage/opendal/src/lib.rs 
b/crates/storage/opendal/src/lib.rs
index a0336868e..65deaa5f4 100644
--- a/crates/storage/opendal/src/lib.rs
+++ b/crates/storage/opendal/src/lib.rs
@@ -482,7 +482,11 @@ impl Storage for OpenDalStorage {
         } else {
             format!("{relative_path}/")
         };
-        Ok(op.remove_all(&path).await.map_err(from_opendal_error)?)
+        Ok(op
+            .delete_with(&path)
+            .recursive(true)
+            .await
+            .map_err(from_opendal_error)?)
     }
 
     async fn delete_stream(&self, mut paths: BoxStream<'static, String>) -> 
Result<()> {
diff --git a/crates/storage/opendal/src/resolving.rs 
b/crates/storage/opendal/src/resolving.rs
index 64a16b18d..621495519 100644
--- a/crates/storage/opendal/src/resolving.rs
+++ b/crates/storage/opendal/src/resolving.rs
@@ -30,7 +30,6 @@ use iceberg::io::{
     StorageFactory,
 };
 use iceberg::{Error, ErrorKind, Result};
-use opendal::Scheme;
 use serde::{Deserialize, Serialize};
 use url::Url;
 
@@ -52,26 +51,24 @@ pub const SCHEME_ABFS: &str = "abfs";
 pub const SCHEME_WASBS: &str = "wasbs";
 pub const SCHEME_WASB: &str = "wasb";
 
-/// Parse a URL scheme string into an [`opendal::Scheme`].
-fn parse_scheme(scheme: &str) -> Result<Scheme> {
+/// Parse a URL scheme string.
+fn parse_scheme(scheme: &str) -> Result<&'static str> {
     match scheme {
-        SCHEME_MEMORY => Ok(Scheme::Memory),
-        SCHEME_FILE | "" => Ok(Scheme::Fs),
-        SCHEME_S3 | SCHEME_S3A | SCHEME_S3N => Ok(Scheme::S3),
-        SCHEME_GS | SCHEME_GCS => Ok(Scheme::Gcs),
-        SCHEME_OSS => Ok(Scheme::Oss),
-        SCHEME_ABFSS | SCHEME_ABFS | SCHEME_WASBS | SCHEME_WASB => 
Ok(Scheme::Azdls),
-        s => s.parse::<Scheme>().map_err(|e| {
-            Error::new(
-                ErrorKind::FeatureUnsupported,
-                format!("Unsupported storage scheme: {s}: {e}"),
-            )
-        }),
+        SCHEME_MEMORY => Ok("memory"),
+        SCHEME_FILE | "" => Ok("file"),
+        SCHEME_S3 | SCHEME_S3A | SCHEME_S3N => Ok("s3"),
+        SCHEME_GS | SCHEME_GCS => Ok("gcs"),
+        SCHEME_OSS => Ok("oss"),
+        SCHEME_ABFSS | SCHEME_ABFS | SCHEME_WASBS | SCHEME_WASB => Ok("azdls"),
+        s => Err(Error::new(
+            ErrorKind::FeatureUnsupported,
+            format!("Unsupported storage scheme: {s}"),
+        )),
     }
 }
 
-/// Extract the [`Scheme`] family from a path URL.
-fn extract_scheme(path: &str) -> Result<Scheme> {
+/// Extract the scheme from a path URL.
+fn extract_scheme(path: &str) -> Result<&'static str> {
     let url = Url::parse(path).map_err(|e| {
         Error::new(
             ErrorKind::DataInvalid,
@@ -83,13 +80,13 @@ fn extract_scheme(path: &str) -> Result<Scheme> {
 
 /// Build an [`OpenDalStorage`] variant for the given scheme and config 
properties.
 fn build_storage_for_scheme(
-    scheme: Scheme,
+    scheme: &'static str,
     props: &HashMap<String, String>,
     #[cfg(feature = "opendal-s3")] customized_credential_load: 
&Option<CustomAwsCredentialLoader>,
 ) -> Result<OpenDalStorage> {
     match scheme {
         #[cfg(feature = "opendal-s3")]
-        Scheme::S3 => {
+        "s3" => {
             let config = crate::s3::s3_config_parse(props.clone())?;
             Ok(OpenDalStorage::S3 {
                 config: Arc::new(config),
@@ -97,30 +94,30 @@ fn build_storage_for_scheme(
             })
         }
         #[cfg(feature = "opendal-gcs")]
-        Scheme::Gcs => {
+        "gcs" => {
             let config = crate::gcs::gcs_config_parse(props.clone())?;
             Ok(OpenDalStorage::Gcs {
                 config: Arc::new(config),
             })
         }
         #[cfg(feature = "opendal-oss")]
-        Scheme::Oss => {
+        "oss" => {
             let config = crate::oss::oss_config_parse(props.clone())?;
             Ok(OpenDalStorage::Oss {
                 config: Arc::new(config),
             })
         }
         #[cfg(feature = "opendal-azdls")]
-        Scheme::Azdls => {
+        "azdls" => {
             let config = crate::azdls::azdls_config_parse(props.clone())?;
             Ok(OpenDalStorage::Azdls {
                 config: Arc::new(config),
             })
         }
         #[cfg(feature = "opendal-fs")]
-        Scheme::Fs => Ok(OpenDalStorage::LocalFs),
+        "file" => Ok(OpenDalStorage::LocalFs),
         #[cfg(feature = "opendal-memory")]
-        Scheme::Memory => 
Ok(OpenDalStorage::Memory(crate::memory::memory_config_build()?)),
+        "memory" => 
Ok(OpenDalStorage::Memory(crate::memory::memory_config_build()?)),
         unsupported => Err(Error::new(
             ErrorKind::FeatureUnsupported,
             format!("Unsupported storage scheme: {unsupported}"),
@@ -194,14 +191,14 @@ impl StorageFactory for OpenDalResolvingStorageFactory {
 ///
 /// Sub-storages are lazily created on first use for each scheme and cached
 /// for subsequent operations. Scheme aliases like `s3`/`s3a`/`s3n` map to
-/// the same [`Scheme`] variant, so they share a storage instance.
+/// the same canonical scheme, so they share a storage instance.
 #[derive(Debug, Serialize, Deserialize)]
 pub struct OpenDalResolvingStorage {
     /// Configuration properties shared across all backends.
     props: HashMap<String, String>,
     /// Cache of scheme to storage mappings.
     #[serde(skip, default)]
-    storages: RwLock<HashMap<Scheme, Arc<OpenDalStorage>>>,
+    storages: RwLock<HashMap<&'static str, Arc<OpenDalStorage>>>,
     /// Custom AWS credential loader for S3 storage.
     #[cfg(feature = "opendal-s3")]
     #[serde(skip)]
@@ -286,7 +283,7 @@ impl Storage for OpenDalResolvingStorage {
     async fn delete_stream(&self, mut paths: BoxStream<'static, String>) -> 
Result<()> {
         // Group paths by scheme so each resolved storage receives a batch,
         // avoiding repeated operator creation per path.
-        let mut grouped: HashMap<Scheme, Vec<String>> = HashMap::new();
+        let mut grouped: HashMap<&'static str, Vec<String>> = HashMap::new();
         while let Some(path) = paths.next().await {
             let scheme = extract_scheme(&path)?;
             grouped.entry(scheme).or_default().push(path);
diff --git a/crates/storage/opendal/src/s3.rs b/crates/storage/opendal/src/s3.rs
index 2e2141860..75f7684cc 100644
--- a/crates/storage/opendal/src/s3.rs
+++ b/crates/storage/opendal/src/s3.rs
@@ -18,7 +18,6 @@
 use std::collections::HashMap;
 use std::sync::Arc;
 
-use async_trait::async_trait;
 use iceberg::io::{
     CLIENT_REGION, S3_ACCESS_KEY_ID, S3_ALLOW_ANONYMOUS, S3_ASSUME_ROLE_ARN,
     S3_ASSUME_ROLE_EXTERNAL_ID, S3_ASSUME_ROLE_SESSION_NAME, 
S3_DISABLE_CONFIG_LOAD,
@@ -28,8 +27,11 @@ use iceberg::io::{
 use iceberg::{Error, ErrorKind, Result};
 use opendal::services::S3Config;
 use opendal::{Configurator, Operator};
-pub use reqsign::{AwsCredential, AwsCredentialLoad};
-use reqwest::Client;
+/// AWS credentials: access key ID, secret access key, and optional session 
token.
+pub use reqsign_aws_v4::Credential as AwsCredential;
+/// Trait for types that can asynchronously supply [`AwsCredential`] to a 
[`CustomAwsCredentialLoader`].
+pub use reqsign_core::ProvideCredential;
+use reqsign_core::{ProvideCredentialChain, ProvideCredentialDyn};
 use url::Url;
 
 use crate::utils::{from_opendal_error, is_truthy};
@@ -143,20 +145,26 @@ pub(crate) fn s3_config_build(
         // Set bucket name.
         .bucket(bucket);
 
-    if let Some(customized_credential_load) = customized_credential_load {
-        builder = builder
-            
.customized_credential_load(customized_credential_load.clone().into_opendal_loader());
+    if let Some(loader) = customized_credential_load {
+        let chain = ProvideCredentialChain::new().push(Arc::clone(&loader.0));
+        builder = builder.credential_provider_chain(chain);
     }
 
     Ok(Operator::new(builder).map_err(from_opendal_error)?.finish())
 }
 
 /// Custom AWS credential loader.
-/// This can be used to load credentials from a custom source, such as the AWS 
SDK.
 ///
-/// This should be set as an extension on `FileIOBuilder`.
-#[derive(Clone)]
-pub struct CustomAwsCredentialLoader(Arc<dyn AwsCredentialLoad>);
+/// Wraps any [`ProvideCredential`] implementation for use with the S3 storage 
backend.
+/// Use [`CustomAwsCredentialLoader::new`] to create one, then pass it to
+/// [`OpenDalStorageFactory::S3`](crate::OpenDalStorageFactory).
+pub struct CustomAwsCredentialLoader(Arc<dyn ProvideCredentialDyn<Credential = 
AwsCredential>>);
+
+impl Clone for CustomAwsCredentialLoader {
+    fn clone(&self) -> Self {
+        Self(Arc::clone(&self.0))
+    }
+}
 
 impl std::fmt::Debug for CustomAwsCredentialLoader {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@@ -166,21 +174,9 @@ impl std::fmt::Debug for CustomAwsCredentialLoader {
 }
 
 impl CustomAwsCredentialLoader {
-    /// Create a new custom AWS credential loader.
-    pub fn new(loader: Arc<dyn AwsCredentialLoad>) -> Self {
-        Self(loader)
-    }
-
-    /// Convert this loader into an opendal compatible loader for customized 
AWS credentials.
-    pub fn into_opendal_loader(self) -> Box<dyn AwsCredentialLoad> {
-        Box::new(self)
-    }
-}
-
-#[async_trait]
-impl AwsCredentialLoad for CustomAwsCredentialLoader {
-    async fn load_credential(&self, client: Client) -> 
anyhow::Result<Option<AwsCredential>> {
-        self.0.load_credential(client).await
+    /// Create a new custom AWS credential loader from any 
[`ProvideCredential`] implementation.
+    pub fn new(provider: impl ProvideCredential<Credential = AwsCredential> + 
'static) -> Self {
+        Self(Arc::new(provider) as Arc<dyn ProvideCredentialDyn<Credential = 
AwsCredential>>)
     }
 }
 
diff --git a/crates/storage/opendal/tests/file_io_s3_test.rs 
b/crates/storage/opendal/tests/file_io_s3_test.rs
index d6dd8a3b4..d5858e18f 100644
--- a/crates/storage/opendal/tests/file_io_s3_test.rs
+++ b/crates/storage/opendal/tests/file_io_s3_test.rs
@@ -23,16 +23,16 @@
 mod tests {
     use std::sync::Arc;
 
-    use async_trait::async_trait;
     use futures::StreamExt;
     use iceberg::io::{
         FileIO, FileIOBuilder, S3_ACCESS_KEY_ID, S3_ENDPOINT, 
S3_PATH_STYLE_ACCESS, S3_REGION,
         S3_SECRET_ACCESS_KEY,
     };
-    use iceberg_storage_opendal::{CustomAwsCredentialLoader, 
OpenDalStorageFactory};
+    use iceberg_storage_opendal::{
+        AwsCredential, CustomAwsCredentialLoader, OpenDalStorageFactory, 
ProvideCredential,
+    };
     use iceberg_test_utils::{get_minio_endpoint, 
normalize_test_name_with_parts, set_up};
-    use reqsign::{AwsCredential, AwsCredentialLoad};
-    use reqwest::Client;
+    use reqsign_core::Context;
 
     async fn get_file_io() -> FileIO {
         set_up();
@@ -99,6 +99,7 @@ mod tests {
     }
 
     // Mock credential loader for testing
+    #[derive(Debug)]
     struct MockCredentialLoader {
         credential: Option<AwsCredential>,
     }
@@ -118,9 +119,13 @@ mod tests {
         }
     }
 
-    #[async_trait]
-    impl AwsCredentialLoad for MockCredentialLoader {
-        async fn load_credential(&self, _client: Client) -> 
anyhow::Result<Option<AwsCredential>> {
+    impl ProvideCredential for MockCredentialLoader {
+        type Credential = AwsCredential;
+
+        async fn provide_credential(
+            &self,
+            _ctx: &Context,
+        ) -> reqsign_core::Result<Option<AwsCredential>> {
             Ok(self.credential.clone())
         }
     }
@@ -129,7 +134,7 @@ mod tests {
     fn test_custom_aws_credential_loader_instantiation() {
         // Test creating CustomAwsCredentialLoader with mock loader
         let mock_loader = MockCredentialLoader::new_minio();
-        let custom_loader = 
CustomAwsCredentialLoader::new(Arc::new(mock_loader));
+        let custom_loader = CustomAwsCredentialLoader::new(mock_loader);
 
         // Test that the loader can be used in FileIOBuilder with 
OpenDalStorageFactory
         let _builder = FileIOBuilder::new(Arc::new(OpenDalStorageFactory::S3 {
@@ -149,7 +154,7 @@ mod tests {
 
         // Create a mock credential loader
         let mock_loader = MockCredentialLoader::new_minio();
-        let custom_loader = 
CustomAwsCredentialLoader::new(Arc::new(mock_loader));
+        let custom_loader = CustomAwsCredentialLoader::new(mock_loader);
 
         let minio_endpoint = get_minio_endpoint();
 
@@ -177,7 +182,7 @@ mod tests {
 
         // Create a mock credential loader with no credentials
         let mock_loader = MockCredentialLoader::new(None);
-        let custom_loader = 
CustomAwsCredentialLoader::new(Arc::new(mock_loader));
+        let custom_loader = CustomAwsCredentialLoader::new(mock_loader);
 
         let minio_endpoint = get_minio_endpoint();
 
@@ -199,8 +204,8 @@ mod tests {
             ),
             Err(e) => {
                 assert!(
-                    e.to_string()
-                        .contains("no valid credential found and anonymous 
access is not allowed")
+                    e.to_string().contains("failed to load signing 
credential"),
+                    "unexpected error: {e}"
                 );
             }
         }
diff --git a/crates/storage/opendal/tests/resolving_storage_test.rs 
b/crates/storage/opendal/tests/resolving_storage_test.rs
index c23508950..1853a796d 100644
--- a/crates/storage/opendal/tests/resolving_storage_test.rs
+++ b/crates/storage/opendal/tests/resolving_storage_test.rs
@@ -257,19 +257,21 @@ mod tests {
     #[cfg(feature = "opendal-s3")]
     #[tokio::test]
     async fn test_with_custom_credential_loader() {
-        use async_trait::async_trait;
-        use iceberg_storage_opendal::CustomAwsCredentialLoader;
-        use reqsign::{AwsCredential, AwsCredentialLoad};
-        use reqwest::Client;
+        use iceberg_storage_opendal::{
+            AwsCredential, CustomAwsCredentialLoader, ProvideCredential,
+        };
+        use reqsign_core::Context;
 
+        #[derive(Debug)]
         struct MinioCredentialLoader;
 
-        #[async_trait]
-        impl AwsCredentialLoad for MinioCredentialLoader {
-            async fn load_credential(
+        impl ProvideCredential for MinioCredentialLoader {
+            type Credential = AwsCredential;
+
+            async fn provide_credential(
                 &self,
-                _client: Client,
-            ) -> anyhow::Result<Option<AwsCredential>> {
+                _ctx: &Context,
+            ) -> reqsign_core::Result<Option<AwsCredential>> {
                 Ok(Some(AwsCredential {
                     access_key_id: "admin".to_string(),
                     secret_access_key: "password".to_string(),
@@ -282,9 +284,8 @@ mod tests {
         set_up();
         let minio_endpoint = get_minio_endpoint();
 
-        let factory = 
OpenDalResolvingStorageFactory::new().with_s3_credential_loader(
-            CustomAwsCredentialLoader::new(Arc::new(MinioCredentialLoader)),
-        );
+        let factory = OpenDalResolvingStorageFactory::new()
+            
.with_s3_credential_loader(CustomAwsCredentialLoader::new(MinioCredentialLoader));
 
         let file_io = FileIOBuilder::new(Arc::new(factory))
             .with_props(vec![


Reply via email to