#
tokens: 44989/50000 1/1362 files (page 71/74)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 71 of 74. Use http://codebase.md/apache/opendal?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .asf.yaml
├── .config
│   └── nextest.toml
├── .devcontainer
│   ├── devcontainer.json
│   └── post_create.sh
├── .editorconfig
├── .env.example
├── .gitattributes
├── .github
│   ├── actions
│   │   ├── fuzz_test
│   │   │   └── action.yaml
│   │   ├── setup
│   │   │   └── action.yaml
│   │   ├── setup-hadoop
│   │   │   └── action.yaml
│   │   ├── setup-ocaml
│   │   │   └── action.yaml
│   │   ├── test_behavior_binding_c
│   │   │   └── action.yaml
│   │   ├── test_behavior_binding_cpp
│   │   │   └── action.yaml
│   │   ├── test_behavior_binding_go
│   │   │   └── action.yaml
│   │   ├── test_behavior_binding_java
│   │   │   └── action.yaml
│   │   ├── test_behavior_binding_nodejs
│   │   │   └── action.yaml
│   │   ├── test_behavior_binding_python
│   │   │   └── action.yaml
│   │   ├── test_behavior_core
│   │   │   └── action.yaml
│   │   └── test_behavior_integration_object_store
│   │       └── action.yml
│   ├── CODEOWNERS
│   ├── dependabot.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── 1-bug-report.yml
│   │   ├── 2-feature-request.yml
│   │   ├── 3-new-release.md
│   │   └── config.yml
│   ├── pull_request_template.md
│   ├── release.yml
│   ├── scripts
│   │   ├── test_behavior
│   │   │   ├── __init__.py
│   │   │   ├── plan.py
│   │   │   └── test_plan.py
│   │   ├── test_go_binding
│   │   │   ├── generate_test_scheme.py
│   │   │   └── matrix.yaml
│   │   └── weekly_update
│   │       ├── .gitignore
│   │       ├── .python-version
│   │       ├── main.py
│   │       ├── pyproject.toml
│   │       ├── README.md
│   │       └── uv.lock
│   ├── services
│   │   ├── aliyun_drive
│   │   │   └── aliyun_drive
│   │   │       └── disable_action.yml
│   │   ├── alluxio
│   │   │   └── alluxio
│   │   │       └── action.yml
│   │   ├── azblob
│   │   │   ├── azure_azblob
│   │   │   │   └── action.yml
│   │   │   └── azurite_azblob
│   │   │       └── action.yml
│   │   ├── azdls
│   │   │   └── azdls
│   │   │       └── action.yml
│   │   ├── azfile
│   │   │   └── azfile
│   │   │       └── action.yml
│   │   ├── b2
│   │   │   └── b2
│   │   │       └── action.yml
│   │   ├── cacache
│   │   │   └── cacache
│   │   │       └── action.yml
│   │   ├── compfs
│   │   │   └── compfs
│   │   │       └── action.yml
│   │   ├── cos
│   │   │   └── cos
│   │   │       └── action.yml
│   │   ├── dashmap
│   │   │   └── dashmap
│   │   │       └── action.yml
│   │   ├── dropbox
│   │   │   └── dropbox
│   │   │       └── disable_action.yml
│   │   ├── etcd
│   │   │   ├── etcd
│   │   │   │   └── action.yml
│   │   │   ├── etcd-cluster
│   │   │   │   └── action.yml
│   │   │   └── etcd-tls
│   │   │       └── action.yml
│   │   ├── fs
│   │   │   └── local_fs
│   │   │       └── action.yml
│   │   ├── ftp
│   │   │   └── vsftpd
│   │   │       └── disable_action.yml
│   │   ├── gcs
│   │   │   ├── gcs
│   │   │   │   └── action.yml
│   │   │   └── gcs_with_default_storage_class
│   │   │       └── action.yml
│   │   ├── gdrive
│   │   │   └── gdrive
│   │   │       └── action.yml
│   │   ├── gridfs
│   │   │   ├── gridfs
│   │   │   │   └── action.yml
│   │   │   └── gridfs_with_basic_auth
│   │   │       └── action.yml
│   │   ├── hdfs
│   │   │   ├── hdfs_cluster
│   │   │   │   └── action.yml
│   │   │   ├── hdfs_cluster_with_atomic_write_dir
│   │   │   │   └── action.yml
│   │   │   ├── hdfs_default
│   │   │   │   └── action.yml
│   │   │   ├── hdfs_default_gcs
│   │   │   │   └── action.yml
│   │   │   ├── hdfs_default_on_azurite_azblob
│   │   │   │   └── action.yml
│   │   │   ├── hdfs_default_on_minio_s3
│   │   │   │   └── action.yml
│   │   │   └── hdfs_default_with_atomic_write_dir
│   │   │       └── action.yml
│   │   ├── hdfs_native
│   │   │   └── hdfs_native_cluster
│   │   │       └── action.yml
│   │   ├── http
│   │   │   ├── caddy
│   │   │   │   └── action.yml
│   │   │   └── nginx
│   │   │       └── action.yml
│   │   ├── huggingface
│   │   │   └── huggingface
│   │   │       └── action.yml
│   │   ├── koofr
│   │   │   └── koofr
│   │   │       └── disable_action.yml
│   │   ├── memcached
│   │   │   ├── memcached
│   │   │   │   └── action.yml
│   │   │   └── memcached_with_auth
│   │   │       └── action.yml
│   │   ├── memory
│   │   │   └── memory
│   │   │       └── action.yml
│   │   ├── mini_moka
│   │   │   └── mini_moka
│   │   │       └── action.yml
│   │   ├── moka
│   │   │   └── moka
│   │   │       └── action.yml
│   │   ├── mongodb
│   │   │   ├── mongodb_with_basic_auth
│   │   │   │   └── action.yml
│   │   │   └── mongodb_with_no_auth
│   │   │       └── action.yml
│   │   ├── monoiofs
│   │   │   └── monoiofs
│   │   │       └── action.yml
│   │   ├── mysql
│   │   │   └── mysql
│   │   │       └── action.yml
│   │   ├── oss
│   │   │   ├── oss
│   │   │   │   └── action.yml
│   │   │   └── oss_with_versioning
│   │   │       └── action.yml
│   │   ├── persy
│   │   │   └── persy
│   │   │       └── action.yml
│   │   ├── postgresql
│   │   │   └── postgresql
│   │   │       └── action.yml
│   │   ├── redb
│   │   │   └── redb
│   │   │       └── action.yml
│   │   ├── redis
│   │   │   ├── dragonfly
│   │   │   │   └── action.yml
│   │   │   ├── kvrocks
│   │   │   │   └── action.yml
│   │   │   ├── redis
│   │   │   │   └── action.yml
│   │   │   ├── redis_tls
│   │   │   │   └── action.yml
│   │   │   ├── redis_with_cluster
│   │   │   │   └── action.yml
│   │   │   └── redis_with_cluster_tls
│   │   │       └── action.yml
│   │   ├── rocksdb
│   │   │   └── rocksdb
│   │   │       └── action.yml
│   │   ├── s3
│   │   │   ├── 0_minio_s3
│   │   │   │   └── action.yml
│   │   │   ├── aws_s3
│   │   │   │   └── action.yml
│   │   │   ├── aws_s3_with_list_objects_v1
│   │   │   │   └── action.yml
│   │   │   ├── aws_s3_with_sse_c
│   │   │   │   └── action.yml
│   │   │   ├── aws_s3_with_versioning
│   │   │   │   └── action.yml
│   │   │   ├── aws_s3_with_virtual_host
│   │   │   │   └── action.yml
│   │   │   ├── ceph_radios_s3_with_versioning
│   │   │   │   └── disable_action.yml
│   │   │   ├── ceph_rados_s3
│   │   │   │   └── disable_action.yml
│   │   │   ├── minio_s3_with_anonymous
│   │   │   │   └── action.yml
│   │   │   ├── minio_s3_with_list_objects_v1
│   │   │   │   └── action.yml
│   │   │   ├── minio_s3_with_versioning
│   │   │   │   └── action.yml
│   │   │   └── r2
│   │   │       └── disabled_action.yml
│   │   ├── seafile
│   │   │   └── seafile
│   │   │       └── action.yml
│   │   ├── sftp
│   │   │   ├── sftp
│   │   │   │   └── action.yml
│   │   │   └── sftp_with_default_root
│   │   │       └── action.yml
│   │   ├── sled
│   │   │   ├── sled
│   │   │   │   └── action.yml
│   │   │   └── sled_with_tree
│   │   │       └── action.yml
│   │   ├── sqlite
│   │   │   └── sqlite
│   │   │       └── action.yml
│   │   ├── swift
│   │   │   ├── ceph_rados_swift
│   │   │   │   └── action.yml
│   │   │   └── swift
│   │   │       └── action.yml
│   │   ├── tikv
│   │   │   └── tikv
│   │   │       └── disable_action.yml
│   │   ├── webdav
│   │   │   ├── 0_nginx
│   │   │   │   └── action.yml
│   │   │   ├── jfrog
│   │   │   │   └── disabled_action.yml
│   │   │   ├── nextcloud
│   │   │   │   └── action.yml
│   │   │   ├── nginx_with_empty_password
│   │   │   │   └── action.yml
│   │   │   ├── nginx_with_password
│   │   │   │   └── action.yml
│   │   │   ├── nginx_with_redirect
│   │   │   │   └── action.yml
│   │   │   └── owncloud
│   │   │       └── action.yml
│   │   └── webhdfs
│   │       ├── webhdfs
│   │       │   └── action.yml
│   │       ├── webhdfs_with_list_batch_disabled
│   │       │   └── action.yml
│   │       └── webhdfs_with_user_name
│   │           └── action.yml
│   └── workflows
│       ├── ci_bindings_c.yml
│       ├── ci_bindings_cpp.yml
│       ├── ci_bindings_d.yml
│       ├── ci_bindings_dart.yml
│       ├── ci_bindings_dotnet.yml
│       ├── ci_bindings_go.yml
│       ├── ci_bindings_haskell.yml
│       ├── ci_bindings_java.yml
│       ├── ci_bindings_lua.yml
│       ├── ci_bindings_nodejs.yml
│       ├── ci_bindings_ocaml.yml
│       ├── ci_bindings_php.yml
│       ├── ci_bindings_python.yml
│       ├── ci_bindings_ruby.yml
│       ├── ci_bindings_swift.yml
│       ├── ci_bindings_zig.yml
│       ├── ci_check.yml
│       ├── ci_core.yml
│       ├── ci_integration_dav_server.yml
│       ├── ci_integration_object_store.yml
│       ├── ci_integration_parquet.yml
│       ├── ci_integration_spring.yml
│       ├── ci_integration_unftp_sbe.yml
│       ├── ci_odev.yml
│       ├── ci_weekly_update.yml
│       ├── discussion-thread-link.yml
│       ├── docs.yml
│       ├── full-ci-promote.yml
│       ├── release_dart.yml
│       ├── release_java.yml
│       ├── release_nodejs.yml
│       ├── release_python.yml
│       ├── release_ruby.yml
│       ├── release_rust.yml
│       ├── service_test_ghac.yml
│       ├── test_behavior_binding_c.yml
│       ├── test_behavior_binding_cpp.yml
│       ├── test_behavior_binding_go.yml
│       ├── test_behavior_binding_java.yml
│       ├── test_behavior_binding_nodejs.yml
│       ├── test_behavior_binding_python.yml
│       ├── test_behavior_core.yml
│       ├── test_behavior_integration_object_store.yml
│       ├── test_behavior.yml
│       ├── test_edge.yml
│       └── test_fuzz.yml
├── .gitignore
├── .taplo.toml
├── .typos.toml
├── .vscode
│   └── settings.json
├── .yamlfmt
├── AGENTS.md
├── bindings
│   ├── java
│   │   ├── .cargo
│   │   │   └── config.toml
│   │   ├── .gitignore
│   │   ├── .mvn
│   │   │   └── wrapper
│   │   │       └── maven-wrapper.properties
│   │   ├── Cargo.toml
│   │   ├── DEPENDENCIES.md
│   │   ├── DEPENDENCIES.rust.tsv
│   │   ├── mvnw
│   │   ├── mvnw.cmd
│   │   ├── pom.xml
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── async_operator.rs
│   │   │   ├── convert.rs
│   │   │   ├── error.rs
│   │   │   ├── executor.rs
│   │   │   ├── layer.rs
│   │   │   ├── lib.rs
│   │   │   ├── main
│   │   │   │   ├── java
│   │   │   │   │   └── org
│   │   │   │   │       └── apache
│   │   │   │   │           └── opendal
│   │   │   │   │               ├── AsyncExecutor.java
│   │   │   │   │               ├── AsyncOperator.java
│   │   │   │   │               ├── Capability.java
│   │   │   │   │               ├── Entry.java
│   │   │   │   │               ├── Environment.java
│   │   │   │   │               ├── layer
│   │   │   │   │               │   ├── ConcurrentLimitLayer.java
│   │   │   │   │               │   ├── package-info.java
│   │   │   │   │               │   └── RetryLayer.java
│   │   │   │   │               ├── Layer.java
│   │   │   │   │               ├── ListOptions.java
│   │   │   │   │               ├── Metadata.java
│   │   │   │   │               ├── NativeLibrary.java
│   │   │   │   │               ├── NativeObject.java
│   │   │   │   │               ├── OpenDAL.java
│   │   │   │   │               ├── OpenDALException.java
│   │   │   │   │               ├── Operator.java
│   │   │   │   │               ├── OperatorInfo.java
│   │   │   │   │               ├── OperatorInputStream.java
│   │   │   │   │               ├── OperatorOutputStream.java
│   │   │   │   │               ├── package-info.java
│   │   │   │   │               ├── PresignedRequest.java
│   │   │   │   │               ├── ReadOptions.java
│   │   │   │   │               ├── ServiceConfig.java
│   │   │   │   │               ├── StatOptions.java
│   │   │   │   │               └── WriteOptions.java
│   │   │   │   └── resources
│   │   │   │       ├── bindings.properties
│   │   │   │       └── META-INF
│   │   │   │           └── NOTICE
│   │   │   ├── operator_input_stream.rs
│   │   │   ├── operator_output_stream.rs
│   │   │   ├── operator.rs
│   │   │   ├── test
│   │   │   │   └── java
│   │   │   │       └── org
│   │   │   │           └── apache
│   │   │   │               └── opendal
│   │   │   │                   └── test
│   │   │   │                       ├── AsyncExecutorTest.java
│   │   │   │                       ├── behavior
│   │   │   │                       │   ├── AsyncCopyTest.java
│   │   │   │                       │   ├── AsyncCreateDirTest.java
│   │   │   │                       │   ├── AsyncListTest.java
│   │   │   │                       │   ├── AsyncPresignTest.java
│   │   │   │                       │   ├── AsyncReadOnlyTest.java
│   │   │   │                       │   ├── AsyncRenameTest.java
│   │   │   │                       │   ├── AsyncStatOptionsTest.java
│   │   │   │                       │   ├── AsyncWriteOptionsTest.java
│   │   │   │                       │   ├── AsyncWriteTest.java
│   │   │   │                       │   ├── BehaviorExtension.java
│   │   │   │                       │   ├── BehaviorTestBase.java
│   │   │   │                       │   ├── BlockingCopyTest.java
│   │   │   │                       │   ├── BlockingCreateDirTest.java
│   │   │   │                       │   ├── BlockingListTest.java
│   │   │   │                       │   ├── BlockingReadOnlyTest.java
│   │   │   │                       │   ├── BlockingRenameTest.java
│   │   │   │                       │   ├── BlockingStatOptionsTest.java
│   │   │   │                       │   ├── BlockingWriteOptionTest.java
│   │   │   │                       │   ├── BlockingWriteTest.java
│   │   │   │                       │   └── RegressionTest.java
│   │   │   │                       ├── condition
│   │   │   │                       │   └── OpenDALExceptionCondition.java
│   │   │   │                       ├── LayerTest.java
│   │   │   │                       ├── MetadataTest.java
│   │   │   │                       ├── OperatorDuplicateTest.java
│   │   │   │                       ├── OperatorInfoTest.java
│   │   │   │                       ├── OperatorInputOutputStreamTest.java
│   │   │   │                       ├── OperatorUtf8DecodeTest.java
│   │   │   │                       └── UtilityTest.java
│   │   │   └── utility.rs
│   │   ├── tools
│   │   │   └── build.py
│   │   ├── upgrade.md
│   │   └── users.md
│   ├── nodejs
│   │   ├── .cargo
│   │   │   └── config.toml
│   │   ├── .gitignore
│   │   ├── .node-version
│   │   ├── .npmignore
│   │   ├── .npmrc
│   │   ├── .prettierignore
│   │   ├── benchmark
│   │   │   ├── deno.ts
│   │   │   ├── node.js
│   │   │   └── README.md
│   │   ├── build.rs
│   │   ├── Cargo.toml
│   │   ├── CONTRIBUTING.md
│   │   ├── DEPENDENCIES.md
│   │   ├── DEPENDENCIES.rust.tsv
│   │   ├── devbox.json
│   │   ├── devbox.lock
│   │   ├── generated.d.ts
│   │   ├── generated.js
│   │   ├── index.cjs
│   │   ├── index.d.ts
│   │   ├── index.mjs
│   │   ├── npm
│   │   │   ├── darwin-arm64
│   │   │   │   ├── package.json
│   │   │   │   └── README.md
│   │   │   ├── darwin-x64
│   │   │   │   ├── package.json
│   │   │   │   └── README.md
│   │   │   ├── linux-arm64-gnu
│   │   │   │   ├── package.json
│   │   │   │   └── README.md
│   │   │   ├── linux-arm64-musl
│   │   │   │   ├── package.json
│   │   │   │   └── README.md
│   │   │   ├── linux-x64-gnu
│   │   │   │   ├── package.json
│   │   │   │   └── README.md
│   │   │   ├── linux-x64-musl
│   │   │   │   ├── package.json
│   │   │   │   └── README.md
│   │   │   ├── win32-arm64-msvc
│   │   │   │   ├── package.json
│   │   │   │   └── README.md
│   │   │   └── win32-x64-msvc
│   │   │       ├── package.json
│   │   │       └── README.md
│   │   ├── package.json
│   │   ├── pnpm-lock.yaml
│   │   ├── README.md
│   │   ├── scripts
│   │   │   └── header.mjs
│   │   ├── src
│   │   │   ├── capability.rs
│   │   │   ├── layer.rs
│   │   │   ├── lib.rs
│   │   │   └── options.rs
│   │   ├── tests
│   │   │   ├── service.test.mjs
│   │   │   ├── suites
│   │   │   │   ├── async.suite.mjs
│   │   │   │   ├── asyncDeleteOptions.suite.mjs
│   │   │   │   ├── asyncLister.suite.mjs
│   │   │   │   ├── asyncListOptions.suite.mjs
│   │   │   │   ├── asyncReadOptions.suite.mjs
│   │   │   │   ├── asyncStatOptions.suite.mjs
│   │   │   │   ├── asyncWriteOptions.suite.mjs
│   │   │   │   ├── index.mjs
│   │   │   │   ├── layer.suite.mjs
│   │   │   │   ├── services.suite.mjs
│   │   │   │   ├── sync.suite.mjs
│   │   │   │   ├── syncDeleteOptions.suite.mjs
│   │   │   │   ├── syncLister.suite.mjs
│   │   │   │   ├── syncListOptions.suite.mjs
│   │   │   │   ├── syncReadOptions.suite.mjs
│   │   │   │   ├── syncStatOptions.suite.mjs
│   │   │   │   └── syncWriteOptions.suite.mjs
│   │   │   └── utils.mjs
│   │   ├── theme
│   │   │   ├── index.tsx
│   │   │   └── package.json
│   │   ├── tsconfig.json
│   │   ├── tsconfig.theme.json
│   │   ├── typedoc.json
│   │   ├── upgrade.md
│   │   └── vitest.config.mjs
│   ├── python
│   │   ├── .gitignore
│   │   ├── benchmark
│   │   │   ├── async_opendal_benchmark.py
│   │   │   ├── async_origin_s3_benchmark_with_gevent.py
│   │   │   └── README.md
│   │   ├── Cargo.toml
│   │   ├── CONTRIBUTING.md
│   │   ├── DEPENDENCIES.md
│   │   ├── DEPENDENCIES.rust.tsv
│   │   ├── docs
│   │   │   ├── api
│   │   │   │   ├── async_file.md
│   │   │   │   ├── async_operator.md
│   │   │   │   ├── capability.md
│   │   │   │   ├── exceptions.md
│   │   │   │   ├── file.md
│   │   │   │   ├── layers.md
│   │   │   │   ├── operator.md
│   │   │   │   └── types.md
│   │   │   └── index.md
│   │   ├── justfile
│   │   ├── mkdocs.yml
│   │   ├── pyproject.toml
│   │   ├── pyrightconfig.json
│   │   ├── python
│   │   │   └── opendal
│   │   │       ├── __init__.py
│   │   │       ├── capability.pyi
│   │   │       ├── exceptions.pyi
│   │   │       ├── file.pyi
│   │   │       ├── layers.pyi
│   │   │       ├── operator.pyi
│   │   │       ├── py.typed
│   │   │       ├── services.pyi
│   │   │       └── types.pyi
│   │   ├── README.md
│   │   ├── ruff.toml
│   │   ├── src
│   │   │   ├── capability.rs
│   │   │   ├── errors.rs
│   │   │   ├── file.rs
│   │   │   ├── layers.rs
│   │   │   ├── lib.rs
│   │   │   ├── lister.rs
│   │   │   ├── metadata.rs
│   │   │   ├── operator.rs
│   │   │   ├── options.rs
│   │   │   ├── services.rs
│   │   │   └── utils.rs
│   │   ├── template
│   │   │   └── module.html.jinja2
│   │   ├── tests
│   │   │   ├── conftest.py
│   │   │   ├── test_async_check.py
│   │   │   ├── test_async_copy.py
│   │   │   ├── test_async_delete.py
│   │   │   ├── test_async_exists.py
│   │   │   ├── test_async_list.py
│   │   │   ├── test_async_pickle_types.py
│   │   │   ├── test_async_rename.py
│   │   │   ├── test_capability.py
│   │   │   ├── test_exceptions.py
│   │   │   ├── test_pickle_rw.py
│   │   │   ├── test_read.py
│   │   │   ├── test_sync_check.py
│   │   │   ├── test_sync_copy.py
│   │   │   ├── test_sync_delete.py
│   │   │   ├── test_sync_exists.py
│   │   │   ├── test_sync_list.py
│   │   │   ├── test_sync_pickle_types.py
│   │   │   ├── test_sync_rename.py
│   │   │   └── test_write.py
│   │   ├── upgrade.md
│   │   ├── users.md
│   │   └── uv.lock
│   └── README.md
├── CHANGELOG.md
├── CITATION.cff
├── CLAUDE.md
├── CONTRIBUTING.md
├── core
│   ├── benches
│   │   ├── ops
│   │   │   ├── main.rs
│   │   │   ├── read.rs
│   │   │   ├── README.md
│   │   │   ├── utils.rs
│   │   │   └── write.rs
│   │   ├── README.md
│   │   ├── types
│   │   │   ├── buffer.rs
│   │   │   ├── main.rs
│   │   │   ├── README.md
│   │   │   └── tasks.rs
│   │   ├── vs_fs
│   │   │   ├── Cargo.toml
│   │   │   ├── README.md
│   │   │   └── src
│   │   │       └── main.rs
│   │   └── vs_s3
│   │       ├── Cargo.toml
│   │       ├── README.md
│   │       └── src
│   │           └── main.rs
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── CHANGELOG.md
│   ├── CONTRIBUTING.md
│   ├── core
│   │   ├── Cargo.toml
│   │   └── src
│   │       ├── blocking
│   │       │   ├── delete.rs
│   │       │   ├── list.rs
│   │       │   ├── mod.rs
│   │       │   ├── operator.rs
│   │       │   ├── read
│   │       │   │   ├── buffer_iterator.rs
│   │       │   │   ├── mod.rs
│   │       │   │   ├── reader.rs
│   │       │   │   ├── std_bytes_iterator.rs
│   │       │   │   └── std_reader.rs
│   │       │   └── write
│   │       │       ├── mod.rs
│   │       │       ├── std_writer.rs
│   │       │       └── writer.rs
│   │       ├── docs
│   │       │   ├── comparisons
│   │       │   │   ├── mod.rs
│   │       │   │   └── vs_object_store.md
│   │       │   ├── concepts.rs
│   │       │   ├── internals
│   │       │   │   ├── accessor.rs
│   │       │   │   ├── layer.rs
│   │       │   │   └── mod.rs
│   │       │   ├── mod.rs
│   │       │   ├── performance
│   │       │   │   ├── concurrent_write.md
│   │       │   │   ├── http_optimization.md
│   │       │   │   └── mod.rs
│   │       │   ├── rfcs
│   │       │   │   ├── 0000_example.md
│   │       │   │   ├── 0041_object_native_api.md
│   │       │   │   ├── 0044_error_handle.md
│   │       │   │   ├── 0057_auto_region.md
│   │       │   │   ├── 0069_object_stream.md
│   │       │   │   ├── 0090_limited_reader.md
│   │       │   │   ├── 0112_path_normalization.md
│   │       │   │   ├── 0191_async_streaming_io.md
│   │       │   │   ├── 0203_remove_credential.md
│   │       │   │   ├── 0221_create_dir.md
│   │       │   │   ├── 0247_retryable_error.md
│   │       │   │   ├── 0293_object_id.md
│   │       │   │   ├── 0337_dir_entry.md
│   │       │   │   ├── 0409_accessor_capabilities.md
│   │       │   │   ├── 0413_presign.md
│   │       │   │   ├── 0423_command_line_interface.md
│   │       │   │   ├── 0429_init_from_iter.md
│   │       │   │   ├── 0438_multipart.md
│   │       │   │   ├── 0443_gateway.md
│   │       │   │   ├── 0501_new_builder.md
│   │       │   │   ├── 0554_write_refactor.md
│   │       │   │   ├── 0561_list_metadata_reuse.md
│   │       │   │   ├── 0599_blocking_api.md
│   │       │   │   ├── 0623_redis_service.md
│   │       │   │   ├── 0627_split_capabilities.md
│   │       │   │   ├── 0661_path_in_accessor.md
│   │       │   │   ├── 0793_generic_kv_services.md
│   │       │   │   ├── 0926_object_reader.md
│   │       │   │   ├── 0977_refactor_error.md
│   │       │   │   ├── 1085_object_handler.md
│   │       │   │   ├── 1391_object_metadataer.md
│   │       │   │   ├── 1398_query_based_metadata.md
│   │       │   │   ├── 1420_object_writer.md
│   │       │   │   ├── 1477_remove_object_concept.md
│   │       │   │   ├── 1735_operation_extension.md
│   │       │   │   ├── 2083_writer_sink_api.md
│   │       │   │   ├── 2133_append_api.md
│   │       │   │   ├── 2299_chain_based_operator_api.md
│   │       │   │   ├── 2602_object_versioning.md
│   │       │   │   ├── 2758_merge_append_into_write.md
│   │       │   │   ├── 2774_lister_api.md
│   │       │   │   ├── 2779_list_with_metakey.md
│   │       │   │   ├── 2852_native_capability.md
│   │       │   │   ├── 2884_merge_range_read_into_read.md
│   │       │   │   ├── 3017_remove_write_copy_from.md
│   │       │   │   ├── 3197_config.md
│   │       │   │   ├── 3232_align_list_api.md
│   │       │   │   ├── 3243_list_prefix.md
│   │       │   │   ├── 3356_lazy_reader.md
│   │       │   │   ├── 3526_list_recursive.md
│   │       │   │   ├── 3574_concurrent_stat_in_list.md
│   │       │   │   ├── 3734_buffered_reader.md
│   │       │   │   ├── 3898_concurrent_writer.md
│   │       │   │   ├── 3911_deleter_api.md
│   │       │   │   ├── 4382_range_based_read.md
│   │       │   │   ├── 4638_executor.md
│   │       │   │   ├── 5314_remove_metakey.md
│   │       │   │   ├── 5444_operator_from_uri.md
│   │       │   │   ├── 5479_context.md
│   │       │   │   ├── 5485_conditional_reader.md
│   │       │   │   ├── 5495_list_with_deleted.md
│   │       │   │   ├── 5556_write_returns_metadata.md
│   │       │   │   ├── 5871_read_returns_metadata.md
│   │       │   │   ├── 6189_remove_native_blocking.md
│   │       │   │   ├── 6209_glob_support.md
│   │       │   │   ├── 6213_options_api.md
│   │       │   │   ├── 6370_foyer_integration.md
│   │       │   │   ├── 6678_simulate_layer.md
│   │       │   │   ├── 6707_capability_override_layer.md
│   │       │   │   ├── 6817_checksum.md
│   │       │   │   ├── 6828_core.md
│   │       │   │   ├── 7130_route_layer.md
│   │       │   │   ├── mod.rs
│   │       │   │   └── README.md
│   │       │   └── upgrade.md
│   │       ├── layers
│   │       │   ├── complete.rs
│   │       │   ├── correctness_check.rs
│   │       │   ├── error_context.rs
│   │       │   ├── http_client.rs
│   │       │   ├── mod.rs
│   │       │   ├── simulate.rs
│   │       │   └── type_eraser.rs
│   │       ├── lib.rs
│   │       ├── raw
│   │       │   ├── accessor.rs
│   │       │   ├── atomic_util.rs
│   │       │   ├── enum_utils.rs
│   │       │   ├── futures_util.rs
│   │       │   ├── http_util
│   │       │   │   ├── body.rs
│   │       │   │   ├── bytes_content_range.rs
│   │       │   │   ├── bytes_range.rs
│   │       │   │   ├── client.rs
│   │       │   │   ├── error.rs
│   │       │   │   ├── header.rs
│   │       │   │   ├── mod.rs
│   │       │   │   ├── multipart.rs
│   │       │   │   └── uri.rs
│   │       │   ├── layer.rs
│   │       │   ├── mod.rs
│   │       │   ├── oio
│   │       │   │   ├── buf
│   │       │   │   │   ├── flex_buf.rs
│   │       │   │   │   ├── mod.rs
│   │       │   │   │   ├── pooled_buf.rs
│   │       │   │   │   └── queue_buf.rs
│   │       │   │   ├── delete
│   │       │   │   │   ├── api.rs
│   │       │   │   │   ├── batch_delete.rs
│   │       │   │   │   ├── mod.rs
│   │       │   │   │   └── one_shot_delete.rs
│   │       │   │   ├── entry.rs
│   │       │   │   ├── list
│   │       │   │   │   ├── api.rs
│   │       │   │   │   ├── flat_list.rs
│   │       │   │   │   ├── hierarchy_list.rs
│   │       │   │   │   ├── mod.rs
│   │       │   │   │   ├── page_list.rs
│   │       │   │   │   └── prefix_list.rs
│   │       │   │   ├── mod.rs
│   │       │   │   ├── read
│   │       │   │   │   ├── api.rs
│   │       │   │   │   └── mod.rs
│   │       │   │   └── write
│   │       │   │       ├── api.rs
│   │       │   │       ├── append_write.rs
│   │       │   │       ├── block_write.rs
│   │       │   │       ├── mod.rs
│   │       │   │       ├── multipart_write.rs
│   │       │   │       ├── one_shot_write.rs
│   │       │   │       └── position_write.rs
│   │       │   ├── operation.rs
│   │       │   ├── ops.rs
│   │       │   ├── path_cache.rs
│   │       │   ├── path.rs
│   │       │   ├── rps.rs
│   │       │   ├── serde_util.rs
│   │       │   ├── std_io_util.rs
│   │       │   ├── time.rs
│   │       │   ├── tokio_util.rs
│   │       │   └── version.rs
│   │       ├── services
│   │       │   ├── memory
│   │       │   │   ├── backend.rs
│   │       │   │   ├── config.rs
│   │       │   │   ├── core.rs
│   │       │   │   ├── deleter.rs
│   │       │   │   ├── docs.md
│   │       │   │   ├── lister.rs
│   │       │   │   ├── mod.rs
│   │       │   │   └── writer.rs
│   │       │   └── mod.rs
│   │       └── types
│   │           ├── buffer.rs
│   │           ├── builder.rs
│   │           ├── capability.rs
│   │           ├── context
│   │           │   ├── mod.rs
│   │           │   ├── read.rs
│   │           │   └── write.rs
│   │           ├── delete
│   │           │   ├── deleter.rs
│   │           │   ├── futures_delete_sink.rs
│   │           │   ├── input.rs
│   │           │   └── mod.rs
│   │           ├── entry.rs
│   │           ├── error.rs
│   │           ├── execute
│   │           │   ├── api.rs
│   │           │   ├── executor.rs
│   │           │   ├── executors
│   │           │   │   ├── mod.rs
│   │           │   │   └── tokio_executor.rs
│   │           │   └── mod.rs
│   │           ├── list.rs
│   │           ├── metadata.rs
│   │           ├── mod.rs
│   │           ├── mode.rs
│   │           ├── operator
│   │           │   ├── builder.rs
│   │           │   ├── info.rs
│   │           │   ├── mod.rs
│   │           │   ├── operator_futures.rs
│   │           │   ├── operator.rs
│   │           │   ├── registry.rs
│   │           │   └── uri.rs
│   │           ├── options.rs
│   │           ├── read
│   │           │   ├── buffer_stream.rs
│   │           │   ├── futures_async_reader.rs
│   │           │   ├── futures_bytes_stream.rs
│   │           │   ├── mod.rs
│   │           │   └── reader.rs
│   │           └── write
│   │               ├── buffer_sink.rs
│   │               ├── futures_async_writer.rs
│   │               ├── futures_bytes_sink.rs
│   │               ├── mod.rs
│   │               └── writer.rs
│   ├── DEPENDENCIES.md
│   ├── DEPENDENCIES.rust.tsv
│   ├── edge
│   │   ├── file_write_on_full_disk
│   │   │   ├── Cargo.toml
│   │   │   ├── README.md
│   │   │   └── src
│   │   │       └── main.rs
│   │   ├── README.md
│   │   ├── s3_aws_assume_role_with_web_identity
│   │   │   ├── Cargo.toml
│   │   │   ├── README.md
│   │   │   └── src
│   │   │       └── main.rs
│   │   └── s3_read_on_wasm
│   │       ├── .gitignore
│   │       ├── Cargo.toml
│   │       ├── README.md
│   │       ├── src
│   │       │   └── lib.rs
│   │       └── webdriver.json
│   ├── fuzz
│   │   ├── .gitignore
│   │   ├── Cargo.toml
│   │   ├── fuzz_reader.rs
│   │   ├── fuzz_writer.rs
│   │   └── README.md
│   ├── layers
│   │   ├── async-backtrace
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── await-tree
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── capability-check
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── chaos
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── concurrent-limit
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── dtrace
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── fastmetrics
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── fastrace
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── foyer
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── hotpath
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── immutable-index
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── logging
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── metrics
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── mime-guess
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── observe-metrics-common
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── otelmetrics
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── oteltrace
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── prometheus
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── prometheus-client
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── retry
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── route
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── tail-cut
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── throttle
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── timeout
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   └── tracing
│   │       ├── Cargo.toml
│   │       └── src
│   │           └── lib.rs
│   ├── LICENSE
│   ├── README.md
│   ├── services
│   │   ├── aliyun-drive
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── alluxio
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── azblob
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── azdls
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── azfile
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── azure-common
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       └── lib.rs
│   │   ├── b2
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── cacache
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── cloudflare-kv
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── model.rs
│   │   │       └── writer.rs
│   │   ├── compfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── reader.rs
│   │   │       └── writer.rs
│   │   ├── cos
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── d1
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── model.rs
│   │   │       └── writer.rs
│   │   ├── dashmap
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── dbfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── dropbox
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── builder.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── etcd
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── foundationdb
│   │   │   ├── build.rs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── fs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── reader.rs
│   │   │       └── writer.rs
│   │   ├── ftp
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── err.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── reader.rs
│   │   │       └── writer.rs
│   │   ├── gcs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── uri.rs
│   │   │       └── writer.rs
│   │   ├── gdrive
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── builder.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── ghac
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── github
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── mod.rs
│   │   │       └── writer.rs
│   │   ├── gridfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── hdfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── reader.rs
│   │   │       └── writer.rs
│   │   ├── hdfs-native
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── reader.rs
│   │   │       └── writer.rs
│   │   ├── http
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       └── lib.rs
│   │   ├── huggingface
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       └── lister.rs
│   │   ├── ipfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── ipld.rs
│   │   │       └── lib.rs
│   │   ├── ipmfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── builder.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── koofr
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── lakefs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── memcached
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── binary.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── mini_moka
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── moka
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── mongodb
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── monoiofs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       ├── reader.rs
│   │   │       └── writer.rs
│   │   ├── mysql
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── obs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── onedrive
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── builder.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── graph_model.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── opfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       └── utils.rs
│   │   ├── oss
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── pcloud
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── persy
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── postgresql
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── redb
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── redis
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── delete.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── rocksdb
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── s3
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── compatible_services.md
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── mod.rs
│   │   │       └── writer.rs
│   │   ├── seafile
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── sftp
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── reader.rs
│   │   │       ├── utils.rs
│   │   │       └── writer.rs
│   │   ├── sled
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── sqlite
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── surrealdb
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── swift
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── compatible_services.md
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── tikv
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── upyun
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── vercel-artifacts
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── builder.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       └── writer.rs
│   │   ├── vercel-blob
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── webdav
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       └── writer.rs
│   │   ├── webhdfs
│   │   │   ├── Cargo.toml
│   │   │   └── src
│   │   │       ├── backend.rs
│   │   │       ├── config.rs
│   │   │       ├── core.rs
│   │   │       ├── deleter.rs
│   │   │       ├── docs.md
│   │   │       ├── error.rs
│   │   │       ├── lib.rs
│   │   │       ├── lister.rs
│   │   │       ├── message.rs
│   │   │       └── writer.rs
│   │   └── yandex-disk
│   │       ├── Cargo.toml
│   │       └── src
│   │           ├── backend.rs
│   │           ├── config.rs
│   │           ├── core.rs
│   │           ├── deleter.rs
│   │           ├── docs.md
│   │           ├── error.rs
│   │           ├── lib.rs
│   │           ├── lister.rs
│   │           └── writer.rs
│   ├── src
│   │   └── lib.rs
│   ├── testkit
│   │   ├── Cargo.toml
│   │   └── src
│   │       ├── lib.rs
│   │       ├── read.rs
│   │       ├── utils.rs
│   │       └── write.rs
│   ├── tests
│   │   ├── behavior
│   │   │   ├── async_copy.rs
│   │   │   ├── async_create_dir.rs
│   │   │   ├── async_delete.rs
│   │   │   ├── async_list.rs
│   │   │   ├── async_presign.rs
│   │   │   ├── async_read.rs
│   │   │   ├── async_rename.rs
│   │   │   ├── async_stat.rs
│   │   │   ├── async_write.rs
│   │   │   ├── main.rs
│   │   │   ├── README.md
│   │   │   └── utils.rs
│   │   └── data
│   │       ├── normal_dir
│   │       │   └── .gitkeep
│   │       ├── normal_file.txt
│   │       ├── special_dir  !@#$%^&()_+-=;',
│   │       │   └── .gitkeep
│   │       └── special_file  !@#$%^&()_+-=;',.txt
│   ├── upgrade.md
│   └── users.md
├── deny.toml
├── DEPENDENCIES.md
├── dev
│   ├── Cargo.lock
│   ├── Cargo.toml
│   ├── README.md
│   └── src
│       ├── generate
│       │   ├── java.j2
│       │   ├── java.rs
│       │   ├── mod.rs
│       │   ├── parser.rs
│       │   ├── python.j2
│       │   └── python.rs
│       ├── main.rs
│       └── release
│           ├── mod.rs
│           └── package.rs
├── doap.rdf
├── fixtures
│   ├── alluxio
│   │   └── docker-compose-alluxio.yml
│   ├── azblob
│   │   └── docker-compose-azurite.yml
│   ├── data
│   │   ├── normal_dir
│   │   │   └── .gitkeep
│   │   ├── normal_file.txt
│   │   ├── special_dir  !@#$%^&()_+-=;',
│   │   │   └── .gitkeep
│   │   └── special_file  !@#$%^&()_+-=;',.txt
│   ├── etcd
│   │   ├── ca-key.pem
│   │   ├── ca.pem
│   │   ├── client-key.pem
│   │   ├── client.pem
│   │   ├── docker-compose-cluster.yml
│   │   ├── docker-compose-standalone-tls.yml
│   │   ├── docker-compose-standalone.yml
│   │   ├── server-key.pem
│   │   └── server.pem
│   ├── ftp
│   │   └── docker-compose-vsftpd.yml
│   ├── hdfs
│   │   ├── azurite-azblob-core-site.xml
│   │   ├── docker-compose-hdfs-cluster.yml
│   │   ├── gcs-core-site.xml
│   │   ├── hdfs-site.xml
│   │   └── minio-s3-core-site.xml
│   ├── http
│   │   ├── Caddyfile
│   │   ├── docker-compose-caddy.yml
│   │   ├── docker-compose-nginx.yml
│   │   └── nginx.conf
│   ├── libsql
│   │   ├── docker-compose-auth.yml
│   │   └── docker-compose.yml
│   ├── memcached
│   │   ├── docker-compose-memcached-with-auth.yml
│   │   └── docker-compose-memcached.yml
│   ├── mongodb
│   │   ├── docker-compose-basic-auth.yml
│   │   └── docker-compose-no-auth.yml
│   ├── mysql
│   │   ├── docker-compose.yml
│   │   └── init.sql
│   ├── postgresql
│   │   ├── docker-compose.yml
│   │   └── init.sql
│   ├── redis
│   │   ├── docker-compose-dragonfly.yml
│   │   ├── docker-compose-kvrocks.yml
│   │   ├── docker-compose-redis-cluster-tls.yml
│   │   ├── docker-compose-redis-cluster.yml
│   │   ├── docker-compose-redis-tls.yml
│   │   ├── docker-compose-redis.yml
│   │   └── ssl
│   │       ├── .gitignore
│   │       ├── ca.crt
│   │       ├── ca.key
│   │       ├── ca.srl
│   │       ├── README.md
│   │       ├── redis.crt
│   │       ├── redis.key
│   │       └── req.conf
│   ├── s3
│   │   ├── docker-compose-ceph-rados.yml
│   │   └── docker-compose-minio.yml
│   ├── seafile
│   │   └── docker-compose-seafile.yml
│   ├── sftp
│   │   ├── change_root_dir.sh
│   │   ├── docker-compose-sftp-with-default-root.yml
│   │   ├── docker-compose-sftp.yml
│   │   ├── health-check.sh
│   │   ├── test_ssh_key
│   │   └── test_ssh_key.pub
│   ├── sqlite
│   │   └── data.sql
│   ├── swift
│   │   ├── docker-compose-ceph-rados.yml
│   │   └── docker-compose-swift.yml
│   ├── tikv
│   │   ├── gen_cert.sh
│   │   ├── pd-tls.toml
│   │   ├── pd.toml
│   │   ├── ssl
│   │   │   ├── ca-key.pem
│   │   │   ├── ca.pem
│   │   │   ├── client-key.pem
│   │   │   ├── client.pem
│   │   │   ├── pd-server-key.pem
│   │   │   ├── pd-server.pem
│   │   │   ├── tikv-server-key.pem
│   │   │   └── tikv-server.pem
│   │   ├── tikv-tls.toml
│   │   └── tikv.toml
│   ├── webdav
│   │   ├── config
│   │   │   └── nginx
│   │   │       └── http.conf
│   │   ├── docker-compose-webdav-jfrog.yml
│   │   ├── docker-compose-webdav-nextcloud.yml
│   │   ├── docker-compose-webdav-owncloud.yml
│   │   ├── docker-compose-webdav-with-auth.yml
│   │   ├── docker-compose-webdav-with-empty-passwd.yml
│   │   ├── docker-compose-webdav.yml
│   │   └── health-check-nextcloud.sh
│   └── webhdfs
│       └── docker-compose-webhdfs.yml
├── justfile
├── LICENSE
├── licenserc.toml
├── NOTICE
├── README.md
├── rust-toolchain.toml
├── rustfmt.toml
└── scripts
    ├── constants.py
    ├── dependencies.py
    ├── merge_local_staging.py
    ├── README.md
    ├── verify.py
    └── workspace.py
```

# Files

--------------------------------------------------------------------------------
/core/core/src/types/operator/operator.rs:
--------------------------------------------------------------------------------

```rust
   1 | // Licensed to the Apache Software Foundation (ASF) under one
   2 | // or more contributor license agreements.  See the NOTICE file
   3 | // distributed with this work for additional information
   4 | // regarding copyright ownership.  The ASF licenses this file
   5 | // to you under the Apache License, Version 2.0 (the
   6 | // "License"); you may not use this file except in compliance
   7 | // with the License.  You may obtain a copy of the License at
   8 | //
   9 | //   http://www.apache.org/licenses/LICENSE-2.0
  10 | //
  11 | // Unless required by applicable law or agreed to in writing,
  12 | // software distributed under the License is distributed on an
  13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14 | // KIND, either express or implied.  See the License for the
  15 | // specific language governing permissions and limitations
  16 | // under the License.
  17 | 
  18 | use std::future::Future;
  19 | 
  20 | use futures::Stream;
  21 | use futures::StreamExt;
  22 | use futures::TryStreamExt;
  23 | 
  24 | use crate::operator_futures::*;
  25 | use crate::raw::oio::DeleteDyn;
  26 | use crate::raw::*;
  27 | use crate::types::delete::Deleter;
  28 | use crate::*;
  29 | 
  30 | /// The `Operator` serves as the entry point for all public asynchronous APIs.
  31 | ///
  32 | /// For more details about the `Operator`, refer to the [`concepts`][crate::docs::concepts] section.
  33 | ///
  34 | /// All cloned `Operator` instances share the same internal state, such as
  35 | /// `HttpClient` and `Runtime`. Some layers may modify the internal state of
  36 | /// the `Operator` too like inject logging and metrics for `HttpClient`.
  37 | ///
  38 | /// ## Build
  39 | ///
  40 | /// Users can initialize an `Operator` through the following methods:
  41 | ///
  42 | /// - [`Operator::new`]: Creates an operator using a [`services`] builder, such as [`services::Memory`].
  43 | /// - [`Operator::from_config`]: Creates an operator using a [`services`] configuration, such as [`services::MemoryConfig`].
  44 | /// - [`Operator::from_iter`]: Creates an operator from an iterator of configuration key-value pairs.
  45 | ///
  46 | /// ```
  47 | /// # use anyhow::Result;
  48 | /// use opendal_core::services::Memory;
  49 | /// use opendal_core::Operator;
  50 | /// async fn test() -> Result<()> {
  51 | ///     // Build an `Operator` to start operating the storage.
  52 | ///     let _: Operator = Operator::new(Memory::default())?.finish();
  53 | ///
  54 | ///     Ok(())
  55 | /// }
  56 | /// ```
  57 | ///
  58 | /// ## Layer
  59 | ///
  60 | /// After the operator is built, users can add the layers they need on top of it.
  61 | ///
  62 | /// OpenDAL offers various layers for users to choose from. Visit [`layers`] for further details.
  63 | ///
  64 | /// Please note that `Layer` can modify internal contexts such as `HttpClient`
  65 | /// and `Runtime` for all clones of given operator. Therefore, it is recommended
  66 | /// to add layers before interacting with the storage. Adding or duplicating
  67 | /// layers after accessing the storage may result in unexpected behavior.
  68 | ///
  69 | /// ```
  70 | /// use opendal_core::layers::HttpClientLayer;
  71 | /// use opendal_core::raw::HttpClient;
  72 | /// use opendal_core::services::Memory;
  73 | /// use opendal_core::Operator;
  74 | /// use opendal_core::Result;
  75 | ///
  76 | /// async fn test() -> Result<()> {
  77 | ///     let op: Operator = Operator::new(Memory::default())?.finish();
  78 | ///
  79 | ///     // OpenDAL will replace the default HTTP client now.
  80 | ///     let client = HttpClient::new()?;
  81 | ///     let op = op.layer(HttpClientLayer::new(client));
  82 | ///
  83 | ///     Ok(())
  84 | /// }
  85 | /// ```
  86 | ///
  87 | /// ## Operate
  88 | ///
  89 | /// After the operator is built and the layers are added, users can start operating the storage.
  90 | ///
  91 | /// The operator is `Send`, `Sync`, and `Clone`. It has no internal state, and all APIs only take
  92 | /// a `&self` reference, making it safe to share the operator across threads.
  93 | ///
  94 | /// Operator provides a consistent API pattern for data operations. For reading operations, it exposes:
  95 | ///
  96 | /// - [`Operator::read`]: Executes a read operation.
  97 | /// - [`Operator::read_with`]: Executes a read operation with additional options using the builder pattern.
  98 | /// - [`Operator::read_options`]: Executes a read operation with extra options provided via a [`options::ReadOptions`] struct.
  99 | /// - [`Operator::reader`]: Creates a reader for streaming data, allowing for flexible access.
 100 | /// - [`Operator::reader_with`]: Creates a reader with advanced options using the builder pattern.
 101 | /// - [`Operator::reader_options`]: Creates a reader with extra options provided via a [`options::ReadOptions`] struct.
 102 | ///
 103 | /// The [`Reader`] created by [`Operator`] supports custom read control methods and can be converted
 104 | /// into [`futures::AsyncRead`] or [`futures::Stream`] for broader ecosystem compatibility.
 105 | ///
 106 | /// ```no_run
 107 | /// use opendal_core::options;
 108 | /// use opendal_core::services;
 109 | /// use opendal_core::Operator;
 110 | /// use opendal_core::Result;
 111 | ///
 112 | /// #[tokio::main]
 113 | /// async fn main() -> Result<()> {
 114 | ///     // Pick a builder and configure it.
 115 | ///     let builder = services::Memory::default();
 116 | ///
 117 | ///     // Init an operator
 118 | ///     let op = Operator::new(builder)?.finish();
 119 | ///
 120 | ///     // Fetch this file's metadata
 121 | ///     let meta = op.stat("hello.txt").await?;
 122 | ///     let length = meta.content_length();
 123 | ///
 124 | ///     // Read data from `hello.txt` with options.
 125 | ///     let bs = op
 126 | ///         .read_with("hello.txt")
 127 | ///         .range(0..8 * 1024 * 1024)
 128 | ///         .chunk(1024 * 1024)
 129 | ///         .concurrent(4)
 130 | ///         .await?;
 131 | ///
 132 | ///     // The same to:
 133 | ///     let bs = op
 134 | ///         .read_options("hello.txt", options::ReadOptions {
 135 | ///             range: (0..8 * 1024 * 1024).into(),
 136 | ///             chunk: Some(1024 * 1024),
 137 | ///             concurrent: 4,
 138 | ///             ..Default::default()
 139 | ///         })
 140 | ///         .await?;
 141 | ///
 142 | ///     Ok(())
 143 | /// }
 144 | /// ```
 145 | #[derive(Clone, Debug)]
 146 | pub struct Operator {
 147 |     // accessor is what Operator delegates for
 148 |     accessor: Accessor,
 149 | }
 150 | 
 151 | /// # Operator basic API.
 152 | impl Operator {
 153 |     /// Fetch the internal accessor.
 154 |     pub fn inner(&self) -> &Accessor {
 155 |         &self.accessor
 156 |     }
 157 | 
 158 |     /// Convert inner accessor into operator.
 159 |     pub fn from_inner(accessor: Accessor) -> Self {
 160 |         Self { accessor }
 161 |     }
 162 | 
 163 |     /// Convert operator into inner accessor.
 164 |     pub fn into_inner(self) -> Accessor {
 165 |         self.accessor
 166 |     }
 167 | 
 168 |     /// Get information of underlying accessor.
 169 |     ///
 170 |     /// # Examples
 171 |     ///
 172 |     /// ```
 173 |     /// # use std::sync::Arc;
 174 |     /// # use anyhow::Result;
 175 |     /// use opendal_core::Operator;
 176 |     ///
 177 |     /// # async fn test(op: Operator) -> Result<()> {
 178 |     /// let info = op.info();
 179 |     /// # Ok(())
 180 |     /// # }
 181 |     /// ```
 182 |     pub fn info(&self) -> OperatorInfo {
 183 |         OperatorInfo::new(self.accessor.info())
 184 |     }
 185 | 
 186 |     /// Get the executor used by current operator.
 187 |     pub fn executor(&self) -> Executor {
 188 |         self.accessor.info().executor()
 189 |     }
 190 | 
 191 |     /// Update executor for the context.
 192 |     ///
 193 |     /// All cloned `Operator` instances share the same internal state, such as
 194 |     /// `HttpClient` and `Runtime`. Some layers may modify the internal state of
 195 |     /// the `Operator` too like inject logging and metrics for `HttpClient`.
 196 |     ///
 197 |     /// # Note
 198 |     ///
 199 |     /// Tasks must be forwarded to the old executor after the update. Otherwise, features such as retry, timeout, and metrics may not function properly.
 200 |     pub fn update_executor(&self, f: impl FnOnce(Executor) -> Executor) {
 201 |         self.accessor.info().update_executor(f);
 202 |     }
 203 | }
 204 | 
 205 | /// # Operator async API.
 206 | impl Operator {
 207 |     /// Check if this operator can work correctly.
 208 |     ///
 209 |     /// We will send a `list` request to path and return any errors we met.
 210 |     ///
 211 |     /// ```
 212 |     /// # use std::sync::Arc;
 213 |     /// # use anyhow::Result;
 214 |     /// use opendal_core::Operator;
 215 |     ///
 216 |     /// # async fn test(op: Operator) -> Result<()> {
 217 |     /// op.check().await?;
 218 |     /// # Ok(())
 219 |     /// # }
 220 |     /// ```
 221 |     pub async fn check(&self) -> Result<()> {
 222 |         let mut ds = self.lister_with("/").limit(1).await?;
 223 | 
 224 |         match ds.next().await {
 225 |             Some(Err(e)) if e.kind() != ErrorKind::NotFound => Err(e),
 226 |             _ => Ok(()),
 227 |         }
 228 |     }
 229 | 
 230 |     /// Retrieve the metadata for the specified path.
 231 |     ///
 232 |     /// # Notes
 233 |     ///
 234 |     /// ## Extra Options
 235 |     ///
 236 |     /// [`Operator::stat`] is a wrapper around [`Operator::stat_with`] that uses no additional options.
 237 |     /// To specify extra options such as `if_match` and `if_none_match`, please use [`Operator::stat_with`] instead.
 238 |     ///
 239 |     /// # Examples
 240 |     ///
 241 |     /// ## Check if file exists
 242 |     ///
 243 |     /// ```
 244 |     /// # use anyhow::Result;
 245 |     /// # use futures::io;
 246 |     /// # use opendal_core::Operator;
 247 |     /// use opendal_core::ErrorKind;
 248 |     /// #
 249 |     /// # async fn test(op: Operator) -> Result<()> {
 250 |     /// if let Err(e) = op.stat("test").await {
 251 |     ///     if e.kind() == ErrorKind::NotFound {
 252 |     ///         println!("file not exist")
 253 |     ///     }
 254 |     /// }
 255 |     /// # Ok(())
 256 |     /// # }
 257 |     /// ```
 258 |     pub async fn stat(&self, path: &str) -> Result<Metadata> {
 259 |         self.stat_with(path).await
 260 |     }
 261 | 
 262 |     /// Retrieve the metadata of the specified path with additional options.
 263 |     ///
 264 |     /// # Options
 265 |     ///
 266 |     /// Check [`options::StatOptions`] for all available options.
 267 |     ///
 268 |     /// # Examples
 269 |     ///
 270 |     /// ## Get metadata while `ETag` matches
 271 |     ///
 272 |     /// `stat_with` will
 273 |     ///
 274 |     /// - return `Ok(metadata)` if `ETag` matches
 275 |     /// - return `Err(error)` and `error.kind() == ErrorKind::ConditionNotMatch` if file exists but
 276 |     ///   `ETag` mismatch
 277 |     /// - return `Err(err)` if other errors occur, for example, `NotFound`.
 278 |     ///
 279 |     /// ```
 280 |     /// # use anyhow::Result;
 281 |     /// # use futures::io;
 282 |     /// # use opendal_core::Operator;
 283 |     /// use opendal_core::ErrorKind;
 284 |     /// #
 285 |     /// # async fn test(op: Operator) -> Result<()> {
 286 |     /// if let Err(e) = op.stat_with("test").if_match("<etag>").await {
 287 |     ///     if e.kind() == ErrorKind::ConditionNotMatch {
 288 |     ///         println!("file exists, but etag mismatch")
 289 |     ///     }
 290 |     ///     if e.kind() == ErrorKind::NotFound {
 291 |     ///         println!("file not exist")
 292 |     ///     }
 293 |     /// }
 294 |     /// # Ok(())
 295 |     /// # }
 296 |     /// ```
 297 |     pub fn stat_with(&self, path: &str) -> FutureStat<impl Future<Output = Result<Metadata>>> {
 298 |         let path = normalize_path(path);
 299 |         OperatorFuture::new(
 300 |             self.inner().clone(),
 301 |             path,
 302 |             options::StatOptions::default(),
 303 |             Self::stat_inner,
 304 |         )
 305 |     }
 306 | 
 307 |     /// Retrieve the metadata of the specified path with additional options.
 308 |     ///
 309 |     /// # Examples
 310 |     ///
 311 |     /// ## Get metadata while `ETag` matches
 312 |     ///
 313 |     /// `stat_with` will
 314 |     ///
 315 |     /// - return `Ok(metadata)` if `ETag` matches
 316 |     /// - return `Err(error)` and `error.kind() == ErrorKind::ConditionNotMatch` if file exists but
 317 |     ///   `ETag` mismatch
 318 |     /// - return `Err(err)` if other errors occur, for example, `NotFound`.
 319 |     ///
 320 |     /// ```
 321 |     /// # use anyhow::Result;
 322 |     /// # use futures::io;
 323 |     /// # use opendal_core::Operator;
 324 |     /// use opendal_core::options;
 325 |     /// use opendal_core::ErrorKind;
 326 |     /// #
 327 |     /// # async fn test(op: Operator) -> Result<()> {
 328 |     /// let res = op
 329 |     ///     .stat_options("test", options::StatOptions {
 330 |     ///         if_match: Some("<etag>".to_string()),
 331 |     ///         ..Default::default()
 332 |     ///     })
 333 |     ///     .await;
 334 |     /// if let Err(e) = res {
 335 |     ///     if e.kind() == ErrorKind::ConditionNotMatch {
 336 |     ///         println!("file exists, but etag mismatch")
 337 |     ///     }
 338 |     ///     if e.kind() == ErrorKind::NotFound {
 339 |     ///         println!("file not exist")
 340 |     ///     }
 341 |     /// }
 342 |     /// # Ok(())
 343 |     /// # }
 344 |     /// ```
 345 |     pub async fn stat_options(&self, path: &str, opts: options::StatOptions) -> Result<Metadata> {
 346 |         let path = normalize_path(path);
 347 |         Self::stat_inner(self.accessor.clone(), path, opts).await
 348 |     }
 349 | 
 350 |     #[inline]
 351 |     async fn stat_inner(
 352 |         acc: Accessor,
 353 |         path: String,
 354 |         opts: options::StatOptions,
 355 |     ) -> Result<Metadata> {
 356 |         let rp = acc.stat(&path, opts.into()).await?;
 357 |         Ok(rp.into_metadata())
 358 |     }
 359 | 
 360 |     /// Check whether this path exists.
 361 |     ///
 362 |     /// # Example
 363 |     ///
 364 |     /// ```
 365 |     /// use anyhow::Result;
 366 |     /// use futures::io;
 367 |     /// use opendal_core::Operator;
 368 |     ///
 369 |     /// async fn test(op: Operator) -> Result<()> {
 370 |     ///     let _ = op.exists("test").await?;
 371 |     ///
 372 |     ///     Ok(())
 373 |     /// }
 374 |     /// ```
 375 |     pub async fn exists(&self, path: &str) -> Result<bool> {
 376 |         let r = self.stat(path).await;
 377 |         match r {
 378 |             Ok(_) => Ok(true),
 379 |             Err(err) if err.kind() == ErrorKind::NotFound => Ok(false),
 380 |             Err(err) => Err(err),
 381 |         }
 382 |     }
 383 | 
 384 |     /// Create a directory at the specified path.
 385 |     ///
 386 |     /// # Notes
 387 |     ///
 388 |     /// To specify that a path is a directory, you must include a trailing slash (/).
 389 |     /// Omitting the trailing slash may cause OpenDAL to return a `NotADirectory` error.
 390 |     ///
 391 |     /// # Behavior
 392 |     ///
 393 |     /// - Creating a directory that already exists will succeed.
 394 |     /// - Directory creation is always recursive, functioning like `mkdir -p`.
 395 |     ///
 396 |     /// # Examples
 397 |     ///
 398 |     /// ```
 399 |     /// # use opendal_core::Result;
 400 |     /// # use opendal_core::Operator;
 401 |     /// # async fn test(op: Operator) -> Result<()> {
 402 |     /// op.create_dir("path/to/dir/").await?;
 403 |     /// # Ok(())
 404 |     /// # }
 405 |     /// ```
 406 |     pub async fn create_dir(&self, path: &str) -> Result<()> {
 407 |         let path = normalize_path(path);
 408 | 
 409 |         if !validate_path(&path, EntryMode::DIR) {
 410 |             return Err(Error::new(
 411 |                 ErrorKind::NotADirectory,
 412 |                 "the path trying to create should end with `/`",
 413 |             )
 414 |             .with_operation("create_dir")
 415 |             .with_context("service", self.inner().info().scheme())
 416 |             .with_context("path", &path));
 417 |         }
 418 | 
 419 |         self.inner().create_dir(&path, OpCreateDir::new()).await?;
 420 | 
 421 |         Ok(())
 422 |     }
 423 | 
 424 |     /// Read the entire file into bytes from given path.
 425 |     ///
 426 |     /// # Notes
 427 |     ///
 428 |     /// ## Additional Options
 429 |     ///
 430 |     /// [`Operator::read`] is a simplified method that does not support additional options. To access features like `range` and `if_match`, please use [`Operator::read_with`] or [`Operator::read_options`] instead.
 431 |     ///
 432 |     /// ## Streaming Read
 433 |     ///
 434 |     /// This function reads all content into memory at once. For more precise memory management or to read big file lazily, please use [`Operator::reader`].
 435 |     ///
 436 |     /// # Examples
 437 |     ///
 438 |     /// ```
 439 |     /// # use opendal_core::Result;
 440 |     /// # use opendal_core::Operator;
 441 |     /// # use futures::TryStreamExt;
 442 |     /// # async fn test(op: Operator) -> Result<()> {
 443 |     /// let bs = op.read("path/to/file").await?;
 444 |     /// # Ok(())
 445 |     /// # }
 446 |     /// ```
 447 |     pub async fn read(&self, path: &str) -> Result<Buffer> {
 448 |         self.read_options(path, options::ReadOptions::default())
 449 |             .await
 450 |     }
 451 | 
 452 |     /// Read the entire file into bytes from given path with additional options.
 453 |     ///
 454 |     /// # Notes
 455 |     ///
 456 |     /// ## Streaming Read
 457 |     ///
 458 |     /// This function reads all content into memory at once. For more precise memory management or to read big file lazily, please use [`Operator::reader`].
 459 |     ///
 460 |     /// # Options
 461 |     ///
 462 |     /// Visit [`options::ReadOptions`] for all available options.
 463 |     ///
 464 |     /// # Examples
 465 |     ///
 466 |     /// Read the first 10 bytes of a file:
 467 |     ///
 468 |     /// ```
 469 |     /// # use opendal_core::Result;
 470 |     /// # use opendal_core::Operator;
 471 |     /// # async fn test(op: Operator) -> Result<()> {
 472 |     /// let bs = op.read_with("path/to/file").range(0..10).await?;
 473 |     /// # Ok(())
 474 |     /// # }
 475 |     /// ```
 476 |     pub fn read_with(&self, path: &str) -> FutureRead<impl Future<Output = Result<Buffer>>> {
 477 |         let path = normalize_path(path);
 478 | 
 479 |         OperatorFuture::new(
 480 |             self.inner().clone(),
 481 |             path,
 482 |             options::ReadOptions::default(),
 483 |             Self::read_inner,
 484 |         )
 485 |     }
 486 | 
 487 |     /// Read the entire file into bytes from given path with additional options.
 488 |     ///
 489 |     /// # Notes
 490 |     ///
 491 |     /// ## Streaming Read
 492 |     ///
 493 |     /// This function reads all content into memory at once. For more precise memory management or to read big file lazily, please use [`Operator::reader`].
 494 |     ///
 495 |     /// # Examples
 496 |     ///
 497 |     /// Read the first 10 bytes of a file:
 498 |     ///
 499 |     /// ```
 500 |     /// # use opendal_core::Result;
 501 |     /// # use opendal_core::Operator;
 502 |     /// use opendal_core::options;
 503 |     /// # async fn test(op: Operator) -> Result<()> {
 504 |     /// let bs = op
 505 |     ///     .read_options("path/to/file", options::ReadOptions {
 506 |     ///         range: (0..10).into(),
 507 |     ///         ..Default::default()
 508 |     ///     })
 509 |     ///     .await?;
 510 |     /// # Ok(())
 511 |     /// # }
 512 |     /// ```
 513 |     pub async fn read_options(&self, path: &str, opts: options::ReadOptions) -> Result<Buffer> {
 514 |         let path = normalize_path(path);
 515 |         Self::read_inner(self.inner().clone(), path, opts).await
 516 |     }
 517 | 
 518 |     #[inline]
 519 |     async fn read_inner(acc: Accessor, path: String, opts: options::ReadOptions) -> Result<Buffer> {
 520 |         if !validate_path(&path, EntryMode::FILE) {
 521 |             return Err(
 522 |                 Error::new(ErrorKind::IsADirectory, "read path is a directory")
 523 |                     .with_operation("read")
 524 |                     .with_context("service", acc.info().scheme())
 525 |                     .with_context("path", &path),
 526 |             );
 527 |         }
 528 | 
 529 |         let (args, opts) = opts.into();
 530 |         let range = args.range();
 531 |         let context = ReadContext::new(acc, path, args, opts);
 532 |         let r = Reader::new(context);
 533 |         let buf = r.read(range.to_range()).await?;
 534 |         Ok(buf)
 535 |     }
 536 | 
 537 |     /// Create a new reader of given path.
 538 |     ///
 539 |     /// # Notes
 540 |     ///
 541 |     /// ## Extra Options
 542 |     ///
 543 |     /// [`Operator::reader`] is a simplified method without any options. To use additional options such as `concurrent` or `if_match`, please use [`Operator::reader_with`] or [`Operator::reader_options`] instead.
 544 |     ///
 545 |     /// # Examples
 546 |     ///
 547 |     /// ```
 548 |     /// # use opendal_core::Result;
 549 |     /// # use opendal_core::Operator;
 550 |     /// # use futures::TryStreamExt;
 551 |     /// # async fn test(op: Operator) -> Result<()> {
 552 |     /// let r = op.reader("path/to/file").await?;
 553 |     /// // Read the first 10 bytes of the file
 554 |     /// let data = r.read(0..10).await?;
 555 |     /// # Ok(())
 556 |     /// # }
 557 |     /// ```
 558 |     pub async fn reader(&self, path: &str) -> Result<Reader> {
 559 |         self.reader_with(path).await
 560 |     }
 561 | 
 562 |     /// Create a new reader of given path with additional options.
 563 |     ///
 564 |     /// # Options
 565 |     ///
 566 |     /// Visit [`options::ReaderOptions`] for all available options.
 567 |     ///
 568 |     /// # Examples
 569 |     ///
 570 |     /// Create a reader with a specific version ID:
 571 |     ///
 572 |     /// ```
 573 |     /// # use opendal_core::Result;
 574 |     /// # use opendal_core::Operator;
 575 |     /// # async fn test(op: Operator) -> Result<()> {
 576 |     /// let r = op.reader_with("path/to/file").version("version_id").await?;
 577 |     /// // Read the first 10 bytes of the file
 578 |     /// let data = r.read(0..10).await?;
 579 |     /// # Ok(())
 580 |     /// # }
 581 |     /// ```
 582 |     pub fn reader_with(&self, path: &str) -> FutureReader<impl Future<Output = Result<Reader>>> {
 583 |         let path = normalize_path(path);
 584 | 
 585 |         OperatorFuture::new(
 586 |             self.inner().clone(),
 587 |             path,
 588 |             options::ReaderOptions::default(),
 589 |             Self::reader_inner,
 590 |         )
 591 |     }
 592 | 
 593 |     /// Create a new reader of given path with additional options.
 594 |     ///
 595 |     /// # Examples
 596 |     ///
 597 |     /// Create a reader with a specific version ID:
 598 |     ///
 599 |     /// ```
 600 |     /// # use opendal_core::Result;
 601 |     /// # use opendal_core::Operator;
 602 |     /// use opendal_core::options;
 603 |     /// # async fn test(op: Operator) -> Result<()> {
 604 |     /// let r = op
 605 |     ///     .reader_options("path/to/file", options::ReaderOptions {
 606 |     ///         version: Some("version_id".to_string()),
 607 |     ///         ..Default::default()
 608 |     ///     })
 609 |     ///     .await?;
 610 |     /// // Read the first 10 bytes of the file
 611 |     /// let data = r.read(0..10).await?;
 612 |     /// # Ok(())
 613 |     /// # }
 614 |     /// ```
 615 |     pub async fn reader_options(&self, path: &str, opts: options::ReaderOptions) -> Result<Reader> {
 616 |         let path = normalize_path(path);
 617 |         Self::reader_inner(self.inner().clone(), path, opts).await
 618 |     }
 619 | 
 620 |     /// Allow this unused async since we don't want
 621 |     /// to change our public API.
 622 |     #[allow(clippy::unused_async)]
 623 |     #[inline]
 624 |     async fn reader_inner(
 625 |         acc: Accessor,
 626 |         path: String,
 627 |         options: options::ReaderOptions,
 628 |     ) -> Result<Reader> {
 629 |         if !validate_path(&path, EntryMode::FILE) {
 630 |             return Err(
 631 |                 Error::new(ErrorKind::IsADirectory, "read path is a directory")
 632 |                     .with_operation("Operator::reader")
 633 |                     .with_context("service", acc.info().scheme())
 634 |                     .with_context("path", path),
 635 |             );
 636 |         }
 637 | 
 638 |         let (args, opts) = options.into();
 639 |         let context = ReadContext::new(acc, path, args, opts);
 640 |         Ok(Reader::new(context))
 641 |     }
 642 | 
 643 |     /// Write all data to the specified path at once.
 644 |     ///
 645 |     /// # Notes
 646 |     ///
 647 |     /// Visit [`performance::concurrent_write`][crate::docs::performance::concurrent_write] for more details on concurrent writes.
 648 |     ///
 649 |     /// ## Extra Options
 650 |     ///
 651 |     /// [`Operator::write`] is a simplified method that does not include additional options.
 652 |     /// For advanced features such as `chunk` and `concurrent`, use [`Operator::write_with`] or [`Operator::write_options`] instead.
 653 |     ///
 654 |     /// ## Streaming Write
 655 |     ///
 656 |     /// This method executes a single bulk write operation. For more precise memory management
 657 |     /// or to write data in a streaming fashion, use [`Operator::writer`] instead.
 658 |     ///
 659 |     /// ## Multipart Uploads
 660 |     ///
 661 |     /// OpenDAL offers multipart upload capabilities through the [`Writer`] abstraction,
 662 |     /// automatically managing all upload details for you. You can fine-tune the upload process
 663 |     /// by adjusting the `chunk` size and the number of `concurrent` operations using [`Operator::writer_with`].
 664 |     ///
 665 |     /// # Examples
 666 |     ///
 667 |     /// ```
 668 |     /// # use opendal_core::Result;
 669 |     /// # use opendal_core::Operator;
 670 |     /// # use futures::StreamExt;
 671 |     /// # use futures::SinkExt;
 672 |     /// use bytes::Bytes;
 673 |     ///
 674 |     /// # async fn test(op: Operator) -> Result<()> {
 675 |     /// op.write("path/to/file", vec![0; 4096]).await?;
 676 |     /// # Ok(())
 677 |     /// # }
 678 |     /// ```
 679 |     pub async fn write(&self, path: &str, bs: impl Into<Buffer>) -> Result<Metadata> {
 680 |         let bs = bs.into();
 681 |         self.write_with(path, bs).await
 682 |     }
 683 | 
 684 |     /// Write all data to the specified path at once with additional options.
 685 |     ///
 686 |     /// # Notes
 687 |     ///
 688 |     /// Visit [`performance::concurrent_write`][crate::docs::performance::concurrent_write] for more details on concurrent writes.
 689 |     ///
 690 |     /// ## Streaming Write
 691 |     ///
 692 |     /// This method executes a single bulk write operation. For more precise memory management
 693 |     /// or to write data in a streaming fashion, use [`Operator::writer`] instead.
 694 |     ///
 695 |     /// ## Multipart Uploads
 696 |     ///
 697 |     /// OpenDAL offers multipart upload capabilities through the [`Writer`] abstraction,
 698 |     /// automatically managing all upload details for you. You can fine-tune the upload process
 699 |     /// by adjusting the `chunk` size and the number of `concurrent` operations using [`Operator::writer_with`].
 700 |     ///
 701 |     /// # Options
 702 |     ///
 703 |     /// Visit [`options::WriteOptions`] for all available options.
 704 |     ///
 705 |     /// # Examples
 706 |     ///
 707 |     /// Write data to a file only when it does not already exist:
 708 |     ///
 709 |     /// ```
 710 |     /// # use opendal_core::Result;
 711 |     /// # use opendal_core::Operator;
 712 |     /// use bytes::Bytes;
 713 |     ///
 714 |     /// # async fn test(op: Operator) -> Result<()> {
 715 |     /// let _ = op
 716 |     ///     .write_with("path/to/file", vec![0; 4096])
 717 |     ///     .if_not_exists(true)
 718 |     ///     .await?;
 719 |     /// # Ok(())
 720 |     /// # }
 721 |     /// ```
 722 |     pub fn write_with(
 723 |         &self,
 724 |         path: &str,
 725 |         bs: impl Into<Buffer>,
 726 |     ) -> FutureWrite<impl Future<Output = Result<Metadata>>> {
 727 |         let path = normalize_path(path);
 728 |         let bs = bs.into();
 729 | 
 730 |         OperatorFuture::new(
 731 |             self.inner().clone(),
 732 |             path,
 733 |             (options::WriteOptions::default(), bs),
 734 |             |inner, path, (opts, bs)| Self::write_inner(inner, path, bs, opts),
 735 |         )
 736 |     }
 737 | 
 738 |     /// Write all data to the specified path at once with additional options.
 739 |     ///
 740 |     /// # Notes
 741 |     ///
 742 |     /// Visit [`performance::concurrent_write`][crate::docs::performance::concurrent_write] for more details on concurrent writes.
 743 |     ///
 744 |     /// ## Streaming Write
 745 |     ///
 746 |     /// This method executes a single bulk write operation. For more precise memory management
 747 |     /// or to write data in a streaming fashion, use [`Operator::writer`] instead.
 748 |     ///
 749 |     /// ## Multipart Uploads
 750 |     ///
 751 |     /// OpenDAL offers multipart upload capabilities through the [`Writer`] abstraction,
 752 |     /// automatically managing all upload details for you. You can fine-tune the upload process
 753 |     /// by adjusting the `chunk` size and the number of `concurrent` operations using [`Operator::writer_with`].
 754 |     ///
 755 |     /// # Examples
 756 |     ///
 757 |     /// Write data to a file only when it does not already exist:
 758 |     ///
 759 |     /// ```
 760 |     /// # use opendal_core::Result;
 761 |     /// # use opendal_core::Operator;
 762 |     /// use opendal_core::options;
 763 |     ///
 764 |     /// # async fn test(op: Operator) -> Result<()> {
 765 |     /// let _ = op
 766 |     ///     .write_options("path/to/file", vec![0; 4096], options::WriteOptions {
 767 |     ///         if_not_exists: true,
 768 |     ///         ..Default::default()
 769 |     ///     })
 770 |     ///     .await?;
 771 |     /// # Ok(())
 772 |     /// # }
 773 |     /// ```
 774 |     pub async fn write_options(
 775 |         &self,
 776 |         path: &str,
 777 |         bs: impl Into<Buffer>,
 778 |         opts: options::WriteOptions,
 779 |     ) -> Result<Metadata> {
 780 |         let path = normalize_path(path);
 781 |         Self::write_inner(self.inner().clone(), path, bs.into(), opts).await
 782 |     }
 783 | 
 784 |     #[inline]
 785 |     async fn write_inner(
 786 |         acc: Accessor,
 787 |         path: String,
 788 |         bs: Buffer,
 789 |         opts: options::WriteOptions,
 790 |     ) -> Result<Metadata> {
 791 |         if !validate_path(&path, EntryMode::FILE) {
 792 |             return Err(
 793 |                 Error::new(ErrorKind::IsADirectory, "write path is a directory")
 794 |                     .with_operation("Operator::write")
 795 |                     .with_context("service", acc.info().scheme())
 796 |                     .with_context("path", &path),
 797 |             );
 798 |         }
 799 | 
 800 |         let (args, opts) = opts.into();
 801 | 
 802 |         let context = WriteContext::new(acc, path, args, opts);
 803 |         let mut w = Writer::new(context).await?;
 804 |         w.write(bs).await?;
 805 |         w.close().await
 806 |     }
 807 | 
 808 |     /// Create a new writer of given path.
 809 |     ///
 810 |     /// # Notes
 811 |     ///
 812 |     /// ## Writer Features
 813 |     ///
 814 |     /// The writer provides several powerful capabilities:
 815 |     /// - Streaming writes for continuous data transfer
 816 |     /// - Automatic multipart upload handling
 817 |     /// - Memory-efficient chunk-based writing
 818 |     ///
 819 |     /// ## Extra Options
 820 |     ///
 821 |     /// [`Operator::writer`] is a simplified version that does not include additional options.
 822 |     /// For advanced features such as `chunk` and `concurrent`, use [`Operator::writer_with`] or [`Operator::writer_options`] instead.
 823 |     ///
 824 |     /// # Examples
 825 |     ///
 826 |     /// ```
 827 |     /// # use opendal_core::Result;
 828 |     /// # use opendal_core::Operator;
 829 |     /// use bytes::Bytes;
 830 |     ///
 831 |     /// # async fn test(op: Operator) -> Result<()> {
 832 |     /// let mut w = op.writer("path/to/file").await?;
 833 |     /// w.write(vec![0; 4096]).await?;
 834 |     /// w.write(vec![1; 4096]).await?;
 835 |     /// w.close().await?;
 836 |     /// # Ok(())
 837 |     /// # }
 838 |     /// ```
 839 |     pub async fn writer(&self, path: &str) -> Result<Writer> {
 840 |         self.writer_with(path).await
 841 |     }
 842 | 
 843 |     /// Create a new writer of given path with additional options.
 844 |     ///
 845 |     /// # Notes
 846 |     ///
 847 |     /// ## Writer Features
 848 |     ///
 849 |     /// The writer provides several powerful capabilities:
 850 |     /// - Streaming writes for continuous data transfer
 851 |     /// - Automatic multipart upload handling
 852 |     /// - Memory-efficient chunk-based writing
 853 |     ///
 854 |     /// ## Chunk Size Handling
 855 |     ///
 856 |     /// Storage services often have specific requirements for chunk sizes:
 857 |     /// - Services like `s3` may return `EntityTooSmall` errors for undersized chunks
 858 |     /// - Using small chunks in cloud storage services can lead to increased costs
 859 |     ///
 860 |     /// OpenDAL automatically determines optimal chunk sizes based on the service's
 861 |     /// [Capability](crate::types::Capability). However, you can override this by explicitly
 862 |     /// setting the `chunk` parameter.
 863 |     ///
 864 |     /// Visit [`performance::concurrent_write`][crate::docs::performance::concurrent_write] for more details on concurrent writes.
 865 |     ///
 866 |     /// # Examples
 867 |     ///
 868 |     /// ```
 869 |     /// # use opendal_core::Result;
 870 |     /// # use opendal_core::Operator;
 871 |     /// use bytes::Bytes;
 872 |     ///
 873 |     /// # async fn test(op: Operator) -> Result<()> {
 874 |     /// let mut w = op
 875 |     ///     .writer_with("path/to/file")
 876 |     ///     .chunk(4 * 1024 * 1024)
 877 |     ///     .concurrent(8)
 878 |     ///     .await?;
 879 |     /// w.write(vec![0; 4096]).await?;
 880 |     /// w.write(vec![1; 4096]).await?;
 881 |     /// w.close().await?;
 882 |     /// # Ok(())
 883 |     /// # }
 884 |     /// ```
 885 |     pub fn writer_with(&self, path: &str) -> FutureWriter<impl Future<Output = Result<Writer>>> {
 886 |         let path = normalize_path(path);
 887 | 
 888 |         OperatorFuture::new(
 889 |             self.inner().clone(),
 890 |             path,
 891 |             options::WriteOptions::default(),
 892 |             Self::writer_inner,
 893 |         )
 894 |     }
 895 | 
 896 |     /// Create a new writer of given path with additional options.
 897 |     ///
 898 |     /// # Notes
 899 |     ///
 900 |     /// ## Writer Features
 901 |     ///
 902 |     /// The writer provides several powerful capabilities:
 903 |     /// - Streaming writes for continuous data transfer
 904 |     /// - Automatic multipart upload handling
 905 |     /// - Memory-efficient chunk-based writing
 906 |     ///
 907 |     /// ## Chunk Size Handling
 908 |     ///
 909 |     /// Storage services often have specific requirements for chunk sizes:
 910 |     /// - Services like `s3` may return `EntityTooSmall` errors for undersized chunks
 911 |     /// - Using small chunks in cloud storage services can lead to increased costs
 912 |     ///
 913 |     /// OpenDAL automatically determines optimal chunk sizes based on the service's
 914 |     /// [Capability](crate::types::Capability). However, you can override this by explicitly
 915 |     /// setting the `chunk` parameter.
 916 |     ///
 917 |     /// Visit [`performance::concurrent_write`][crate::docs::performance::concurrent_write] for more details on concurrent writes.
 918 |     ///
 919 |     /// # Examples
 920 |     ///
 921 |     /// Write data to a file in 4MiB chunk size and at 8 concurrency:
 922 |     ///
 923 |     /// ```
 924 |     /// # use opendal_core::Result;
 925 |     /// # use opendal_core::Operator;
 926 |     /// use bytes::Bytes;
 927 |     ///
 928 |     /// # async fn test(op: Operator) -> Result<()> {
 929 |     /// let mut w = op
 930 |     ///     .writer_with("path/to/file")
 931 |     ///     .chunk(4 * 1024 * 1024)
 932 |     ///     .concurrent(8)
 933 |     ///     .await?;
 934 |     /// w.write(vec![0; 4096]).await?;
 935 |     /// w.write(vec![1; 4096]).await?;
 936 |     /// w.close().await?;
 937 |     /// # Ok(())
 938 |     /// # }
 939 |     /// ```
 940 |     pub async fn writer_options(&self, path: &str, opts: options::WriteOptions) -> Result<Writer> {
 941 |         let path = normalize_path(path);
 942 |         Self::writer_inner(self.inner().clone(), path, opts).await
 943 |     }
 944 | 
 945 |     #[inline]
 946 |     async fn writer_inner(
 947 |         acc: Accessor,
 948 |         path: String,
 949 |         opts: options::WriteOptions,
 950 |     ) -> Result<Writer> {
 951 |         if !validate_path(&path, EntryMode::FILE) {
 952 |             return Err(
 953 |                 Error::new(ErrorKind::IsADirectory, "write path is a directory")
 954 |                     .with_operation("Operator::writer")
 955 |                     .with_context("service", acc.info().scheme())
 956 |                     .with_context("path", &path),
 957 |             );
 958 |         }
 959 | 
 960 |         let (args, opts) = opts.into();
 961 |         let context = WriteContext::new(acc, path, args, opts);
 962 |         let w = Writer::new(context).await?;
 963 |         Ok(w)
 964 |     }
 965 | 
 966 |     /// Copy a file from `from` to `to`.
 967 |     ///
 968 |     /// # Notes
 969 |     ///
 970 |     /// - `from` and `to` must be a file.
 971 |     /// - `to` will be overwritten if it exists.
 972 |     /// - If `from` and `to` are the same,  an `IsSameFile` error will occur.
 973 |     /// - `copy` is idempotent. For same `from` and `to` input, the result will be the same.
 974 |     ///
 975 |     /// # Examples
 976 |     ///
 977 |     /// ```
 978 |     /// # use opendal_core::Result;
 979 |     /// # use opendal_core::Operator;
 980 |     ///
 981 |     /// # async fn test(op: Operator) -> Result<()> {
 982 |     /// op.copy("path/to/file", "path/to/file2").await?;
 983 |     /// # Ok(())
 984 |     /// # }
 985 |     /// ```
 986 |     pub async fn copy(&self, from: &str, to: &str) -> Result<()> {
 987 |         let from = normalize_path(from);
 988 | 
 989 |         if !validate_path(&from, EntryMode::FILE) {
 990 |             return Err(
 991 |                 Error::new(ErrorKind::IsADirectory, "from path is a directory")
 992 |                     .with_operation("Operator::copy")
 993 |                     .with_context("service", self.info().scheme())
 994 |                     .with_context("from", from),
 995 |             );
 996 |         }
 997 | 
 998 |         let to = normalize_path(to);
 999 | 
1000 |         if !validate_path(&to, EntryMode::FILE) {
1001 |             return Err(
1002 |                 Error::new(ErrorKind::IsADirectory, "to path is a directory")
1003 |                     .with_operation("Operator::copy")
1004 |                     .with_context("service", self.info().scheme())
1005 |                     .with_context("to", to),
1006 |             );
1007 |         }
1008 | 
1009 |         if from == to {
1010 |             return Err(
1011 |                 Error::new(ErrorKind::IsSameFile, "from and to paths are same")
1012 |                     .with_operation("Operator::copy")
1013 |                     .with_context("service", self.info().scheme())
1014 |                     .with_context("from", from)
1015 |                     .with_context("to", to),
1016 |             );
1017 |         }
1018 | 
1019 |         self.inner().copy(&from, &to, OpCopy::new()).await?;
1020 | 
1021 |         Ok(())
1022 |     }
1023 | 
1024 |     /// Copy a file from `from` to `to` with additional options.
1025 |     ///
1026 |     /// # Notes
1027 |     ///
1028 |     /// - `from` and `to` must be a file.
1029 |     /// - If `from` and `to` are the same, an `IsSameFile` error will occur.
1030 |     /// - `copy` is idempotent. For same `from` and `to` input, the result will be the same.
1031 |     ///
1032 |     /// # Options
1033 |     ///
1034 |     /// Visit [`options::CopyOptions`] for all available options.
1035 |     ///
1036 |     /// # Examples
1037 |     ///
1038 |     /// Copy a file only if the destination doesn't exist:
1039 |     ///
1040 |     /// ```
1041 |     /// # use opendal_core::Result;
1042 |     /// # use opendal_core::Operator;
1043 |     ///
1044 |     /// # async fn test(op: Operator) -> Result<()> {
1045 |     /// op.copy_with("path/to/file", "path/to/file2")
1046 |     ///     .if_not_exists(true)
1047 |     ///     .await?;
1048 |     /// # Ok(())
1049 |     /// # }
1050 |     /// ```
1051 |     pub fn copy_with(&self, from: &str, to: &str) -> FutureCopy<impl Future<Output = Result<()>>> {
1052 |         let from = normalize_path(from);
1053 |         let to = normalize_path(to);
1054 | 
1055 |         OperatorFuture::new(
1056 |             self.inner().clone(),
1057 |             from,
1058 |             (options::CopyOptions::default(), to),
1059 |             Self::copy_inner,
1060 |         )
1061 |     }
1062 | 
1063 |     /// Copy a file from `from` to `to` with additional options.
1064 |     ///
1065 |     /// # Notes
1066 |     ///
1067 |     /// - `from` and `to` must be a file.
1068 |     /// - If `from` and `to` are the same, an `IsSameFile` error will occur.
1069 |     /// - `copy` is idempotent. For same `from` and `to` input, the result will be the same.
1070 |     ///
1071 |     /// # Options
1072 |     ///
1073 |     /// Check [`options::CopyOptions`] for all available options.
1074 |     ///
1075 |     /// # Examples
1076 |     ///
1077 |     /// Copy a file only if the destination doesn't exist:
1078 |     ///
1079 |     /// ```
1080 |     /// # use opendal_core::Result;
1081 |     /// # use opendal_core::Operator;
1082 |     /// # use opendal_core::options::CopyOptions;
1083 |     ///
1084 |     /// # async fn test(op: Operator) -> Result<()> {
1085 |     /// let mut opts = CopyOptions::default();
1086 |     /// opts.if_not_exists = true;
1087 |     /// op.copy_options("path/to/file", "path/to/file2", opts).await?;
1088 |     /// # Ok(())
1089 |     /// # }
1090 |     /// ```
1091 |     pub async fn copy_options(
1092 |         &self,
1093 |         from: &str,
1094 |         to: &str,
1095 |         opts: impl Into<options::CopyOptions>,
1096 |     ) -> Result<()> {
1097 |         let from = normalize_path(from);
1098 |         let to = normalize_path(to);
1099 |         let opts = opts.into();
1100 | 
1101 |         Self::copy_inner(self.inner().clone(), from, (opts, to)).await
1102 |     }
1103 | 
1104 |     async fn copy_inner(
1105 |         acc: Accessor,
1106 |         from: String,
1107 |         (opts, to): (options::CopyOptions, String),
1108 |     ) -> Result<()> {
1109 |         if !validate_path(&from, EntryMode::FILE) {
1110 |             return Err(
1111 |                 Error::new(ErrorKind::IsADirectory, "from path is a directory")
1112 |                     .with_operation("Operator::copy")
1113 |                     .with_context("service", acc.info().scheme())
1114 |                     .with_context("from", from),
1115 |             );
1116 |         }
1117 | 
1118 |         if !validate_path(&to, EntryMode::FILE) {
1119 |             return Err(
1120 |                 Error::new(ErrorKind::IsADirectory, "to path is a directory")
1121 |                     .with_operation("Operator::copy")
1122 |                     .with_context("service", acc.info().scheme())
1123 |                     .with_context("to", to),
1124 |             );
1125 |         }
1126 | 
1127 |         if from == to {
1128 |             return Err(
1129 |                 Error::new(ErrorKind::IsSameFile, "from and to paths are same")
1130 |                     .with_operation("Operator::copy")
1131 |                     .with_context("service", acc.info().scheme())
1132 |                     .with_context("from", &from)
1133 |                     .with_context("to", &to),
1134 |             );
1135 |         }
1136 | 
1137 |         let mut op = OpCopy::new();
1138 |         if opts.if_not_exists {
1139 |             op = op.with_if_not_exists(true);
1140 |         }
1141 | 
1142 |         acc.copy(&from, &to, op).await.map(|_| ())
1143 |     }
1144 | 
1145 |     /// Rename a file from `from` to `to`.
1146 |     ///
1147 |     /// # Notes
1148 |     ///
1149 |     /// - `from` and `to` must be a file.
1150 |     /// - `to` will be overwritten if it exists.
1151 |     /// - If `from` and `to` are the same, an `IsSameFile` error will occur.
1152 |     ///
1153 |     /// # Examples
1154 |     ///
1155 |     /// ```
1156 |     /// # use opendal_core::Result;
1157 |     /// # use opendal_core::Operator;
1158 |     ///
1159 |     /// # async fn test(op: Operator) -> Result<()> {
1160 |     /// op.rename("path/to/file", "path/to/file2").await?;
1161 |     /// # Ok(())
1162 |     /// # }
1163 |     /// ```
1164 |     pub async fn rename(&self, from: &str, to: &str) -> Result<()> {
1165 |         let from = normalize_path(from);
1166 | 
1167 |         if !validate_path(&from, EntryMode::FILE) {
1168 |             return Err(
1169 |                 Error::new(ErrorKind::IsADirectory, "from path is a directory")
1170 |                     .with_operation("Operator::move_")
1171 |                     .with_context("service", self.info().scheme())
1172 |                     .with_context("from", from),
1173 |             );
1174 |         }
1175 | 
1176 |         let to = normalize_path(to);
1177 | 
1178 |         if !validate_path(&to, EntryMode::FILE) {
1179 |             return Err(
1180 |                 Error::new(ErrorKind::IsADirectory, "to path is a directory")
1181 |                     .with_operation("Operator::move_")
1182 |                     .with_context("service", self.info().scheme())
1183 |                     .with_context("to", to),
1184 |             );
1185 |         }
1186 | 
1187 |         if from == to {
1188 |             return Err(
1189 |                 Error::new(ErrorKind::IsSameFile, "from and to paths are same")
1190 |                     .with_operation("Operator::move_")
1191 |                     .with_context("service", self.info().scheme())
1192 |                     .with_context("from", from)
1193 |                     .with_context("to", to),
1194 |             );
1195 |         }
1196 | 
1197 |         self.inner().rename(&from, &to, OpRename::new()).await?;
1198 | 
1199 |         Ok(())
1200 |     }
1201 | 
1202 |     /// Delete the given path.
1203 |     ///
1204 |     /// # Notes
1205 |     ///
1206 |     /// - Deleting a file that does not exist won't return errors.
1207 |     ///
1208 |     /// # Examples
1209 |     ///
1210 |     /// ```
1211 |     /// # use anyhow::Result;
1212 |     /// # use futures::io;
1213 |     /// # use opendal_core::Operator;
1214 |     /// # async fn test(op: Operator) -> Result<()> {
1215 |     /// op.delete("test").await?;
1216 |     /// # Ok(())
1217 |     /// # }
1218 |     /// ```
1219 |     pub async fn delete(&self, path: &str) -> Result<()> {
1220 |         self.delete_with(path).await
1221 |     }
1222 | 
1223 |     /// Delete the given path with additional options.
1224 |     ///
1225 |     /// # Notes
1226 |     ///
1227 |     /// - Deleting a file that does not exist won't return errors.
1228 |     ///
1229 |     /// # Options
1230 |     ///
1231 |     /// Visit [`options::DeleteOptions`] for all available options.
1232 |     ///
1233 |     /// # Examples
1234 |     ///
1235 |     /// Delete a specific version of a file:
1236 |     ///
1237 |     /// ```
1238 |     /// # use opendal_core::Result;
1239 |     /// # use opendal_core::Operator;
1240 |     ///
1241 |     /// # async fn test(op: Operator, version: &str) -> Result<()> {
1242 |     /// op.delete_with("path/to/file").version(version).await?;
1243 |     /// # Ok(())
1244 |     /// # }
1245 |     /// ```
1246 |     pub fn delete_with(&self, path: &str) -> FutureDelete<impl Future<Output = Result<()>>> {
1247 |         let path = normalize_path(path);
1248 | 
1249 |         OperatorFuture::new(
1250 |             self.inner().clone(),
1251 |             path,
1252 |             options::DeleteOptions::default(),
1253 |             Self::delete_inner,
1254 |         )
1255 |     }
1256 | 
1257 |     /// Delete the given path with additional options.
1258 |     ///
1259 |     /// # Notes
1260 |     ///
1261 |     /// - Deleting a file that does not exist won't return errors.
1262 |     ///
1263 |     /// # Examples
1264 |     ///
1265 |     /// Delete a specific version of a file:
1266 |     ///
1267 |     /// ```
1268 |     /// # use opendal_core::Result;
1269 |     /// # use opendal_core::Operator;
1270 |     /// use opendal_core::options;
1271 |     ///
1272 |     /// # async fn test(op: Operator, version: &str) -> Result<()> {
1273 |     /// op.delete_options("path/to/file", options::DeleteOptions {
1274 |     ///     version: Some(version.to_string()),
1275 |     ///     ..Default::default()
1276 |     /// })
1277 |     /// .await?;
1278 |     /// # Ok(())
1279 |     /// # }
1280 |     /// ```
1281 |     pub async fn delete_options(&self, path: &str, opts: options::DeleteOptions) -> Result<()> {
1282 |         let path = normalize_path(path);
1283 |         Self::delete_inner(self.inner().clone(), path, opts).await
1284 |     }
1285 | 
1286 |     async fn delete_inner(acc: Accessor, path: String, opts: options::DeleteOptions) -> Result<()> {
1287 |         let (_, mut deleter) = acc.delete_dyn().await?;
1288 |         let args = opts.into();
1289 |         deleter.delete_dyn(&path, args).await?;
1290 |         deleter.close_dyn().await?;
1291 |         Ok(())
1292 |     }
1293 | 
1294 |     /// Delete an infallible iterator of paths.
1295 |     ///
1296 |     /// Also see:
1297 |     ///
1298 |     /// - [`Operator::delete_try_iter`]: delete a fallible iterator of paths.
1299 |     /// - [`Operator::delete_stream`]: delete an infallible stream of paths.
1300 |     /// - [`Operator::delete_try_stream`]: delete a fallible stream of paths.
1301 |     pub async fn delete_iter<I, D>(&self, iter: I) -> Result<()>
1302 |     where
1303 |         I: IntoIterator<Item = D>,
1304 |         D: IntoDeleteInput,
1305 |     {
1306 |         let mut deleter = self.deleter().await?;
1307 |         deleter.delete_iter(iter).await?;
1308 |         deleter.close().await?;
1309 |         Ok(())
1310 |     }
1311 | 
1312 |     /// Delete a fallible iterator of paths.
1313 |     ///
1314 |     /// Also see:
1315 |     ///
1316 |     /// - [`Operator::delete_iter`]: delete an infallible iterator of paths.
1317 |     /// - [`Operator::delete_stream`]: delete an infallible stream of paths.
1318 |     /// - [`Operator::delete_try_stream`]: delete a fallible stream of paths.
1319 |     pub async fn delete_try_iter<I, D>(&self, try_iter: I) -> Result<()>
1320 |     where
1321 |         I: IntoIterator<Item = Result<D>>,
1322 |         D: IntoDeleteInput,
1323 |     {
1324 |         let mut deleter = self.deleter().await?;
1325 |         deleter.delete_try_iter(try_iter).await?;
1326 |         deleter.close().await?;
1327 |         Ok(())
1328 |     }
1329 | 
1330 |     /// Delete an infallible stream of paths.
1331 |     ///
1332 |     /// Also see:
1333 |     ///
1334 |     /// - [`Operator::delete_iter`]: delete an infallible iterator of paths.
1335 |     /// - [`Operator::delete_try_iter`]: delete a fallible iterator of paths.
1336 |     /// - [`Operator::delete_try_stream`]: delete a fallible stream of paths.
1337 |     pub async fn delete_stream<S, D>(&self, stream: S) -> Result<()>
1338 |     where
1339 |         S: Stream<Item = D>,
1340 |         D: IntoDeleteInput,
1341 |     {
1342 |         let mut deleter = self.deleter().await?;
1343 |         deleter.delete_stream(stream).await?;
1344 |         deleter.close().await?;
1345 |         Ok(())
1346 |     }
1347 | 
1348 |     /// Delete a fallible stream of paths.
1349 |     ///
1350 |     /// Also see:
1351 |     ///
1352 |     /// - [`Operator::delete_iter`]: delete an infallible iterator of paths.
1353 |     /// - [`Operator::delete_try_iter`]: delete a fallible iterator of paths.
1354 |     /// - [`Operator::delete_stream`]: delete an infallible stream of paths.
1355 |     pub async fn delete_try_stream<S, D>(&self, try_stream: S) -> Result<()>
1356 |     where
1357 |         S: Stream<Item = Result<D>>,
1358 |         D: IntoDeleteInput,
1359 |     {
1360 |         let mut deleter = self.deleter().await?;
1361 |         deleter.delete_try_stream(try_stream).await?;
1362 |         deleter.close().await?;
1363 |         Ok(())
1364 |     }
1365 | 
1366 |     /// Create a [`Deleter`] to continuously remove content from storage.
1367 |     ///
1368 |     /// It leverages batch deletion capabilities provided by storage services for efficient removal.
1369 |     ///
1370 |     /// Users can have more control over the deletion process by using [`Deleter`] directly.
1371 |     pub async fn deleter(&self) -> Result<Deleter> {
1372 |         Deleter::create(self.inner().clone()).await
1373 |     }
1374 | 
1375 |     /// Remove the path and all nested dirs and files recursively.
1376 |     ///
1377 |     /// # Deprecated
1378 |     ///
1379 |     /// This method is deprecated since v0.55.0. Use [`Operator::delete_with`] with
1380 |     /// `recursive(true)` instead.
1381 |     ///
1382 |     /// ## Migration Example
1383 |     ///
1384 |     /// Instead of:
1385 |     /// ```ignore
1386 |     /// op.remove_all("path/to/dir").await?;
1387 |     /// ```
1388 |     ///
1389 |     /// Use:
1390 |     /// ```ignore
1391 |     /// op.delete_with("path/to/dir").recursive(true).await?;
1392 |     /// ```
1393 |     ///
1394 |     /// # Notes
1395 |     ///
1396 |     /// If underlying services support delete in batch, we will use batch
1397 |     /// delete instead.
1398 |     ///
1399 |     /// # Examples
1400 |     ///
1401 |     /// ```
1402 |     /// # use anyhow::Result;
1403 |     /// # use futures::io;
1404 |     /// # use opendal_core::Operator;
1405 |     /// #
1406 |     /// # async fn test(op: Operator) -> Result<()> {
1407 |     /// op.remove_all("path/to/dir").await?;
1408 |     /// # Ok(())
1409 |     /// # }
1410 |     /// ```
1411 |     #[deprecated(
1412 |         since = "0.55.0",
1413 |         note = "Use `delete_with` with `recursive(true)` instead"
1414 |     )]
1415 |     pub async fn remove_all(&self, path: &str) -> Result<()> {
1416 |         self.delete_with(path).recursive(true).await
1417 |     }
1418 | 
1419 |     /// List entries whose paths start with the given prefix `path`.
1420 |     ///
1421 |     /// # Semantics
1422 |     ///
1423 |     /// - Listing is **prefix-based**. It does not require the parent directory to exist.
1424 |     /// - If `path` itself exists (file or dir), it will be returned as an entry in addition to any prefixed children.
1425 |     /// - If `path` is absent but deeper objects exist (e.g. `path/child`), the list succeeds and returns those prefixed entries instead of an error.
1426 |     ///
1427 |     /// ## Streaming List
1428 |     ///
1429 |     /// This function materializes the entire list into memory. For large listings, prefer [`Operator::lister`] to stream entries.
1430 |     ///
1431 |     /// # Examples
1432 |     ///
1433 |     /// This example will list all entries under the dir `path/to/dir/`.
1434 |     ///
1435 |     /// ```
1436 |     /// # use anyhow::Result;
1437 |     /// use opendal_core::EntryMode;
1438 |     /// use opendal_core::Operator;
1439 |     /// # async fn test(op: Operator) -> Result<()> {
1440 |     /// let mut entries = op.list("path/to/dir/").await?;
1441 |     /// for entry in entries {
1442 |     ///     match entry.metadata().mode() {
1443 |     ///         EntryMode::FILE => {
1444 |     ///             println!("Handling file")
1445 |     ///         }
1446 |     ///         EntryMode::DIR => {
1447 |     ///             println!("Handling dir {}", entry.path())
1448 |     ///         }
1449 |     ///         EntryMode::Unknown => continue,
1450 |     ///     }
1451 |     /// }
1452 |     /// # Ok(())
1453 |     /// # }
1454 |     /// ```
1455 |     pub async fn list(&self, path: &str) -> Result<Vec<Entry>> {
1456 |         self.list_with(path).await
1457 |     }
1458 | 
1459 |     /// List entries whose paths start with the given prefix `path` with additional options.
1460 |     ///
1461 |     /// # Semantics
1462 |     ///
1463 |     /// Inherits the prefix semantics described in [`Operator::list`]: returns `path` itself if it exists and tolerates missing parents when prefixed objects exist.
1464 |     ///
1465 |     /// # Notes
1466 |     ///
1467 |     /// ## Streaming List
1468 |     ///
1469 |     /// This function materializes the entire list into memory. For large listings, prefer [`Operator::lister`] to stream entries.
1470 |     ///
1471 |     /// ## Options
1472 |     ///
1473 |     /// See [`options::ListOptions`] for the full set. Common knobs:
1474 |     /// - Traversal: `recursive` (default `false`) toggles depth-first listing under the prefix.
1475 |     /// - Pagination: `limit` and `start_after` tune page size and resume positions (backend dependent).
1476 |     /// - Versioning: `versions` / `deleted` ask versioned backends to return extra entries.
1477 |     ///
1478 |     /// # Examples
1479 |     ///
1480 |     /// This example will list all entries recursively under the prefix `path/to/prefix`.
1481 |     ///
1482 |     /// ```
1483 |     /// # use anyhow::Result;
1484 |     /// use opendal_core::EntryMode;
1485 |     /// use opendal_core::Operator;
1486 |     /// # async fn test(op: Operator) -> Result<()> {
1487 |     /// let mut entries = op.list_with("path/to/prefix").recursive(true).await?;
1488 |     /// for entry in entries {
1489 |     ///     match entry.metadata().mode() {
1490 |     ///         EntryMode::FILE => {
1491 |     ///             println!("Handling file")
1492 |     ///         }
1493 |     ///         EntryMode::DIR => {
1494 |     ///             println!("Handling dir like start a new list via meta.path()")
1495 |     ///         }
1496 |     ///         EntryMode::Unknown => continue,
1497 |     ///     }
1498 |     /// }
1499 |     /// # Ok(())
1500 |     /// # }
1501 |     /// ```
1502 |     pub fn list_with(&self, path: &str) -> FutureList<impl Future<Output = Result<Vec<Entry>>>> {
1503 |         let path = normalize_path(path);
1504 | 
1505 |         OperatorFuture::new(
1506 |             self.inner().clone(),
1507 |             path,
1508 |             options::ListOptions::default(),
1509 |             Self::list_inner,
1510 |         )
1511 |     }
1512 | 
1513 |     /// List entries whose paths start with the given prefix `path` using explicit options.
1514 |     ///
1515 |     /// # Semantics
1516 |     ///
1517 |     /// Same prefix behavior as [`Operator::list`]: returns `path` itself if present and tolerates missing parents when prefixed objects exist.
1518 |     ///
1519 |     /// # Options
1520 |     ///
1521 |     /// Accepts [`options::ListOptions`] (see field docs for meaning).
1522 |     ///
1523 |     /// ## Streaming List
1524 |     ///
1525 |     /// Materializes the entire list; use [`Operator::lister`] to stream large result sets.
1526 |     ///
1527 |     /// # Examples
1528 |     ///
1529 |     /// This example will list all entries recursively under the prefix `path/to/prefix`.
1530 |     ///
1531 |     /// ```
1532 |     /// # use anyhow::Result;
1533 |     /// use opendal_core::options;
1534 |     /// use opendal_core::EntryMode;
1535 |     /// use opendal_core::Operator;
1536 |     /// # async fn test(op: Operator) -> Result<()> {
1537 |     /// let mut entries = op
1538 |     ///     .list_options("path/to/prefix", options::ListOptions {
1539 |     ///         recursive: true,
1540 |     ///         ..Default::default()
1541 |     ///     })
1542 |     ///     .await?;
1543 |     /// for entry in entries {
1544 |     ///     match entry.metadata().mode() {
1545 |     ///         EntryMode::FILE => {
1546 |     ///             println!("Handling file")
1547 |     ///         }
1548 |     ///         EntryMode::DIR => {
1549 |     ///             println!("Handling dir like start a new list via meta.path()")
1550 |     ///         }
1551 |     ///         EntryMode::Unknown => continue,
1552 |     ///     }
1553 |     /// }
1554 |     /// # Ok(())
1555 |     /// # }
1556 |     /// ```
1557 |     pub async fn list_options(&self, path: &str, opts: options::ListOptions) -> Result<Vec<Entry>> {
1558 |         let path = normalize_path(path);
1559 |         Self::list_inner(self.inner().clone(), path, opts).await
1560 |     }
1561 | 
1562 |     #[inline]
1563 |     async fn list_inner(
1564 |         acc: Accessor,
1565 |         path: String,
1566 |         opts: options::ListOptions,
1567 |     ) -> Result<Vec<Entry>> {
1568 |         let args = opts.into();
1569 |         let lister = Lister::create(acc, &path, args).await?;
1570 |         lister.try_collect().await
1571 |     }
1572 | 
1573 |     /// Create a streaming lister for entries whose paths start with the given prefix `path`.
1574 |     ///
1575 |     /// # Semantics
1576 |     ///
1577 |     /// Shares the same prefix semantics as [`Operator::list`]: the parent directory is not required to exist; the entry for `path` is yielded if present; missing parents with deeper objects are accepted.
1578 |     ///
1579 |     /// # Options
1580 |     ///
1581 |     /// Takes the same [`options::ListOptions`] as [`list_with`](Operator::list_with): traversal (`recursive`), pagination (`limit`, `start_after`), and versioning (`versions`, `deleted`).
1582 |     ///
1583 |     /// # Examples
1584 |     ///
1585 |     /// ```
1586 |     /// # use anyhow::Result;
1587 |     /// # use futures::io;
1588 |     /// use futures::TryStreamExt;
1589 |     /// use opendal_core::EntryMode;
1590 |     /// use opendal_core::Operator;
1591 |     /// # async fn test(op: Operator) -> Result<()> {
1592 |     /// let mut ds = op.lister("path/to/dir/").await?;
1593 |     /// while let Some(mut de) = ds.try_next().await? {
1594 |     ///     match de.metadata().mode() {
1595 |     ///         EntryMode::FILE => {
1596 |     ///             println!("Handling file")
1597 |     ///         }
1598 |     ///         EntryMode::DIR => {
1599 |     ///             println!("Handling dir like start a new list via meta.path()")
1600 |     ///         }
1601 |     ///         EntryMode::Unknown => continue,
1602 |     ///     }
1603 |     /// }
1604 |     /// # Ok(())
1605 |     /// # }
1606 |     /// ```
1607 |     pub async fn lister(&self, path: &str) -> Result<Lister> {
1608 |         self.lister_with(path).await
1609 |     }
1610 | 
1611 |     /// Create a new lister to list entries that start with the given prefix `path` using additional options.
1612 |     ///
1613 |     /// # Options
1614 |     ///
1615 |     /// Same as [`lister_with`](Operator::lister_with); see [`options::ListOptions`] for traversal, pagination, and versioning knobs.
1616 |     ///
1617 |     /// # Examples
1618 |     ///
1619 |     /// ## List all files recursively
1620 |     ///
1621 |     /// ```
1622 |     /// # use anyhow::Result;
1623 |     /// use futures::TryStreamExt;
1624 |     /// use opendal_core::EntryMode;
1625 |     /// use opendal_core::Operator;
1626 |     /// # async fn test(op: Operator) -> Result<()> {
1627 |     /// let mut lister = op.lister_with("path/to/dir/").recursive(true).await?;
1628 |     /// while let Some(mut entry) = lister.try_next().await? {
1629 |     ///     match entry.metadata().mode() {
1630 |     ///         EntryMode::FILE => {
1631 |     ///             println!("Handling file {}", entry.path())
1632 |     ///         }
1633 |     ///         EntryMode::DIR => {
1634 |     ///             println!("Handling dir {}", entry.path())
1635 |     ///         }
1636 |     ///         EntryMode::Unknown => continue,
1637 |     ///     }
1638 |     /// }
1639 |     /// # Ok(())
1640 |     /// # }
1641 |     /// ```
1642 |     pub fn lister_with(&self, path: &str) -> FutureLister<impl Future<Output = Result<Lister>>> {
1643 |         let path = normalize_path(path);
1644 | 
1645 |         OperatorFuture::new(
1646 |             self.inner().clone(),
1647 |             path,
1648 |             options::ListOptions::default(),
1649 |             Self::lister_inner,
1650 |         )
1651 |     }
1652 | 
1653 |     /// Create a new lister to list entries that start with the given prefix `path` using additional options.
1654 |     ///
1655 |     /// # Semantics
1656 |     ///
1657 |     /// Inherits the prefix behavior of [`Operator::lister_with`].
1658 |     ///
1659 |     /// # Options
1660 |     ///
1661 |     /// Uses [`options::ListOptions`] to control traversal, pagination, and versioning.
1662 |     ///
1663 |     /// # Examples
1664 |     ///
1665 |     /// ## List all files recursively
1666 |     ///
1667 |     /// ```
1668 |     /// # use anyhow::Result;
1669 |     /// use futures::TryStreamExt;
1670 |     /// use opendal_core::options;
1671 |     /// use opendal_core::EntryMode;
1672 |     /// use opendal_core::Operator;
1673 |     /// # async fn test(op: Operator) -> Result<()> {
1674 |     /// let mut lister = op
1675 |     ///     .lister_options("path/to/dir/", options::ListOptions {
1676 |     ///         recursive: true,
1677 |     ///         ..Default::default()
1678 |     ///     })
1679 |     ///     .await?;
1680 |     /// while let Some(mut entry) = lister.try_next().await? {
1681 |     ///     match entry.metadata().mode() {
1682 |     ///         EntryMode::FILE => {
1683 |     ///             println!("Handling file {}", entry.path())
1684 |     ///         }
1685 |     ///         EntryMode::DIR => {
1686 |     ///             println!("Handling dir {}", entry.path())
1687 |     ///         }
1688 |     ///         EntryMode::Unknown => continue,
1689 |     ///     }
1690 |     /// }
1691 |     /// # Ok(())
1692 |     /// # }
1693 |     /// ```
1694 |     pub async fn lister_options(&self, path: &str, opts: options::ListOptions) -> Result<Lister> {
1695 |         let path = normalize_path(path);
1696 |         Self::lister_inner(self.inner().clone(), path, opts).await
1697 |     }
1698 | 
1699 |     #[inline]
1700 |     async fn lister_inner(
1701 |         acc: Accessor,
1702 |         path: String,
1703 |         opts: options::ListOptions,
1704 |     ) -> Result<Lister> {
1705 |         let args = opts.into();
1706 |         let lister = Lister::create(acc, &path, args).await?;
1707 |         Ok(lister)
1708 |     }
1709 | }
1710 | 
1711 | /// Operator presign API.
1712 | impl Operator {
1713 |     /// Presign an operation for stat(head).
1714 |     ///
1715 |     /// # Example
1716 |     ///
1717 |     /// ```
1718 |     /// use anyhow::Result;
1719 |     /// use futures::io;
1720 |     /// use opendal_core::Operator;
1721 |     /// use std::time::Duration;
1722 |     ///
1723 |     /// async fn test(op: Operator) -> Result<()> {
1724 |     ///     let signed_req = op.presign_stat("test",Duration::from_secs(3600)).await?;
1725 |     ///     let req = http::Request::builder()
1726 |     ///         .method(signed_req.method())
1727 |     ///         .uri(signed_req.uri())
1728 |     ///         .body(())?;
1729 |     ///
1730 |     /// #    Ok(())
1731 |     /// # }
1732 |     /// ```
1733 |     pub async fn presign_stat(&self, path: &str, expire: Duration) -> Result<PresignedRequest> {
1734 |         let path = normalize_path(path);
1735 | 
1736 |         let op = OpPresign::new(OpStat::new(), expire);
1737 | 
1738 |         let rp = self.inner().presign(&path, op).await?;
1739 |         Ok(rp.into_presigned_request())
1740 |     }
1741 | 
1742 |     /// Presign an operation for stat(head).
1743 |     ///
1744 |     /// # Example
1745 |     ///
1746 |     /// ```
1747 |     /// use anyhow::Result;
1748 |     /// use futures::io;
1749 |     /// use opendal_core::Operator;
1750 |     /// use std::time::Duration;
1751 |     ///
1752 |     /// async fn test(op: Operator) -> Result<()> {
1753 |     ///     let signed_req = op.presign_stat_with("test",Duration::from_secs(3600)).override_content_disposition("attachment; filename=\"othertext.txt\"").await?;
1754 |     /// #    Ok(())
1755 |     /// # }
1756 |     /// ```
1757 |     pub fn presign_stat_with(
1758 |         &self,
1759 |         path: &str,
1760 |         expire: Duration,
1761 |     ) -> FuturePresignStat<impl Future<Output = Result<PresignedRequest>>> {
1762 |         let path = normalize_path(path);
1763 | 
1764 |         OperatorFuture::new(
1765 |             self.inner().clone(),
1766 |             path,
1767 |             (options::StatOptions::default(), expire),
1768 |             Self::presign_stat_inner,
1769 |         )
1770 |     }
1771 | 
1772 |     /// Presign an operation for stat(head) with additional options.
1773 |     ///
1774 |     /// # Options
1775 |     ///
1776 |     /// Visit [`options::StatOptions`] for all available options.
1777 |     ///
1778 |     /// # Example
1779 |     ///
1780 |     /// ```
1781 |     /// use anyhow::Result;
1782 |     /// use opendal_core::Operator;
1783 |     /// use opendal_core::options;
1784 |     /// use std::time::Duration;
1785 |     ///
1786 |     /// async fn test(op: Operator) -> Result<()> {
1787 |     ///     let signed_req = op.presign_stat_options(
1788 |     ///         "test",
1789 |     ///         Duration::from_secs(3600),
1790 |     ///         options::StatOptions {
1791 |     ///             if_match: Some("<etag>".to_string()),
1792 |     ///             ..Default::default()
1793 |     ///         }
1794 |     ///     ).await?;
1795 |     ///     let req = http::Request::builder()
1796 |     ///         .method(signed_req.method())
1797 |     ///         .uri(signed_req.uri())
1798 |     ///         .body(())?;
1799 |     ///
1800 |     /// #    Ok(())
1801 |     /// # }
1802 |     /// ```
1803 |     pub async fn presign_stat_options(
1804 |         &self,
1805 |         path: &str,
1806 |         expire: Duration,
1807 |         opts: options::StatOptions,
1808 |     ) -> Result<PresignedRequest> {
1809 |         let path = normalize_path(path);
1810 |         Self::presign_stat_inner(self.inner().clone(), path, (opts, expire)).await
1811 |     }
1812 | 
1813 |     #[inline]
1814 |     async fn presign_stat_inner(
1815 |         acc: Accessor,
1816 |         path: String,
1817 |         (opts, expire): (options::StatOptions, Duration),
1818 |     ) -> Result<PresignedRequest> {
1819 |         let op = OpPresign::new(OpStat::from(opts), expire);
1820 |         let rp = acc.presign(&path, op).await?;
1821 |         Ok(rp.into_presigned_request())
1822 |     }
1823 | 
1824 |     /// Presign an operation for read.
1825 |     ///
1826 |     /// # Notes
1827 |     ///
1828 |     /// ## Extra Options
1829 |     ///
1830 |     /// `presign_read` is a wrapper of [`Self::presign_read_with`] without any options. To use
1831 |     /// extra options like `override_content_disposition`, please use [`Self::presign_read_with`] or
1832 |     /// [`Self::presign_read_options] instead.
1833 |     ///
1834 |     /// # Example
1835 |     ///
1836 |     /// ```
1837 |     /// use anyhow::Result;
1838 |     /// use futures::io;
1839 |     /// use opendal_core::Operator;
1840 |     /// use std::time::Duration;
1841 |     ///
1842 |     /// async fn test(op: Operator) -> Result<()> {
1843 |     ///     let signed_req = op.presign_read("test.txt", Duration::from_secs(3600)).await?;
1844 |     /// #    Ok(())
1845 |     /// # }
1846 |     /// ```
1847 |     ///
1848 |     /// - `signed_req.method()`: `GET`
1849 |     /// - `signed_req.uri()`: `https://s3.amazonaws.com/examplebucket/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_key_id/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature-value>`
1850 |     /// - `signed_req.headers()`: `{ "host": "s3.amazonaws.com" }`
1851 |     ///
1852 |     /// We can download this file via `curl` or other tools without credentials:
1853 |     ///
1854 |     /// ```shell
1855 |     /// curl "https://s3.amazonaws.com/examplebucket/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_key_id/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature-value>" -O /tmp/test.txt
1856 |     /// ```
1857 |     pub async fn presign_read(&self, path: &str, expire: Duration) -> Result<PresignedRequest> {
1858 |         let path = normalize_path(path);
1859 | 
1860 |         let op = OpPresign::new(OpRead::new(), expire);
1861 | 
1862 |         let rp = self.inner().presign(&path, op).await?;
1863 |         Ok(rp.into_presigned_request())
1864 |     }
1865 | 
1866 |     /// Presign an operation for read with extra options.
1867 |     ///
1868 |     /// # Options
1869 |     ///
1870 |     /// Visit [`options::ReadOptions`] for all available options.
1871 |     ///
1872 |     /// # Example
1873 |     ///
1874 |     /// ```
1875 |     /// use std::time::Duration;
1876 |     ///
1877 |     /// use anyhow::Result;
1878 |     /// use futures::io;
1879 |     /// use opendal_core::Operator;
1880 |     ///
1881 |     /// async fn test(op: Operator) -> Result<()> {
1882 |     ///     let signed_req = op
1883 |     ///         .presign_read_with("test.txt", Duration::from_secs(3600))
1884 |     ///         .override_content_type("text/plain")
1885 |     ///         .await?;
1886 |     ///     Ok(())
1887 |     /// }
1888 |     /// ```
1889 |     pub fn presign_read_with(
1890 |         &self,
1891 |         path: &str,
1892 |         expire: Duration,
1893 |     ) -> FuturePresignRead<impl Future<Output = Result<PresignedRequest>>> {
1894 |         let path = normalize_path(path);
1895 | 
1896 |         OperatorFuture::new(
1897 |             self.inner().clone(),
1898 |             path,
1899 |             (options::ReadOptions::default(), expire),
1900 |             Self::presign_read_inner,
1901 |         )
1902 |     }
1903 | 
1904 |     /// Presign an operation for read with additional options.
1905 |     ///
1906 |     /// # Options
1907 |     ///
1908 |     /// Visit [`options::ReadOptions`] for all available options.
1909 |     ///
1910 |     /// # Example
1911 |     ///
1912 |     /// ```
1913 |     /// use anyhow::Result;
1914 |     /// use opendal_core::Operator;
1915 |     /// use opendal_core::options;
1916 |     /// use std::time::Duration;
1917 |     ///
1918 |     /// async fn test(op: Operator) -> Result<()> {
1919 |     ///     let signed_req = op.presign_read_options(
1920 |     ///         "file",
1921 |     ///         Duration::from_secs(3600),
1922 |     ///         options::ReadOptions {
1923 |     ///             override_content_disposition: Some("attachment; filename=\"othertext.txt\"".to_string()),
1924 |     ///             ..Default::default()
1925 |     ///         }
1926 |     ///     ).await?;
1927 |     ///     let req = http::Request::builder()
1928 |     ///         .method(signed_req.method())
1929 |     ///         .uri(signed_req.uri())
1930 |     ///         .body(())?;
1931 |     ///
1932 |     /// #    Ok(())
1933 |     /// # }
1934 |     /// ```
1935 |     pub async fn presign_read_options(
1936 |         &self,
1937 |         path: &str,
1938 |         expire: Duration,
1939 |         opts: options::ReadOptions,
1940 |     ) -> Result<PresignedRequest> {
1941 |         let path = normalize_path(path);
1942 |         Self::presign_read_inner(self.inner().clone(), path, (opts, expire)).await
1943 |     }
1944 | 
1945 |     #[inline]
1946 |     async fn presign_read_inner(
1947 |         acc: Accessor,
1948 |         path: String,
1949 |         (opts, expire): (options::ReadOptions, Duration),
1950 |     ) -> Result<PresignedRequest> {
1951 |         let (op_read, _) = opts.into();
1952 |         let op = OpPresign::new(op_read, expire);
1953 |         let rp = acc.presign(&path, op).await?;
1954 |         Ok(rp.into_presigned_request())
1955 |     }
1956 | 
1957 |     /// Presign an operation for write.
1958 |     ///
1959 |     /// # Notes
1960 |     ///
1961 |     /// ## Extra Options
1962 |     ///
1963 |     /// `presign_write` is a wrapper of [`Self::presign_write_with`] without any options. To use
1964 |     /// extra options like `content_type`, please use [`Self::presign_write_with`] or
1965 |     /// [`Self::presign_write_options`] instead.
1966 |     ///
1967 |     /// # Example
1968 |     ///
1969 |     /// ```
1970 |     /// use std::time::Duration;
1971 |     ///
1972 |     /// use anyhow::Result;
1973 |     /// use opendal_core::Operator;
1974 |     ///
1975 |     /// async fn test(op: Operator) -> Result<()> {
1976 |     ///     let signed_req = op
1977 |     ///         .presign_write("test.txt", Duration::from_secs(3600))
1978 |     ///         .await?;
1979 |     ///     Ok(())
1980 |     /// }
1981 |     /// ```
1982 |     ///
1983 |     /// - `signed_req.method()`: `PUT`
1984 |     /// - `signed_req.uri()`: `https://s3.amazonaws.com/examplebucket/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_key_id/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature-value>`
1985 |     /// - `signed_req.headers()`: `{ "host": "s3.amazonaws.com" }`
1986 |     ///
1987 |     /// We can upload file as this file via `curl` or other tools without credential:
1988 |     ///
1989 |     /// ```shell
1990 |     /// curl -X PUT "https://s3.amazonaws.com/examplebucket/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_key_id/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature-value>" -d "Hello, World!"
1991 |     /// ```
1992 |     pub async fn presign_write(&self, path: &str, expire: Duration) -> Result<PresignedRequest> {
1993 |         self.presign_write_with(path, expire).await
1994 |     }
1995 | 
1996 |     /// Presign an operation for write with extra options.
1997 |     ///
1998 |     /// # Options
1999 |     ///
2000 |     /// Visit [`options::WriteOptions`] for all available options.
2001 |     ///
2002 |     /// # Example
2003 |     ///
2004 |     /// ```
2005 |     /// use std::time::Duration;
2006 |     ///
2007 |     /// use anyhow::Result;
2008 |     /// use opendal_core::Operator;
2009 |     ///
2010 |     /// async fn test(op: Operator) -> Result<()> {
2011 |     ///     let signed_req = op
2012 |     ///         .presign_write_with("test", Duration::from_secs(3600))
2013 |     ///         .cache_control("no-store")
2014 |     ///         .await?;
2015 |     ///     let req = http::Request::builder()
2016 |     ///         .method(signed_req.method())
2017 |     ///         .uri(signed_req.uri())
2018 |     ///         .body(())?;
2019 |     ///
2020 |     ///     Ok(())
2021 |     /// }
2022 |     /// ```
2023 |     pub fn presign_write_with(
2024 |         &self,
2025 |         path: &str,
2026 |         expire: Duration,
2027 |     ) -> FuturePresignWrite<impl Future<Output = Result<PresignedRequest>>> {
2028 |         let path = normalize_path(path);
2029 | 
2030 |         OperatorFuture::new(
2031 |             self.inner().clone(),
2032 |             path,
2033 |             (options::WriteOptions::default(), expire),
2034 |             Self::presign_write_inner,
2035 |         )
2036 |     }
2037 | 
2038 |     /// Presign an operation for write with additional options.
2039 |     ///
2040 |     /// # Options
2041 |     ///
2042 |     /// Check [`options::WriteOptions`] for all available options.
2043 |     ///
2044 |     /// # Example
2045 |     ///
2046 |     /// ```
2047 |     /// use anyhow::Result;
2048 |     /// use opendal_core::Operator;
2049 |     /// use opendal_core::options;
2050 |     /// use std::time::Duration;
2051 |     ///
2052 |     /// async fn test(op: Operator) -> Result<()> {
2053 |     ///     let signed_req = op.presign_write_options(
2054 |     ///         "file",
2055 |     ///         Duration::from_secs(3600),
2056 |     ///         options::WriteOptions {
2057 |     ///             content_type: Some("application/json".to_string()),
2058 |     ///             cache_control: Some("max-age=3600".to_string()),
2059 |     ///             if_not_exists: true,
2060 |     ///             ..Default::default()
2061 |     ///         }
2062 |     ///     ).await?;
2063 |     ///     let req = http::Request::builder()
2064 |     ///         .method(signed_req.method())
2065 |     ///         .uri(signed_req.uri())
2066 |     ///         .body(())?;
2067 |     ///
2068 |     /// #    Ok(())
2069 |     /// # }
2070 |     /// ```
2071 |     pub async fn presign_write_options(
2072 |         &self,
2073 |         path: &str,
2074 |         expire: Duration,
2075 |         opts: options::WriteOptions,
2076 |     ) -> Result<PresignedRequest> {
2077 |         let path = normalize_path(path);
2078 |         Self::presign_write_inner(self.inner().clone(), path, (opts, expire)).await
2079 |     }
2080 | 
2081 |     #[inline]
2082 |     async fn presign_write_inner(
2083 |         acc: Accessor,
2084 |         path: String,
2085 |         (opts, expire): (options::WriteOptions, Duration),
2086 |     ) -> Result<PresignedRequest> {
2087 |         let (op_write, _) = opts.into();
2088 |         let op = OpPresign::new(op_write, expire);
2089 |         let rp = acc.presign(&path, op).await?;
2090 |         Ok(rp.into_presigned_request())
2091 |     }
2092 | 
2093 |     /// Presign an operation for delete.
2094 |     ///
2095 |     /// # Notes
2096 |     ///
2097 |     /// ## Extra Options
2098 |     ///
2099 |     /// `presign_delete` is a wrapper of [`Self::presign_delete_with`] without any options.
2100 |     ///
2101 |     /// # Example
2102 |     ///
2103 |     /// ```
2104 |     /// use std::time::Duration;
2105 |     ///
2106 |     /// use anyhow::Result;
2107 |     /// use opendal_core::Operator;
2108 |     ///
2109 |     /// async fn test(op: Operator) -> Result<()> {
2110 |     ///     let signed_req = op
2111 |     ///         .presign_delete("test.txt", Duration::from_secs(3600))
2112 |     ///         .await?;
2113 |     ///     Ok(())
2114 |     /// }
2115 |     /// ```
2116 |     ///
2117 |     /// - `signed_req.method()`: `DELETE`
2118 |     /// - `signed_req.uri()`: `https://s3.amazonaws.com/examplebucket/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_key_id/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature-value>`
2119 |     /// - `signed_req.headers()`: `{ "host": "s3.amazonaws.com" }`
2120 |     ///
2121 |     /// We can delete file as this file via `curl` or other tools without credential:
2122 |     ///
2123 |     /// ```shell
2124 |     /// curl -X DELETE "https://s3.amazonaws.com/examplebucket/test.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=access_key_id/20130721/us-east-1/s3/aws4_request&X-Amz-Date=20130721T201207Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=<signature-value>"
2125 |     /// ```
2126 |     pub async fn presign_delete(&self, path: &str, expire: Duration) -> Result<PresignedRequest> {
2127 |         self.presign_delete_with(path, expire).await
2128 |     }
2129 | 
2130 |     /// Presign an operation for delete without extra options.
2131 |     pub fn presign_delete_with(
2132 |         &self,
2133 |         path: &str,
2134 |         expire: Duration,
2135 |     ) -> FuturePresignDelete<impl Future<Output = Result<PresignedRequest>>> {
2136 |         let path = normalize_path(path);
2137 | 
2138 |         OperatorFuture::new(
2139 |             self.inner().clone(),
2140 |             path,
2141 |             (options::DeleteOptions::default(), expire),
2142 |             Self::presign_delete_inner,
2143 |         )
2144 |     }
2145 | 
2146 |     /// Presign an operation for delete with additional options.
2147 |     ///
2148 |     /// # Options
2149 |     ///
2150 |     /// Visit [`options::DeleteOptions`] for all available options.
2151 |     ///
2152 |     /// # Example
2153 |     ///
2154 |     /// ```
2155 |     /// use anyhow::Result;
2156 |     /// use opendal_core::Operator;
2157 |     /// use opendal_core::options;
2158 |     /// use std::time::Duration;
2159 |     ///
2160 |     /// async fn test(op: Operator) -> Result<()> {
2161 |     ///     let signed_req = op.presign_delete_options(
2162 |     ///         "path/to/file",
2163 |     ///         Duration::from_secs(3600),
2164 |     ///         options::DeleteOptions {
2165 |     ///             ..Default::default()
2166 |     ///         }
2167 |     ///     ).await?;
2168 |     ///     let req = http::Request::builder()
2169 |     ///         .method(signed_req.method())
2170 |     ///         .uri(signed_req.uri())
2171 |     ///         .body(())?;
2172 |     ///
2173 |     /// #    Ok(())
2174 |     /// # }
2175 |     /// ```
2176 |     pub async fn presign_delete_options(
2177 |         &self,
2178 |         path: &str,
2179 |         expire: Duration,
2180 |         opts: options::DeleteOptions,
2181 |     ) -> Result<PresignedRequest> {
2182 |         let path = normalize_path(path);
2183 |         Self::presign_delete_inner(self.inner().clone(), path, (opts, expire)).await
2184 |     }
2185 | 
2186 |     #[inline]
2187 |     async fn presign_delete_inner(
2188 |         acc: Accessor,
2189 |         path: String,
2190 |         (opts, expire): (options::DeleteOptions, Duration),
2191 |     ) -> Result<PresignedRequest> {
2192 |         let op = OpPresign::new(OpDelete::from(opts), expire);
2193 |         let rp = acc.presign(&path, op).await?;
2194 |         Ok(rp.into_presigned_request())
2195 |     }
2196 | }
2197 | 
```
Page 71/74FirstPrevNextLast