This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new c1b0b953f6 docs: Refactor rust core examples (#4757)
c1b0b953f6 is described below
commit c1b0b953f638e9e4f8314fb354aa2d45e9ae44a3
Author: Xuanwo <[email protected]>
AuthorDate: Tue Jun 18 17:31:46 2024 +0800
docs: Refactor rust core examples (#4757)
Signed-off-by: Xuanwo <[email protected]>
---
.github/workflows/test_examples.yml | 66 --------
core/Cargo.lock | 33 +++-
core/Cargo.toml | 21 ++-
core/README.md | 11 +-
core/edge/file_write_on_full_disk/Cargo.toml | 9 +-
.../Cargo.toml | 9 +-
core/edge/s3_read_on_wasm/Cargo.toml | 9 +-
core/examples/README.md | 23 +++
.../basic}/Cargo.toml | 14 +-
core/examples/basic/README.md | 15 ++
core/examples/basic/src/main.rs | 49 ++++++
.../concurrent-upload}/Cargo.toml | 14 +-
core/examples/concurrent-upload/README.md | 15 ++
core/examples/concurrent-upload/src/main.rs | 66 ++++++++
.../multipart-upload}/Cargo.toml | 14 +-
core/examples/multipart-upload/README.md | 15 ++
core/examples/multipart-upload/src/main.rs | 55 +++++++
examples/README.md | 2 +-
examples/rust/00-setup/.gitignore | 2 -
examples/rust/00-setup/Cargo.toml | 19 ---
examples/rust/00-setup/README.md | 98 ------------
examples/rust/00-setup/src/main.rs | 5 -
examples/rust/01-init-operator/.gitignore | 2 -
examples/rust/01-init-operator/Cargo.toml | 9 --
examples/rust/01-init-operator/README.md | 168 --------------------
examples/rust/01-init-operator/src/main.rs | 41 -----
examples/rust/02-async-io/.gitignore | 2 -
examples/rust/02-async-io/Cargo.toml | 10 --
examples/rust/02-async-io/README.md | 175 ---------------------
examples/rust/02-async-io/src/main.rs | 25 ---
examples/rust/03-add-layers/.gitignore | 2 -
examples/rust/03-add-layers/Cargo.toml | 11 --
examples/rust/03-add-layers/README.md | 126 ---------------
examples/rust/03-add-layers/src/main.rs | 40 -----
examples/rust/README.md | 18 ---
35 files changed, 332 insertions(+), 861 deletions(-)
diff --git a/.github/workflows/test_examples.yml
b/.github/workflows/test_examples.yml
deleted file mode 100644
index 7a6d575929..0000000000
--- a/.github/workflows/test_examples.yml
+++ /dev/null
@@ -1,66 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-name: Examples
-
-on:
- push:
- branches:
- - main
- pull_request:
- branches:
- - main
- paths:
- - "examples/**"
-
-concurrency:
- group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
- cancel-in-progress: true
-
-jobs:
- rust-00-setup:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - name: Setup Rust toolchain
- uses: ./.github/actions/setup
- - name: Test
- shell: bash
- working-directory: examples/rust/00-setup
- run: cargo run
-
- rust-01-init-operator:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - name: Setup Rust toolchain
- uses: ./.github/actions/setup
- - name: Test
- shell: bash
- working-directory: examples/rust/01-init-operator
- run: cargo run
-
- rust-02-async-io:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - name: Setup Rust toolchain
- uses: ./.github/actions/setup
- - name: Test
- shell: bash
- working-directory: examples/rust/02-async-io
- run: cargo run
diff --git a/core/Cargo.lock b/core/Cargo.lock
index 250a5a1f11..367d4d1b0f 100644
--- a/core/Cargo.lock
+++ b/core/Cargo.lock
@@ -2421,7 +2421,7 @@ dependencies = [
[[package]]
name = "edge_test_aws_s3_assume_role_with_web_identity"
-version = "0.0.0"
+version = "0.47.0"
dependencies = [
"opendal",
"tokio",
@@ -2430,7 +2430,7 @@ dependencies = [
[[package]]
name = "edge_test_file_write_on_full_disk"
-version = "0.0.0"
+version = "0.47.0"
dependencies = [
"futures",
"opendal",
@@ -2440,7 +2440,7 @@ dependencies = [
[[package]]
name = "edge_test_s3_read_on_wasm"
-version = "0.0.0"
+version = "0.47.0"
dependencies = [
"opendal",
"wasm-bindgen",
@@ -4854,6 +4854,33 @@ dependencies = [
"uuid",
]
+[[package]]
+name = "opendal-examples-basic"
+version = "0.47.0"
+dependencies = [
+ "futures",
+ "opendal",
+ "tokio",
+]
+
+[[package]]
+name = "opendal-examples-concurrent-upload"
+version = "0.47.0"
+dependencies = [
+ "futures",
+ "opendal",
+ "tokio",
+]
+
+[[package]]
+name = "opendal-examples-multipart-upload"
+version = "0.47.0"
+dependencies = [
+ "futures",
+ "opendal",
+ "tokio",
+]
+
[[package]]
name = "opendal-fuzz"
version = "0.0.0"
diff --git a/core/Cargo.toml b/core/Cargo.toml
index d49b9de04e..4865597728 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -36,7 +36,13 @@ rustdoc-args = ["--cfg", "docs"]
[workspace]
default-members = ["."]
-members = [".", "fuzz", "edge/*", "benches/vs_*"]
+members = [".", "examples/*", "fuzz", "edge/*", "benches/vs_*"]
+
+[workspace.package]
+edition = "2021"
+license = "Apache-2.0"
+rust-version = "1.75"
+version = "0.47.0"
[features]
default = ["reqwest/rustls-tls", "executors-tokio", "services-memory"]
@@ -95,6 +101,7 @@ layers-async-backtrace = ["dep:async-backtrace"]
layers-blocking = ["internal-tokio-rt"]
layers-dtrace = ["dep:probe"]
+services-aliyun-drive = []
services-alluxio = []
services-atomicserver = ["dep:atomic_lib"]
services-azblob = [
@@ -193,7 +200,6 @@ services-vercel-blob = []
services-webdav = []
services-webhdfs = []
services-yandex-disk = []
-services-aliyun-drive = []
[lib]
bench = false
@@ -233,7 +239,10 @@ chrono = { version = "0.4.28", default-features = false,
features = [
"std",
] }
flagset = "0.4"
-futures = { version = "0.3", default-features = false, features = ["std",
"async-await"] }
+futures = { version = "0.3", default-features = false, features = [
+ "std",
+ "async-await",
+] }
http = "1.1"
log = "0.4"
md-5 = "0.10"
@@ -335,7 +344,11 @@ hdfs-native = { version = "0.9.4", optional = true }
# for services-surrealdb
surrealdb = { version = "1.3.0", optional = true, features = ["protocol-http"]
}
# for services-compfs
-compio = { version = "0.10.0", optional = true, features = ["runtime",
"bytes", "polling"] }
+compio = { version = "0.10.0", optional = true, features = [
+ "runtime",
+ "bytes",
+ "polling",
+] }
# for services-s3
crc32c = { version = "0.6.6", optional = true }
diff --git a/core/README.md b/core/README.md
index 94b3cc2ae3..eb31e363a1 100644
--- a/core/README.md
+++ b/core/README.md
@@ -17,6 +17,7 @@ OpenDAL offers a unified data access layer, empowering users
to seamlessly and e
## Useful Links
- Documentation: [release](https://docs.rs/opendal/) |
[dev](https://opendal.apache.org/docs/rust/opendal/)
+- [Examples](./examples)
- [Release
Notes](https://docs.rs/opendal/latest/opendal/docs/changelog/index.html)
- [Upgrade
Guide](https://docs.rs/opendal/latest/opendal/docs/upgrade/index.html)
- [RFC List](https://docs.rs/opendal/latest/opendal/docs/rfcs/index.html)
@@ -194,7 +195,15 @@ async fn main() -> Result<()> {
## Examples
-The examples are available at [here](../examples/rust).
+| Name | Description
|
+|---------------------|---------------------------------------------------------------|
+| [Basic] | Show how to use opendal to operate storage service.
|
+| [Concurrent Upload] | Show how to perform upload concurrently to a storage
service. |
+| [Multipart Upload] | Show how to perform a multipart upload to a storage
service. |
+
+[Basic]: ./examples/basic
+[Concurrent Upload]: ./examples/concurrent-upload
+[Multipart Upload]: ./examples/multipart-upload
## Contributing
diff --git a/core/edge/file_write_on_full_disk/Cargo.toml
b/core/edge/file_write_on_full_disk/Cargo.toml
index 339c73a3d7..57bfb10a3d 100644
--- a/core/edge/file_write_on_full_disk/Cargo.toml
+++ b/core/edge/file_write_on_full_disk/Cargo.toml
@@ -16,12 +16,13 @@
# under the License.
[package]
-edition = "2021"
-license = "Apache-2.0"
name = "edge_test_file_write_on_full_disk"
+
+edition.workspace = true
+license.workspace = true
publish = false
-rust-version = "1.75"
-version = "0.0.0"
+rust-version.workspace = true
+version.workspace = true
[dependencies]
futures = "0.3"
diff --git a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
b/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
index f503ef8e6f..0e898209e5 100644
--- a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
+++ b/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
@@ -16,12 +16,13 @@
# under the License.
[package]
-edition = "2021"
-license = "Apache-2.0"
name = "edge_test_aws_s3_assume_role_with_web_identity"
+
+edition.workspace = true
+license.workspace = true
publish = false
-rust-version = "1.75"
-version = "0.0.0"
+rust-version.workspace = true
+version.workspace = true
[dependencies]
opendal = { path = "../..", features = ["tests"] }
diff --git a/core/edge/s3_read_on_wasm/Cargo.toml
b/core/edge/s3_read_on_wasm/Cargo.toml
index 4c14b7678a..df57849cb6 100644
--- a/core/edge/s3_read_on_wasm/Cargo.toml
+++ b/core/edge/s3_read_on_wasm/Cargo.toml
@@ -16,12 +16,13 @@
# under the License.
[package]
-edition = "2021"
-license = "Apache-2.0"
name = "edge_test_s3_read_on_wasm"
+
+edition.workspace = true
+license.workspace = true
publish = false
-rust-version = "1.75"
-version = "0.0.0"
+rust-version.workspace = true
+version.workspace = true
[lib]
crate-type = ["cdylib"]
diff --git a/core/examples/README.md b/core/examples/README.md
new file mode 100644
index 0000000000..6c761c5f9d
--- /dev/null
+++ b/core/examples/README.md
@@ -0,0 +1,23 @@
+# Apache OpenDALâ„¢ Rust Core Examples
+
+Thank you for using OpenDAL!
+
+Those examples are designed to help you to understand how to use OpenDAL Rust
Core.
+
+## Setup
+
+All examples following the same setup steps:
+
+To run this example, please copy the `.env.example`, which is at project root,
to `.env` and change the values on need.
+
+Take `fs` for example, we need to change to enable behavior test on `fs` on
`/tmp`.
+
+```dotenv
+OPENDAL_FS_ROOT=/path/to/dir
+```
+
+into
+
+```dotenv
+OPENDAL_FS_ROOT=/tmp
+```
diff --git a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
b/core/examples/basic/Cargo.toml
similarity index 78%
copy from core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
copy to core/examples/basic/Cargo.toml
index f503ef8e6f..185d4b8e51 100644
--- a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
+++ b/core/examples/basic/Cargo.toml
@@ -16,14 +16,14 @@
# under the License.
[package]
-edition = "2021"
-license = "Apache-2.0"
-name = "edge_test_aws_s3_assume_role_with_web_identity"
+name = "opendal-examples-basic"
publish = false
-rust-version = "1.75"
-version = "0.0.0"
+
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
+futures = "0.3"
opendal = { path = "../..", features = ["tests"] }
-tokio = { version = "1", features = ["full"] }
-uuid = { version = "1", features = ["serde", "v4"] }
+tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
diff --git a/core/examples/basic/README.md b/core/examples/basic/README.md
new file mode 100644
index 0000000000..65621a18c9
--- /dev/null
+++ b/core/examples/basic/README.md
@@ -0,0 +1,15 @@
+# Basic
+
+This example will show how to use opendal to operate storage service.
+
+## Setup
+
+Refer [Setup](../README.md) to setup all examples.
+
+## Run
+
+Use `OPENDAL_TEST` to control which service to run example:
+
+```shell
+OPENDAL_TEST=fs cargo run
+```
\ No newline at end of file
diff --git a/core/examples/basic/src/main.rs b/core/examples/basic/src/main.rs
new file mode 100644
index 0000000000..8a7c3ba88d
--- /dev/null
+++ b/core/examples/basic/src/main.rs
@@ -0,0 +1,49 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use opendal::{Operator, Result};
+
+async fn example(op: Operator) -> Result<()> {
+ // Write data to S3.
+ op.write("test.txt", "Hello, World!").await?;
+ println!("write succeeded");
+
+ // Read data from s3.
+ let bs = op.read("test.txt").await?;
+ println!("read: {}", String::from_utf8(bs.to_vec()).unwrap());
+
+ // Fetch metadata of s3.
+ let meta = op.stat("test.txt").await?;
+ println!("stat: {:?}", meta);
+
+ // Delete data from s3.
+ op.delete("test.txt").await?;
+ println!("delete succeeded");
+
+ Ok(())
+}
+
+// --- The following data is not part of this example ---
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ use opendal::raw::tests::init_test_service;
+ let op = init_test_service()?.expect("OPENDAL_TEST must be set");
+
+ println!("service {:?} has been initialized", op.info());
+ example(op).await
+}
diff --git a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
b/core/examples/concurrent-upload/Cargo.toml
similarity index 78%
copy from core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
copy to core/examples/concurrent-upload/Cargo.toml
index f503ef8e6f..8a9ba0963f 100644
--- a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
+++ b/core/examples/concurrent-upload/Cargo.toml
@@ -16,14 +16,14 @@
# under the License.
[package]
-edition = "2021"
-license = "Apache-2.0"
-name = "edge_test_aws_s3_assume_role_with_web_identity"
+name = "opendal-examples-concurrent-upload"
publish = false
-rust-version = "1.75"
-version = "0.0.0"
+
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
+futures = "0.3"
opendal = { path = "../..", features = ["tests"] }
-tokio = { version = "1", features = ["full"] }
-uuid = { version = "1", features = ["serde", "v4"] }
+tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
diff --git a/core/examples/concurrent-upload/README.md
b/core/examples/concurrent-upload/README.md
new file mode 100644
index 0000000000..d1e735924d
--- /dev/null
+++ b/core/examples/concurrent-upload/README.md
@@ -0,0 +1,15 @@
+# Concurrent Upload
+
+This example will show how to perform upload concurrently to a storage service.
+
+## Setup
+
+Refer [Setup](../README.md) to setup all examples.
+
+## Run
+
+Use `OPENDAL_TEST` to control which service to run example:
+
+```shell
+OPENDAL_TEST=s3 cargo run
+```
\ No newline at end of file
diff --git a/core/examples/concurrent-upload/src/main.rs
b/core/examples/concurrent-upload/src/main.rs
new file mode 100644
index 0000000000..d5350b6715
--- /dev/null
+++ b/core/examples/concurrent-upload/src/main.rs
@@ -0,0 +1,66 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use opendal::{Operator, Result};
+use std::time::SystemTime;
+
+async fn example(op: Operator) -> Result<()> {
+ let mut w = op.writer_with("test.txt").concurrent(4).await?;
+
+ let now = SystemTime::now();
+ // Write a 10MiB chunk.
+ w.write(vec![0; 10 * 1024 * 1024]).await?;
+ println!(
+ "vec![0; 10 * 1024 * 1024] uploaded at {:03}",
+ now.elapsed().unwrap().as_secs_f64()
+ );
+ // Write another 10MiB chunk.
+ w.write(vec![1; 10 * 1024 * 1024]).await?;
+ println!(
+ "vec![1; 10 * 1024 * 1024] uploaded at {:03}",
+ now.elapsed().unwrap().as_secs_f64()
+ );
+ // Finish the upload.
+ w.close().await?;
+ println!(
+ "upload finished at {:03}",
+ now.elapsed().unwrap().as_secs_f64()
+ );
+
+ let bs = op.read("test.txt").await?;
+ println!("read: {} bytes", bs.len());
+ assert_eq!(
+ bs.to_vec(),
+ vec![0; 10 * 1024 * 1024]
+ .into_iter()
+ .chain(vec![1; 10 * 1024 * 1024])
+ .collect::<Vec<_>>()
+ );
+
+ Ok(())
+}
+
+// --- The following data is not part of this example ---
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ use opendal::raw::tests::init_test_service;
+ let op = init_test_service()?.expect("OPENDAL_TEST must be set");
+
+ println!("service {:?} has been initialized", op.info());
+ example(op).await
+}
diff --git a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
b/core/examples/multipart-upload/Cargo.toml
similarity index 78%
copy from core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
copy to core/examples/multipart-upload/Cargo.toml
index f503ef8e6f..575f37aa33 100644
--- a/core/edge/s3_aws_assume_role_with_web_identity/Cargo.toml
+++ b/core/examples/multipart-upload/Cargo.toml
@@ -16,14 +16,14 @@
# under the License.
[package]
-edition = "2021"
-license = "Apache-2.0"
-name = "edge_test_aws_s3_assume_role_with_web_identity"
+name = "opendal-examples-multipart-upload"
publish = false
-rust-version = "1.75"
-version = "0.0.0"
+
+version.workspace = true
+edition.workspace = true
+rust-version.workspace = true
[dependencies]
+futures = "0.3"
opendal = { path = "../..", features = ["tests"] }
-tokio = { version = "1", features = ["full"] }
-uuid = { version = "1", features = ["serde", "v4"] }
+tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] }
diff --git a/core/examples/multipart-upload/README.md
b/core/examples/multipart-upload/README.md
new file mode 100644
index 0000000000..defd177f48
--- /dev/null
+++ b/core/examples/multipart-upload/README.md
@@ -0,0 +1,15 @@
+# Multipart Upload
+
+This example will show how to perform a multipart upload to a storage service.
+
+## Setup
+
+Refer [Setup](../README.md) to setup all examples.
+
+## Run
+
+Use `OPENDAL_TEST` to control which service to run example:
+
+```shell
+OPENDAL_TEST=s3 cargo run
+```
diff --git a/core/examples/multipart-upload/src/main.rs
b/core/examples/multipart-upload/src/main.rs
new file mode 100644
index 0000000000..7f9e4a1a27
--- /dev/null
+++ b/core/examples/multipart-upload/src/main.rs
@@ -0,0 +1,55 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use opendal::{Operator, Result};
+
+async fn example(op: Operator) -> Result<()> {
+ let mut w = op.writer("test.txt").await?;
+
+ // Write a 10MiB chunk.
+ w.write(vec![0; 10 * 1024 * 1024]).await?;
+ println!("vec![0; 10 * 1024 * 1024] uploaded");
+ // Write another 10MiB chunk.
+ w.write(vec![1; 10 * 1024 * 1024]).await?;
+ println!("vec![1; 10 * 1024 * 1024] uploaded");
+ // Finish the upload.
+ w.close().await?;
+ println!("upload finished");
+
+ let bs = op.read("test.txt").await?;
+ println!("read: {} bytes", bs.len());
+ assert_eq!(
+ bs.to_vec(),
+ vec![0; 10 * 1024 * 1024]
+ .into_iter()
+ .chain(vec![1; 10 * 1024 * 1024])
+ .collect::<Vec<_>>()
+ );
+
+ Ok(())
+}
+
+// --- The following data is not part of this example ---
+
+#[tokio::main]
+async fn main() -> Result<()> {
+ use opendal::raw::tests::init_test_service;
+ let op = init_test_service()?.expect("OPENDAL_TEST must be set");
+
+ println!("service {:?} has been initialized", op.info());
+ example(op).await
+}
diff --git a/examples/README.md b/examples/README.md
index a072e882b9..3cf11479db 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -6,5 +6,5 @@ The goal of these documents is to provide you with everything
you need to start
## Examples
-- [Rust](rust/README.md)
+- [Rust](../core/examples/README.md)
- [C++](cpp/README.md)
\ No newline at end of file
diff --git a/examples/rust/00-setup/.gitignore
b/examples/rust/00-setup/.gitignore
deleted file mode 100644
index 2c96eb1b65..0000000000
--- a/examples/rust/00-setup/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-target/
-Cargo.lock
diff --git a/examples/rust/00-setup/Cargo.toml
b/examples/rust/00-setup/Cargo.toml
deleted file mode 100644
index 2c28f6f6ee..0000000000
--- a/examples/rust/00-setup/Cargo.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[package]
-# name for this package
-name = "setup"
-# edition is the rust edition that used to compile this package.
-# We will not discuss about this a lot, use `2021` is a good choice.
-#
-# For more information: <https://doc.rust-lang.org/edition-guide/editions/>
-edition = "2021"
-# version is the semver for this package.
-# We will not publish this package publicly, so the version is leave AS-IS.
-version = "0.1.0"
-
-# In this example, we are depending on two crates (packages): `futures` and
`opendal`
-[dependencies]
-futures = "0.3"
-# The `0.45` is the semver version of opendal.
-#
-# We use `0.45` to indicate all versions that `>=0.45.0 && <0.46.0`.
-opendal = "0.45"
diff --git a/examples/rust/00-setup/README.md b/examples/rust/00-setup/README.md
deleted file mode 100644
index e8e9aded44..0000000000
--- a/examples/rust/00-setup/README.md
+++ /dev/null
@@ -1,98 +0,0 @@
-# Chapter-00: Set up Your First Rust Project
-
-Welcome to our first chapter. In this example we will set up our first Rust
project with OpenDAL.
-
-## Install Rust
-
-First of all, we need to install Rust. Refer
[here](../../../CONTRIBUTING.md#bring-your-own-toolbox) to figure it out.
-
-After Rust has been installed, we will have the following components:
-
-- `rustup`: [rustup](https://rust-lang.github.io/rustup/) is a command-line
toolchain manager for the Rust programming language. It allows you to easily
install, manage, and update different versions of the Rust compiler and
associated tools on your system.
-- `cargo`: [cargo](https://doc.rust-lang.org/cargo/index.html) is the package
manager and build system for the Rust programming language. It is designed to
make it easy to develop, build, and manage Rust projects.
-- `rustc`: [rustc](https://rustc-dev-guide.rust-lang.org/) is the official
compiler for the Rust programming language. It takes Rust source code as input
and translates it into machine-readable instructions that can be executed by
the computer's hardware. Most time, `rustc` will be called by `cargo` and we
don't need to use it directly.
-
-We can use `cargo --version` to check if it works as expected:
-
-```shell
-> cargo --version
-cargo 1.70.0 (ec8a8a0ca 2023-04-25)
-```
-
-## Rust Project Structure
-
-A typical Rust project follows a specific directory structure. The most simple
project structure will contain the following files:
-
-- `Cargo.toml`: The Cargo.toml file is the manifest file for the project. It
specifies metadata about the project, including its name, version,
dependencies, and build configuration. It is also where you declare the
project's dependencies using the Cargo package manager.
-- `src/`: The `src` directory is where the main source code files of the
project reside. It typically contains the Rust source files with the code
implementation for the project's functionality.
-
-Let's go into more depth by our example code.
-
-### `Cargo.toml`
-
-Let's take a look over [`Cargo.toml`](Cargo.toml) first.
-
-The most simple `Cargo.toml` will contains two parts:
-
-- `package`: The metadata of this package like `name`, `version`.
-- `dependencies`: The dependencies that this package will depend on. `cargo`
will download them from <https://crates.io> and compile them.
-
-### `src/`
-
-Then, let's read [`main.rs`](./src/main.rs).
-
-The most simple `main.rs` will contain only one function: `fn main()`, this is
the entry of an application.
-
-In our example, we did the following things:
-
-```rust
-use opendal::Scheme;
-```
-
-Import the `opendal::Scheme` into current namespace, so that we can use
`Scheme` instead of the full naming `opendal::Scheme` everywhere.
-
-``` rust
-fn main() {
- ...
-}
-```
-
-Declare our main function, this is the most simple function that not take any
input and not return any output.
-
-```rust
-println!("Hello, {}", Scheme::S3)
-```
-
-- `println!()` is a built macro in rust to prints to the standard output, with
a newline. Macro will be expanded to real code during compilation.
-- `"Hello, {}", Scheme::S3` is the format string in rust. It will convert
`Scheme::S3` to string, and construct a new string in this format.
-
-## Build our first rust project!
-
-Now, it's time to build our first rust project!
-
-Make sure we are under folder `examples/rust/00-setup`, running:
-
-```shell
-cargo run
-```
-
-We will see output like:
-
-```shell
-:) cargo run
- Compiling setup v0.1.0
(/home/xuanwo/Code/apache/opendal/examples/rust/00-setup)
- Finished dev [unoptimized + debuginfo] target(s) in 0.32s
- Running `target/debug/setup`
-Hello, s3
-```
-
-Congrats! Our first Rust project is built and running with success!
-
-After built, we will find that there are some new files created:
-
-- `Cargo.lock`: Cargo.lock is a file generated by the cargo package manager
when you build or run a Rust project. It serves as a lock file and records the
exact versions of dependencies that were used during the previous successful
build or run of the project. It's always a good idea to commit `Cargo.lock` to
your repo, so developers can reproduce the same build result with you.
-- `target`: `target` folder is a directory automatically generated by `rustc`
and managed cargo. It contains the compiled artifacts and build output for
specific target platforms and architectures.
-
-## Conclusion
-
-In this chapter we have learnt the Rust project structure and run our first
Rust example. We will use this knowledge to build our first Rust application in
the next chapter!
diff --git a/examples/rust/00-setup/src/main.rs
b/examples/rust/00-setup/src/main.rs
deleted file mode 100644
index 626a518c37..0000000000
--- a/examples/rust/00-setup/src/main.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-use opendal::Scheme;
-
-fn main() {
- println!("Hello, {}", Scheme::S3)
-}
diff --git a/examples/rust/01-init-operator/.gitignore
b/examples/rust/01-init-operator/.gitignore
deleted file mode 100644
index 2c96eb1b65..0000000000
--- a/examples/rust/01-init-operator/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-target/
-Cargo.lock
diff --git a/examples/rust/01-init-operator/Cargo.toml
b/examples/rust/01-init-operator/Cargo.toml
deleted file mode 100644
index 546c7e1fcb..0000000000
--- a/examples/rust/01-init-operator/Cargo.toml
+++ /dev/null
@@ -1,9 +0,0 @@
-[package]
-name = "init-operator"
-
-edition = "2021"
-version = "0.1.0"
-
-[dependencies]
-futures = "0.3"
-opendal = "0.45"
diff --git a/examples/rust/01-init-operator/README.md
b/examples/rust/01-init-operator/README.md
deleted file mode 100644
index 3387b7df2b..0000000000
--- a/examples/rust/01-init-operator/README.md
+++ /dev/null
@@ -1,168 +0,0 @@
-# Chapter-01: Initiate OpenDAL Operator
-
-The core concept in OpenDAL is the `Operator`, which is used to handle
operations on different storage services. This chapter will discuss how to
initiate OpenDAL operators.
-
-## Warmup
-
-Before delving into the OpenDAL API, let's take a look at some new Rust
features.
-
-### Enum and Set Returning Type for Function
-
-First of all, our main functions now returns `Result<()>`:
-
-```rust
-use opendal::Result;
-
-fn main() -> Result<()> {
- Ok(())
-}
-```
-
-This is one of the coolest part of Rust:
[`enum`](https://doc.rust-lang.org/book/ch06-01-defining-an-enum.html). In
rust, an `enum` (short for enumeration) is a data type that represents a value
that can be one of several possible variants. It allows you to define a set of
distinct options or choices, making it useful for scenarios where a variable
can have a limited number of predefined states.
-
-For example, Rust provide a built-in enum called `Option`:
-
-```rust
-enum Option<T> {
- Some(T),
- None,
-}
-```
-
-The `T` represents the type of the value that may or may not be present.
`Some` variant holds the actual value, while `None` indicates the absence of a
value.
-
-Rust also provides a `Result` enum for returning and propagating errors:
-
-```rust
-enum Result<T, E> {
- Ok(T),
- Err(E),
-}
-```
-
-OpenDAL defines it own `Result` type for it easier to use:
-
-```rust
-/// Result that is a wrapper of `Result<T, opendal::Error>`
-pub type Result<T> = std::result::Result<T, Error>;
-```
-
-So let's go back into our examples:
-
-```rust
-use opendal::Result;
-
-fn main() -> Result<()> {
- Ok(())
-}
-```
-
-> `use opendal::Result;`
-
-imports opendal's `Result` which will shadows Rust built-in result.
-
-> `fn main() -> Result<()>`
-
-The way that Rust to declare returning types of a function. This case means
`main` will return a `Result` which holds `()`.
-
-> `()`
-
-The `()` type has exactly one value `()`, and is used when there is no other
meaningful value that could be returned. In fact, the example in `00-setup`
could is exactly `fn main() -> () {}`.
-
-> `Ok(())`
-
-The variants of `Result` are preluded, allowing us to use `Ok` and `Err`
directly instead of having to write out `Result::Ok` and `Result::Err`. In this
context, using `Ok(())` means creating a new value for the type `Result<()>`.
-
-### Call Functions
-
-Let's go next line:
-
-```rust
-let op = init_operator_via_builder()?;
-```
-
-- `let a = b;` is the syntax in Rust for declaring an immutable variable.
-- `xxx()` means call function that named `xxx`.
-- the `?` is a syntax sugar in Rust that checks if the returned `Result` is an
`Err`. If it is, then it immediately returns that error. Otherwise, it returns
the value of `Ok`.
-
-So this line will call `init_operator_via_builder` function first and set to
variable `op` if it returns `Ok`.
-
-## Initiate Via Builder
-
-Now, we can go deeper into the OpenDAL side.
-
-Let's take look over `init_operator_via_builder` function first.
-
-```rust
-fn init_operator_via_builder() -> Result<Operator> {
- let mut builder = S3::default();
- builder.bucket("example");
- builder.access_key_id("access_key_id");
- builder.secret_access_key("secret_access_key");
- builder.region("us-east-1");
-
- let op = Operator::new(builder)?.finish();
- Ok(op)
-}
-```
-
-We have a new concept here:
-
-> let mut builder = xxx;
-
-The `mut` here means `mutable`, allowing its value to be changed later.
-
-In Rust, all variables are declared as `immutable` by default, meaning that
users cannot change their values. However, by declaring them as `mut`, we can
call mutable functions such as `bucket` and `access_key_id`.
-
-In this example, we initiate a new builder and call its functions to set
different arguments. Finally, we use `Operator::new(builder)?.finish()` to
build it.
-
-Each service provides its own builder, which can be accessed at
[opendal::services](https://opendal.apache.org/docs/rust/opendal/services/index.html).
-
-## Initiate Via Map
-
-Calling builder's API is simple and directly, but sometimes developer will
read config from files or env which will need to building operator from a map.
-
-```rust
-fn init_operator_via_map() -> Result<Operator> {
- let mut map = HashMap::default();
- map.insert("bucket".to_string(), "example".to_string());
- map.insert("access_key_id".to_string(), "access_key_id".to_string());
- map.insert(
- "secret_access_key".to_string(),
- "secret_access_key".to_string(),
- );
- map.insert("region".to_string(), "us-east-1".to_string());
-
- let op = Operator::via_map(Scheme::S3, map)?;
- Ok(op)
-}
-```
-
-In this example, we use `Operator::via_map()` API the init a new operator.
-
-## Let's Go!
-
-We will see the output of this example in this way:
-
-```shell
-:) cargo run
- Compiling init-operator v0.1.0
(/home/xuanwo/Code/apache/opendal/examples/rust/01-init-operator)
- Finished dev [unoptimized + debuginfo] target(s) in 0.38s
- Running `target/debug/init-operator`
-operator from builder: Operator { accessor: S3Backend { core: S3Core { bucket:
"example", endpoint: "https://s3.us-east-1.amazonaws.com/example", root: "/",
.. } }, limit: 1000 }
-operator from map: Operator { accessor: S3Backend { core: S3Core { bucket:
"example", endpoint: "https://s3.us-east-1.amazonaws.com/example", root: "/",
.. } }, limit: 1000 }
-```
-
-Please feel free to try initiating other services or configuring new settings
for experimentation purposes!
-
-## Conclusion
-
-In this chapter we learnt a lot of basic concepts in Rust! Now we know:
-
-- How to define a function that returns something.
-- How to declare an immutable variable.
-- How to call functions in Rust.
-- How to define and use enums.
-- How to handle results.
-
-With our newly acquired Rust skills, we can initiate the OpenDAL Operator in
two main ways. This knowledge will be used to read and write data to storage in
the next chapter!
diff --git a/examples/rust/01-init-operator/src/main.rs
b/examples/rust/01-init-operator/src/main.rs
deleted file mode 100644
index 2110dad956..0000000000
--- a/examples/rust/01-init-operator/src/main.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use std::collections::HashMap;
-
-use opendal::services::S3;
-use opendal::Operator;
-use opendal::Result;
-use opendal::Scheme;
-
-fn main() -> Result<()> {
- let op = init_operator_via_builder()?;
- println!("operator from builder: {:?}", op);
-
- let op = init_operator_via_map()?;
- println!("operator from map: {:?}", op);
-
- Ok(())
-}
-
-fn init_operator_via_builder() -> Result<Operator> {
- let mut builder = S3::default();
- builder.bucket("example");
- builder.region("us-east-1");
- builder.access_key_id("access_key_id");
- builder.secret_access_key("secret_access_key");
-
- let op = Operator::new(builder)?.finish();
- Ok(op)
-}
-
-fn init_operator_via_map() -> Result<Operator> {
- let mut map = HashMap::default();
- map.insert("bucket".to_string(), "example".to_string());
- map.insert("region".to_string(), "us-east-1".to_string());
- map.insert("access_key_id".to_string(), "access_key_id".to_string());
- map.insert(
- "secret_access_key".to_string(),
- "secret_access_key".to_string(),
- );
-
- let op = Operator::via_map(Scheme::S3, map)?;
- Ok(op)
-}
diff --git a/examples/rust/02-async-io/.gitignore
b/examples/rust/02-async-io/.gitignore
deleted file mode 100644
index 2c96eb1b65..0000000000
--- a/examples/rust/02-async-io/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-target/
-Cargo.lock
diff --git a/examples/rust/02-async-io/Cargo.toml
b/examples/rust/02-async-io/Cargo.toml
deleted file mode 100644
index bc120649e9..0000000000
--- a/examples/rust/02-async-io/Cargo.toml
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "async-io"
-
-edition = "2021"
-version = "0.1.0"
-
-[dependencies]
-futures = "0.3"
-opendal = "0.45"
-tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
diff --git a/examples/rust/02-async-io/README.md
b/examples/rust/02-async-io/README.md
deleted file mode 100644
index f86606fd61..0000000000
--- a/examples/rust/02-async-io/README.md
+++ /dev/null
@@ -1,175 +0,0 @@
-# Chapter-02: Async IO
-
-In [Chapter-01](../01-init-operator/README.md), we learnt how to initiate an
`Operator`. All operations in OpenDAL are IO bound which means most of our
users will use OpenDAL in an async runtime. This chapter will discuss how to
call `Operator` in async runtime and how to use OpenDAL to read and write data!
-
-## Warmup
-
-Before delving into the OpenDAL API, let's take a look at some new Rust
features.
-
-### Crate Features
-
-In this chapter's `Cargo.toml`, we add a new dependence `tokio`:
-
-```toml
-tokio = { version = "1", features = ["full"] }
-```
-
-The syntax is different from what we used before:
-
-```diff
-- tokio = "1"
-+ tokio = { version = "1", features = ["full"] }
-```
-
-We use this syntax to specify additional options for this dependency.
Essentially, `tokio = "1"` can be considered a shorthand for `tokio = { version
= "1" }`.
-
-The most commonly used option is `features`, which works in conjunction with
conditional compilation and the crate's configuration system. These features
allow you to enable or disable specific pieces of code within the crate based
on different use cases.
-
-For instance, since the `tokio` project has many components, not all of them
are necessary for every project. By enabling only the required features, we can
reduce build time.
-
-In our examples, we will just enable the `macros` and `"rt-multi-thread`
feature which allow use to use `#[tokio::main]` in code.
-
-### Attributes
-
-Let's back to read our `main.rs`. We will find a new thing here:
`#[tokio::main]`: the attribute macros denoted by the `#[...]` syntax and are
used to add additional metadata or behavior to the annotated item.
-
-`[tokio::main]` here will expand the following code:
-
-```rust
-#[tokio::main]
-async fn main() {
- println!("Hello world");
-}
-```
-
-into:
-
-```rust
-fn main() {
- tokio::runtime::Builder::new_multi_thread()
- .enable_all()
- .build()
- .unwrap()
- .block_on(async {
- println!("Hello world");
- })
-}
-```
-
-There are many different kinds of attributes in rust, we can refer to [The
Rust Reference -
Attributes](https://doc.rust-lang.org/reference/attributes.html#attributes) for
more information.
-
-## Async Function
-
-Another new thing here is `async fn`. By prefix `async` before `fn`, we can
declare an async function:
-
-```rust
-async fn write_data(op: Operator) -> Result<()> {
- ...
-}
-```
-
-Every async function in Rust is essentially a state machine generator. When we
call an async function, it creates a new state machine that can be polled to
determine if it has finished running or not during runtime. We described this
state machine as a
[`Future`](https://doc.rust-lang.org/std/future/trait.Future.html).
-
-If you call an async function without using `await`, it will not do anything
because we only create a `Future` but do not poll it. We will need to call
async function like the following:
-
-```rust
-async fn write_data(op: Operator) -> Result<()> {
- op.write("test", "Hello, World!").await?;
-
- Ok(())
-}
-```
-
-When using `.await`, we submit the `Future` created by `op.write("test",
"Hello, World!")` to the async runtime and continuously poll it until it
finishes.
-
-The async runtime will have multiple workers running different `Future` tasks,
allowing us to avoid blocking on IO and improving the performance of the entire
application.
-
-## Write Data
-
-Now we can go deeper into OpenDAL's API. Writing data via OpenDAL is simple:
-
-```rust
-async fn write_data(op: Operator) -> Result<()> {
- op.write("test", "Hello, World!").await?;
-
- Ok(())
-}
-```
-
-The `write` API provided by `Operator` is:
-
-```rust
-impl Operator {
- pub async fn write(&self, path: &str, bs: impl Into<Bytes>) -> Result<()>;
-}
-```
-
-`impl Into<Bytes>` here is a syntax sugar of rust, we can expand it like the
following:
-
-```rust
-impl Operator {
- pub async fn write<T>(&self, path: &str, bs: T) -> Result<()>
- where T: Into<Bytes>;
-}
-```
-
-This API means it accepts any types that implements `Into<Bytes>`. `Bytes` is
provided by
[`bytes::Bytes`](https://docs.rs/bytes/latest/bytes/struct.Bytes.html), we can
find all types that implements `Into<Bytes>` here.
-
-So we can also call `write` on:
-
-- `Vec<u8>`
-- `String`
-- `&'static str`
-
-For example:
-
-```rust
-async fn write_data(op: Operator) -> Result<()> {
- let s = "Hello, World!".to_string();
- op.write("test", s).await?;
-
- Ok(())
-}
-```
-
-The easiest way to write data into OpenDAL is by calling the "write" function.
However, OpenDAL also offers additional extensions for adding metadata to files
and writing data in a streaming manner, which eliminates the need to hold all
of the data in memory. We will cover these topics in upcoming chapters.
-
-## Read Data
-
-Reading data via OpenDAL is simple too:
-
-```rust
-async fn read_data(op: Operator) -> Result<()> {
- let bs = op.read("test").await?;
- println!("read data: {}", String::from_utf8_lossy(&bs));
-
- Ok(())
-}
-```
-
-The `read` API provided by `Operator` is:
-
-```rust
-pub async fn read(&self, path: &str) -> Result<Vec<u8>>;
-```
-
-This API will read all data from `path` and return as a `Vec<u8>`.
-
-## Conclusion
-
-In this chapter we learnt a lot basic concepts in async rust! Now we have
known that:
-
-- How to setup tokio async runtime.
-- How to define and call an async function.
-- How to write and read data via OpenDAL.
-
-## Challenge Time
-
-Now that we have mastered all the knowledge required to write and read data
via OpenDAL. Let's take on a challenge!
-
-Our challenge is to
-
-- Write and read data from AWS S3.
-- Explore the API related to `read_with` and `write_with`.
-
-See you in the next chapter!
diff --git a/examples/rust/02-async-io/src/main.rs
b/examples/rust/02-async-io/src/main.rs
deleted file mode 100644
index 1ea8533056..0000000000
--- a/examples/rust/02-async-io/src/main.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use opendal::services::Memory;
-use opendal::Operator;
-use opendal::Result;
-
-#[tokio::main]
-async fn main() -> Result<()> {
- let op = Operator::new(Memory::default())?.finish();
-
- write_data(op.clone()).await?;
- read_data(op.clone()).await?;
- Ok(())
-}
-
-async fn write_data(op: Operator) -> Result<()> {
- op.write("test", "Hello, World!").await?;
-
- Ok(())
-}
-
-async fn read_data(op: Operator) -> Result<()> {
- let bs = op.read("test").await?;
- println!("data: {}", String::from_utf8_lossy(&bs));
-
- Ok(())
-}
diff --git a/examples/rust/03-add-layers/.gitignore
b/examples/rust/03-add-layers/.gitignore
deleted file mode 100644
index 2c96eb1b65..0000000000
--- a/examples/rust/03-add-layers/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-target/
-Cargo.lock
diff --git a/examples/rust/03-add-layers/Cargo.toml
b/examples/rust/03-add-layers/Cargo.toml
deleted file mode 100644
index 8ff929e41b..0000000000
--- a/examples/rust/03-add-layers/Cargo.toml
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "add-layers"
-
-edition = "2021"
-version = "0.1.0"
-
-[dependencies]
-env_logger = "0.11"
-futures = "0.3"
-opendal = "0.45"
-tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
diff --git a/examples/rust/03-add-layers/README.md
b/examples/rust/03-add-layers/README.md
deleted file mode 100644
index 7470a15756..0000000000
--- a/examples/rust/03-add-layers/README.md
+++ /dev/null
@@ -1,126 +0,0 @@
-# Chapter-03: How To Add Layers
-
-In the preceding chapters, we have effectively utilized OpenDAL to access the
storage service and execute basic data read and write operations. This chapter
takes a step forward by introducing additional layers to manage data
operations, allowing for controlled access behavior and the acquisition of
observable data throughout the process.
-
-## What are Layers in OpenDAL
-
-OpenDAL offers native layer support, enabling users to implement middleware or
intercept for all operations. By using layers, we can retry failed requests and
resume from the point of failure with Retry Layer, provide native observability
with Tracing Layer, and so on.
-
-## Simple Examples
-
-In this section, we will incorporate practical Layers into our OpenDAL data
reading and writing operations, allowing us to experience the simplicity and
convenience they offer. You can find the complete code [here](./src/main.rs).
-
-### Adding Logging Capability
-
-Logging is an invaluable feature in daily development. OpenDAL offers
comprehensive logging support throughout various data access operations.
Specifically, OpenDAL utilizes [log](https://docs.rs/log/latest/log/) crate to
record structured logs. At the onset of each operation, an initial log entry is
made. Upon completion of each operation, a log entry is recorded to indicate
its success or failure along with the specific reasons for any failures
encountered.
-
-```diff
-+ env_logger = "0.11"
-```
-
-To utilize logging functionality, we need introduce the
[env_logger](https://docs.rs/env_logger/latest/env_logger/) crate first. This
is necessary because the [log](https://docs.rs/log/latest/log/) crate in Rust
solely offers a unified API abstraction for logging. Users can select the
appropriate crate and specific logging implementation based on their actual
requirements. Here, we opt for the
[env_logger](https://docs.rs/env_logger/latest/env_logger/) crate.
-
-```rust
-#[tokio::main]
-async fn main() -> Result<()> {
- env_logger::init();
- let op = Operator::new(Memory::default())
- .expect("must init")
- .layer(LoggingLayer::default())
- .finish();
- ...
- Ok(())
-}
-```
-
-We simply need to add a layer to the creation process of the `Operator` in a
chain call to apply the functions of the corresponding layers to the
`Operator`. Here, we add a default Logger Layer for the `Operator`. Through log
outputs, we can gain a clearer understanding of the operations performed by
OpenDAL throughout the entire process, as well as the execution status of each
operation.
-
-```shell
-$ RUST_LOG=debug cargo run
-[DEBUG opendal::services] service=memory operation=metadata -> started
-[DEBUG opendal::services] service=memory operation=metadata -> finished:
AccessorInfo { scheme: Memory, root: "/", name: "0x5565075f1ad0",
native_capability: { Stat | Read | Write | Delete | List | Blocking },
full_capability: { Stat | Read | Write | CreateDir | Delete | List | Blocking }
}
-[DEBUG opendal::services] service=memory operation=write path=test -> started
-[DEBUG opendal::services] service=memory operation=write path=test -> start
writing
-[DEBUG opendal::services] service=memory operation=write path=test written=13B
-> data written finished
-[DEBUG opendal::services] service=memory operation=stat path=test -> started
-[DEBUG opendal::services] service=memory operation=stat path=test -> finished:
RpStat { meta: Metadata { metakey: FlagSet(Complete | Mode | ContentLength),
mode: FILE, cache_control: None, content_disposition: None, content_length:
Some(13), content_md5: None, content_range: None, content_type: None, etag:
None, last_modified: None, version: None } }
-[DEBUG opendal::services] service=memory operation=read path=test range=0-12
-> started
-[DEBUG opendal::services] service=memory operation=read path=test range=0-12
-> got reader
-[DEBUG opendal::services] service=memory operation=read path=test read=13 ->
data read finished
-data: Hello, World!
-```
-
-Next let's execute the code. It's important to note that when running the
code, you'll need to include RUST_LOG and specify the log output level. After
running the sample code, you'll see output similar to the above on your
terminal. By enabling Logging Layer, OpenDAL no longer appears as a black box!
By controlling the location and level of log output, you can access all the
details you wish to know.
-
-### Stacking Timeout Layer
-
-OpenDAL not only supports adding a layer to the `Operator`, but also enables
the addition of all necessary layers to the `Operator` through chain calls.
Let's continue by stacking the Timeout Layer on top of the Logger Layer.
-
-```Rust
-let op = Operator::new(Memory::default())
- .expect("must init")
- .layer(LoggingLayer::default())
- .layer(
- TimeoutLayer::default()
- .with_timeout(Duration::from_secs(5))
- .with_io_timeout(Duration::from_secs(3))
- )
- .finish();
-```
-
-We can directly add the Timeout Layer in a unified manner based on the
previous code. Each operation in the `Operator` can be categorized into IO
operations and non-IO operations. Users can set different timeouts for each
operation according to their actual needs. In this example, we set a 5-second
timeout for non-IO operations and a 3-second timeout for IO operations in the
`Operator`.
-
-Through the Timeout Layer, we can prevent any operation in OpenDAL from
waiting excessively long or getting stuck indefinitely due to unforeseen
circumstances. For instance, a dead connection might cause a SQL query to hang
indefinitely. The Timeout Layer will terminate such connections and return an
error, enabling users to handle them by retrying or directly informing the
users.
-
-## More Useful Layers
-
-### Retry Layer
-
-The Retry Layer provides the ability for OpenDAL to automatically retry
related operations when an error occurs in a data access operation based on
OpenDAL.
-
-OpenDAL uses an exponential backoff algorithm to retry erroneous requests to
avoid request current limiting and conflicts to the greatest extent, and
provides relevant settings to further control retry behavior. Specifically,
OpenDAL supports setting the maximum number of retries, the minimum retry
interval, the maximum retry interval, the jitter and exponential coefficients
in the exponential backoff algorithm, and setting the callback function for
each retry.
-
-In addition, OpenDAL divides errors in requests into three types: `Permanent`,
`Temporary` and `Persistent`:
-
-- `Permanent` means that the error cannot be solved by retrying, such as `Not
Found` error and permission authentication error. At this time, OpenDAL will
not retry the error request to avoid adding additional unnecessary request
traffic;
-- `Temporary` means that the error is temporary and may be resolved by
retrying. For example, the storage service returns a traffic restriction error.
After adding the Retry Layer, OpenDAL will automatically retry this type of
request;
-- `Persistent` means that the request error cannot be resolved after retrying,
such as continuing network error. `Persistent` is transformed from `Temporary`.
-
-Users can further judge the service running status based on the error type
returned by the OpenDAL request.
-
-### Concurrent Limit Layer
-
-Through the Concurrency Limit Layer, users can control the maximum number of
concurrent connections between OpenDAL and the underlying storage service. This
control can effectively manage system resources and avoid the risk of excessive
resource usage leading to performance degradation or system crash.
-
-### Blocking Layer
-
-As introduced in the previous chapters, OpenDAL uses the Rust asynchronous
runtime to ensure efficient processing of IO requests. Blocking Layer provides
a synchronous semantic wrapper for operations in OpenDAL, allowing users to
bridge the use of many underlying asynchronous services provided by OpenDAL
with synchronous semantics.
-
-In addition, since synchronization bridging involving asynchronous functions
involves knowledge about the [Tokio](https://docs.rs/tokio/latest/tokio/)
runtime, users need additional processing when using this type of interface.
This is beyond the scope of this tutorial, more examples can be found in
https://docs.rs/opendal/latest/opendal/layers/struct.BlockingLayer.html.
-
-### Built-in Layers in OpenDAL
-
-An interesting fact is that OpenDAL applies some layers by default for every
operation, such as Error Context Layer and Complete Layer. These built-in
layers are usually very thin, light and in a zero-cost way. So there is no need
to worry about its impact on data access performance, but they can greatly
enhance the user experience.
-
-Error Context Layer injects context information, such as service (the `Scheme`
of underlying service), operation (the `Operation` of this operation), path
(the path of this operation), into all returned errors of operations.
-
-Complete Layer adds necessary capabilities to services, complete underlying
services features. OpenDAL exposes a unified interface implementation through
Complete Layer, so that users can use them in the same way, and OpenDAL will
always choose the optimal way to initiate the request.
-
-For example, S3 cannot support `seek`, but OpenDAL will implement it at zero
cost manner according to existing methods provided by S3. So users don't have
to worry about whether the underlying service supports, they only need to pay
attention to what methods OpenDAL provides. And the good news is OpenDAL always
provides interfaces in a unified way. ^_^
-
-### Others
-
-In addition to the many practical layers mentioned above, OpenDAL also
provides support for corresponding observability and fine-grained control
layers of data access for various scenarios, such as:
-
-- [Metrics
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.MetricsLayer.html):
add [metrics](https://docs.rs/metrics/) for every operations;
-- [Tracing
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.TracingLayer.html):
add [tracing](https://docs.rs/tracing/) for every operations;
-- [Prometheus
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.PrometheusLayer.html):
add [prometheus](https://docs.rs/prometheus) for every operations;
-- [Minitrace
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.MinitraceLayer.html):
add [minitrace](https://docs.rs/minitrace/) for every operations;
-- [Immutable Index
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.ImmutableIndexLayer.html):
add an immutable in-memory index for underlying storage services;
-- [Throttle
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.ThrottleLayer.html):
add a bandwidth rate limiter to the underlying services;
-- [Await Tree
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.AwaitTreeLayer.html):
add a instrument await-tree for actor-based applications to the underlying
services;
-- [Async Backtrace
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.AsyncBacktraceLayer.html):
add efficient, logical stack traces of async functions for the underlying
services;
-- [Madsim
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.MadsimServer.html):
add deterministic simulation for async operations;
-- [Chaos
Layer](https://docs.rs/opendal/latest/opendal/layers/struct.ChaosLayer.html):
inject chaos into underlying services for robustness test.
-
-In the end, this article serves as an introductory tutorial to introduce the
techniques of using various layers in OpenDAL. You can refer to
https://docs.rs/opendal/latest/opendal/layers/index.html to learn more about
the layers provided in OpenDAL. Maybe there is an integrated solution you are
looking for!
diff --git a/examples/rust/03-add-layers/src/main.rs
b/examples/rust/03-add-layers/src/main.rs
deleted file mode 100644
index 20b88c7792..0000000000
--- a/examples/rust/03-add-layers/src/main.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use std::time::Duration;
-
-use env_logger;
-use opendal::layers::LoggingLayer;
-use opendal::layers::TimeoutLayer;
-use opendal::services::Memory;
-use opendal::Operator;
-use opendal::Result;
-
-#[tokio::main]
-async fn main() -> Result<()> {
- env_logger::init();
-
- let op = Operator::new(Memory::default())
- .expect("must init")
- .layer(LoggingLayer::default())
- .layer(
- TimeoutLayer::default()
- .with_timeout(Duration::from_secs(5))
- .with_io_timeout(Duration::from_secs(3)),
- )
- .finish();
-
- write_data(op.clone()).await?;
- read_data(op.clone()).await?;
- Ok(())
-}
-
-async fn write_data(op: Operator) -> Result<()> {
- op.write("test", "Hello, World!").await?;
-
- Ok(())
-}
-
-async fn read_data(op: Operator) -> Result<()> {
- let bs = op.read("test").await?;
- println!("data: {}", String::from_utf8_lossy(&bs));
-
- Ok(())
-}
diff --git a/examples/rust/README.md b/examples/rust/README.md
deleted file mode 100644
index 5c179c3b30..0000000000
--- a/examples/rust/README.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# OpenDAL Rust Examples
-
-Thank you for using OpenDAL Rust Core!
-
-The goal of these documents is to give you everything you need to start using
OpenDAL Rust Core. We will start with the Rust basics and move on to more
OpenDAL features. After reading and using all these examples, we hope you will
become a master of OpenDAL and be empowered to build your bravo applications!
-
-## Layout
-
-Our examples are organised like a book with different chapters.
-
-It's a good idea to start reading from the first chapter. It's also ok to pick
the topics that interest you the most. Each chapter will be a separate project
that can be run and referenced.
-
-## Contents
-
-- [Chapter-00: Set up Your First Rust Project](./00-setup/README.md)
-- [Chapter-01: Initiate OpenDAL Operator](./01-init-operator/README.md)
-- [Chapter-02: Async IO](./02-async-io/README.md)
-- [Chapter-03: How To Add Layers](./03-add-layers/README.md)