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 953d472450 docs: Add docs of options for xxx_with APIs (#4099)
953d472450 is described below

commit 953d472450b8b1b8f71ad575289839e64ffcef5f
Author: Xuanwo <[email protected]>
AuthorDate: Tue Jan 30 18:39:32 2024 +0800

    docs: Add docs of options for xxx_with APIs (#4099)
    
    * docs: Add options for xxx_with APIs
    
    Signed-off-by: Xuanwo <[email protected]>
    
    * Update opendal.h
    
    Signed-off-by: Xuanwo <[email protected]>
    
    ---------
    
    Signed-off-by: Xuanwo <[email protected]>
---
 bin/ofs/Cargo.toml                           |  10 +-
 bindings/c/include/opendal.h                 |   1 -
 bindings/java/Cargo.toml                     |   2 +-
 bindings/nodejs/Cargo.toml                   |   2 +-
 bindings/php/Cargo.toml                      |   2 +-
 bindings/python/Cargo.toml                   |   2 +-
 bindings/ruby/Cargo.toml                     |   2 +-
 core/Cargo.toml                              |   8 +-
 core/src/layers/dtrace.rs                    |  27 +-
 core/src/layers/timeout.rs                   |  35 +-
 core/src/raw/oio/write/block_write.rs        |  16 +-
 core/src/raw/oio/write/multipart_write.rs    |  10 +-
 core/src/raw/oio/write/range_write.rs        |  12 +-
 core/src/raw/path_cache.rs                   |  17 +-
 core/src/raw/tokio_util.rs                   |   3 +-
 core/src/services/dropbox/builder.rs         |   2 +-
 core/src/services/gdrive/builder.rs          |   9 +-
 core/src/services/gdrive/core.rs             |   2 +-
 core/src/services/gdrive/writer.rs           |   3 +-
 core/src/services/ghac/backend.rs            |   3 +-
 core/src/services/hdfs_native/backend.rs     |   5 +-
 core/src/services/hdfs_native/error.rs       |   3 +-
 core/src/services/hdfs_native/lister.rs      |   6 +-
 core/src/services/hdfs_native/reader.rs      |  11 +-
 core/src/services/hdfs_native/writer.rs      |   7 +-
 core/src/services/icloud/backend.rs          |   8 +-
 core/src/services/icloud/core.rs             |  17 +-
 core/src/services/koofr/core.rs              |   3 +-
 core/src/services/mod.rs                     |   1 -
 core/src/services/sftp/lister.rs             |   3 +-
 core/src/services/yandex_disk/backend.rs     |   9 +-
 core/src/services/yandex_disk/core.rs        |  14 +-
 core/src/services/yandex_disk/writer.rs      |   8 +-
 core/src/types/operator/blocking_operator.rs |   1 -
 core/src/types/operator/operator.rs          | 609 ++++++++++++++++++++++++---
 core/src/types/operator/operator_futures.rs  |  70 +--
 36 files changed, 740 insertions(+), 203 deletions(-)

diff --git a/bin/ofs/Cargo.toml b/bin/ofs/Cargo.toml
index 860904d7ce..552f68649d 100644
--- a/bin/ofs/Cargo.toml
+++ b/bin/ofs/Cargo.toml
@@ -30,20 +30,20 @@ repository.workspace = true
 rust-version.workspace = true
 
 [dependencies]
+anyhow = "1"
 async-trait = "0.1.75"
+clap = { version = "4.4.18", features = ["derive", "env"] }
+env_logger = "0.10"
 fuse3 = { "version" = "0.6.1", "features" = ["tokio-runtime", "unprivileged"] }
 futures-util = "0.3.30"
 libc = "0.2.151"
 log = "0.4.20"
-anyhow = "1"
+nix = { version = "0.27.1", features = ["user"] }
+opendal.workspace = true
 tokio = { version = "1.34", features = [
   "fs",
   "macros",
   "rt-multi-thread",
   "io-std",
 ] }
-nix = { version = "0.27.1", features = ["user"] }
-env_logger = "0.10"
-clap = { version = "4.4.18", features = ["derive", "env"] }
 url = "2.5.0"
-opendal.workspace = true
diff --git a/bindings/c/include/opendal.h b/bindings/c/include/opendal.h
index 3eb0dc0a3b..daf50f169b 100644
--- a/bindings/c/include/opendal.h
+++ b/bindings/c/include/opendal.h
@@ -120,7 +120,6 @@ typedef struct BlockingLister BlockingLister;
  *
  * Some services like s3, gcs doesn't have native blocking supports, we can 
use [`layers::BlockingLayer`]
  * to wrap the async operator to make it blocking.
- *
  * # use anyhow::Result;
  * use opendal::layers::BlockingLayer;
  * use opendal::services::S3;
diff --git a/bindings/java/Cargo.toml b/bindings/java/Cargo.toml
index 7e38605d88..8038362885 100644
--- a/bindings/java/Cargo.toml
+++ b/bindings/java/Cargo.toml
@@ -98,8 +98,8 @@ services-all = [
 # Default services provided by opendal.
 services-azblob = ["opendal/services-azblob"]
 services-azdls = ["opendal/services-azdls"]
-services-cos = ["opendal/services-cos"]
 services-chainsafe = ["opendal/services-chainsafe"]
+services-cos = ["opendal/services-cos"]
 services-fs = ["opendal/services-fs"]
 services-gcs = ["opendal/services-gcs"]
 services-ghac = ["opendal/services-ghac"]
diff --git a/bindings/nodejs/Cargo.toml b/bindings/nodejs/Cargo.toml
index 9521e3ba7a..b387f28b12 100644
--- a/bindings/nodejs/Cargo.toml
+++ b/bindings/nodejs/Cargo.toml
@@ -93,8 +93,8 @@ services-all = [
 # Default services provided by opendal.
 services-azblob = ["opendal/services-azblob"]
 services-azdls = ["opendal/services-azdls"]
-services-cos = ["opendal/services-cos"]
 services-chainsafe = ["opendal/services-chainsafe"]
+services-cos = ["opendal/services-cos"]
 services-fs = ["opendal/services-fs"]
 services-gcs = ["opendal/services-gcs"]
 services-ghac = ["opendal/services-ghac"]
diff --git a/bindings/php/Cargo.toml b/bindings/php/Cargo.toml
index 0b0a504b48..3ad2a50849 100644
--- a/bindings/php/Cargo.toml
+++ b/bindings/php/Cargo.toml
@@ -17,8 +17,8 @@
 
 [package]
 name = "opendal-php"
-version = "0.1.0"
 publish = false
+version = "0.1.0"
 
 authors = ["Apache OpenDAL <[email protected]>"]
 edition = "2021"
diff --git a/bindings/python/Cargo.toml b/bindings/python/Cargo.toml
index eb964de02f..760fb2430b 100644
--- a/bindings/python/Cargo.toml
+++ b/bindings/python/Cargo.toml
@@ -95,8 +95,8 @@ services-all = [
 # Default services provided by opendal.
 services-azblob = ["opendal/services-azblob"]
 services-azdls = ["opendal/services-azdls"]
-services-cos = ["opendal/services-cos"]
 services-chainsafe = ["opendal/services-chainsafe"]
+services-cos = ["opendal/services-cos"]
 services-fs = ["opendal/services-fs"]
 services-gcs = ["opendal/services-gcs"]
 services-ghac = ["opendal/services-ghac"]
diff --git a/bindings/ruby/Cargo.toml b/bindings/ruby/Cargo.toml
index f790c78890..d28d120399 100644
--- a/bindings/ruby/Cargo.toml
+++ b/bindings/ruby/Cargo.toml
@@ -17,8 +17,8 @@
 
 [package]
 name = "opendal-ruby"
-version = "0.1.0"
 publish = false
+version = "0.1.0"
 
 authors = ["Apache OpenDAL <[email protected]>"]
 edition = "2021"
diff --git a/core/Cargo.toml b/core/Cargo.toml
index 5f315bd541..908e189141 100644
--- a/core/Cargo.toml
+++ b/core/Cargo.toml
@@ -111,8 +111,8 @@ layers-await-tree = ["dep:await-tree"]
 # Enable layers async-backtrace support.
 layers-async-backtrace = ["dep:async-backtrace"]
 # Enable dtrace support.
-layers-dtrace=["dep:probe"]
 layers-blocking = ["internal-tokio-rt"]
+layers-dtrace = ["dep:probe"]
 
 services-alluxio = []
 services-atomicserver = ["dep:atomic_lib"]
@@ -156,9 +156,9 @@ services-gridfs = ["dep:mongodb"]
 services-hdfs = ["dep:hdrs"]
 services-http = []
 services-huggingface = []
+services-icloud = ["internal-path-cache"]
 services-ipfs = ["dep:prost"]
 services-ipmfs = []
-services-icloud = ["internal-path-cache"]
 services-koofr = []
 services-libsql = ["dep:hrana-client-proto"]
 services-memcached = ["dep:bb8"]
@@ -202,11 +202,11 @@ services-vercel-artifacts = []
 # Deprecated
 # wasabi services support has been removed.
 # We will remove this feature in the next version.
+services-hdfs-native = ["hdfs-native"]
 services-wasabi = []
 services-webdav = []
 services-webhdfs = []
 services-yandex-disk = []
-services-hdfs-native = ["hdfs-native"]
 
 internal-tokio-rt = ["tokio/rt-multi-thread"]
 
@@ -341,7 +341,7 @@ suppaftp = { version = "5.3.1", default-features = false, 
features = [
 # for services-tikv
 tikv-client = { version = "0.3.0", optional = true, default-features = false }
 # for services-hdfs-native
-hdfs-native = { version = "0.6.0", optional = true}
+hdfs-native = { version = "0.6.0", optional = true }
 
 # Layers
 # for layers-async-backtrace
diff --git a/core/src/layers/dtrace.rs b/core/src/layers/dtrace.rs
index 389c29f27c..0eb0ce02f6 100644
--- a/core/src/layers/dtrace.rs
+++ b/core/src/layers/dtrace.rs
@@ -15,12 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::raw::Accessor;
-use crate::raw::*;
-use crate::*;
-use async_trait::async_trait;
-use bytes::Bytes;
-use probe::probe_lazy;
 use std::ffi::CString;
 use std::fmt::Debug;
 use std::fmt::Formatter;
@@ -28,6 +22,14 @@ use std::io;
 use std::task::Context;
 use std::task::Poll;
 
+use async_trait::async_trait;
+use bytes::Bytes;
+use probe::probe_lazy;
+
+use crate::raw::Accessor;
+use crate::raw::*;
+use crate::*;
+
 /// Support User Statically-Defined Tracing(aka USDT) on Linux
 ///
 /// This layer is an experimental feature, it will be enabled by `features = 
["layers-dtrace"]` in Cargo.toml.
@@ -113,11 +115,10 @@ use std::task::Poll;
 ///
 /// Example:
 /// ```
-///
 /// use anyhow::Result;
+/// use opendal::layers::DTraceLayer;
 /// use opendal::services::Fs;
 /// use opendal::Operator;
-/// use opendal::layers::DTraceLayer;
 ///
 /// #[tokio::main]
 /// async fn main() -> Result<()> {
@@ -126,10 +127,12 @@ use std::task::Poll;
 ///     builder.root("/tmp");
 ///
 ///     // `Accessor` provides the low level APIs, we will use `Operator` 
normally.
-///     let op: Operator = 
Operator::new(builder)?.layer(DtraceLayer::default()).finish();
-///     
-///     let path="/tmp/test.txt";
-///     for _ in 1..100000{
+///     let op: Operator = Operator::new(builder)?
+///         .layer(DtraceLayer::default())
+///         .finish();
+///
+///     let path = "/tmp/test.txt";
+///     for _ in 1..100000 {
 ///         let bs = vec![0; 64 * 1024 * 1024];
 ///         op.write(path, bs).await?;
 ///         op.read(path).await?;
diff --git a/core/src/layers/timeout.rs b/core/src/layers/timeout.rs
index c05d211f90..4eec45bd87 100644
--- a/core/src/layers/timeout.rs
+++ b/core/src/layers/timeout.rs
@@ -18,8 +18,9 @@
 use std::future::Future;
 use std::io::SeekFrom;
 use std::pin::Pin;
+use std::task::ready;
+use std::task::Context;
 use std::task::Poll;
-use std::task::{ready, Context};
 use std::time::Duration;
 
 use async_trait::async_trait;
@@ -57,18 +58,21 @@ use crate::*;
 /// operations, 3 seconds timeout for all io operations.
 ///
 /// ```
+/// use std::time::Duration;
+///
 /// use anyhow::Result;
 /// use opendal::layers::TimeoutLayer;
 /// use opendal::services;
 /// use opendal::Operator;
 /// use opendal::Scheme;
-/// use std::time::Duration;
 ///
 /// let _ = Operator::new(services::Memory::default())
 ///     .expect("must init")
-///     .layer(TimeoutLayer::default()
-///         .with_timeout(Duration::from_secs(10))
-///         .with_io_timeout(Duration::from_secs(3)))
+///     .layer(
+///         TimeoutLayer::default()
+///             .with_timeout(Duration::from_secs(10))
+///             .with_io_timeout(Duration::from_secs(3)),
+///     )
 ///     .finish();
 /// ```
 ///
@@ -368,17 +372,22 @@ impl<R: oio::List> oio::List for TimeoutWrapper<R> {
 
 #[cfg(test)]
 mod tests {
-    use crate::layers::{TimeoutLayer, TypeEraseLayer};
-    use crate::raw::oio::ReadExt;
-    use crate::raw::*;
-    use crate::*;
-    use async_trait::async_trait;
-    use bytes::Bytes;
     use std::io::SeekFrom;
     use std::sync::Arc;
-    use std::task::{Context, Poll};
+    use std::task::Context;
+    use std::task::Poll;
     use std::time::Duration;
-    use tokio::time::{sleep, timeout};
+
+    use async_trait::async_trait;
+    use bytes::Bytes;
+    use tokio::time::sleep;
+    use tokio::time::timeout;
+
+    use crate::layers::TimeoutLayer;
+    use crate::layers::TypeEraseLayer;
+    use crate::raw::oio::ReadExt;
+    use crate::raw::*;
+    use crate::*;
 
     #[derive(Debug, Clone, Default)]
     struct MockService;
diff --git a/core/src/raw/oio/write/block_write.rs 
b/core/src/raw/oio/write/block_write.rs
index aecc7c66c6..af4e79a058 100644
--- a/core/src/raw/oio/write/block_write.rs
+++ b/core/src/raw/oio/write/block_write.rs
@@ -326,14 +326,20 @@ where
 
 #[cfg(test)]
 mod tests {
-    use super::*;
-    use crate::raw::oio::{StreamExt, WriteBuf, WriteExt};
-    use bytes::Bytes;
-    use pretty_assertions::assert_eq;
-    use rand::{thread_rng, Rng, RngCore};
     use std::collections::HashMap;
     use std::sync::Mutex;
 
+    use bytes::Bytes;
+    use pretty_assertions::assert_eq;
+    use rand::thread_rng;
+    use rand::Rng;
+    use rand::RngCore;
+
+    use super::*;
+    use crate::raw::oio::StreamExt;
+    use crate::raw::oio::WriteBuf;
+    use crate::raw::oio::WriteExt;
+
     struct TestWrite {
         length: u64,
         bytes: HashMap<Uuid, Bytes>,
diff --git a/core/src/raw/oio/write/multipart_write.rs 
b/core/src/raw/oio/write/multipart_write.rs
index 60c6f7d529..46d215ed12 100644
--- a/core/src/raw/oio/write/multipart_write.rs
+++ b/core/src/raw/oio/write/multipart_write.rs
@@ -404,11 +404,15 @@ where
 
 #[cfg(test)]
 mod tests {
+    use std::sync::Mutex;
+
+    use pretty_assertions::assert_eq;
+    use rand::thread_rng;
+    use rand::Rng;
+    use rand::RngCore;
+
     use super::*;
     use crate::raw::oio::WriteExt;
-    use pretty_assertions::assert_eq;
-    use rand::{thread_rng, Rng, RngCore};
-    use std::sync::Mutex;
 
     struct TestWrite {
         upload_id: String,
diff --git a/core/src/raw/oio/write/range_write.rs 
b/core/src/raw/oio/write/range_write.rs
index e4210b5ab0..496722266b 100644
--- a/core/src/raw/oio/write/range_write.rs
+++ b/core/src/raw/oio/write/range_write.rs
@@ -354,13 +354,17 @@ impl<W: RangeWrite> oio::Write for RangeWriter<W> {
 
 #[cfg(test)]
 mod tests {
-    use super::*;
-    use crate::raw::oio::WriteExt;
-    use pretty_assertions::assert_eq;
-    use rand::{thread_rng, Rng, RngCore};
     use std::collections::HashSet;
     use std::sync::Mutex;
 
+    use pretty_assertions::assert_eq;
+    use rand::thread_rng;
+    use rand::Rng;
+    use rand::RngCore;
+
+    use super::*;
+    use crate::raw::oio::WriteExt;
+
     struct TestWrite {
         length: u64,
         bytes: HashSet<u64>,
diff --git a/core/src/raw/path_cache.rs b/core/src/raw/path_cache.rs
index 45efbf8691..b7926f4029 100644
--- a/core/src/raw/path_cache.rs
+++ b/core/src/raw/path_cache.rs
@@ -15,12 +15,15 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::raw::*;
-use crate::*;
+use std::collections::VecDeque;
+
 use async_trait::async_trait;
 use moka::sync::Cache;
-use std::collections::VecDeque;
-use tokio::sync::{Mutex, MutexGuard};
+use tokio::sync::Mutex;
+use tokio::sync::MutexGuard;
+
+use crate::raw::*;
+use crate::*;
 
 /// The trait required for path cacher.
 #[cfg_attr(not(target_arch = "wasm32"), async_trait)]
@@ -191,10 +194,12 @@ impl<Q: PathQuery> PathCacher<Q> {
 
 #[cfg(test)]
 mod tests {
-    use crate::raw::{PathCacher, PathQuery};
-    use crate::*;
     use async_trait::async_trait;
 
+    use crate::raw::PathCacher;
+    use crate::raw::PathQuery;
+    use crate::*;
+
     struct TestQuery {}
 
     #[async_trait]
diff --git a/core/src/raw/tokio_util.rs b/core/src/raw/tokio_util.rs
index bceff00147..528d995c19 100644
--- a/core/src/raw/tokio_util.rs
+++ b/core/src/raw/tokio_util.rs
@@ -15,7 +15,8 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::{Error, ErrorKind};
+use crate::Error;
+use crate::ErrorKind;
 
 /// Parse tokio error into opendal::Error.
 pub fn new_task_join_error(e: tokio::task::JoinError) -> Error {
diff --git a/core/src/services/dropbox/builder.rs 
b/core/src/services/dropbox/builder.rs
index 36eeceaee0..2bdc7726e4 100644
--- a/core/src/services/dropbox/builder.rs
+++ b/core/src/services/dropbox/builder.rs
@@ -15,7 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use serde::Deserialize;
 use std::collections::HashMap;
 use std::fmt::Debug;
 use std::fmt::Formatter;
@@ -23,6 +22,7 @@ use std::sync::Arc;
 
 use chrono::DateTime;
 use chrono::Utc;
+use serde::Deserialize;
 use tokio::sync::Mutex;
 
 use super::backend::DropboxBackend;
diff --git a/core/src/services/gdrive/builder.rs 
b/core/src/services/gdrive/builder.rs
index bcb495d8f7..5ee80ab4c6 100644
--- a/core/src/services/gdrive/builder.rs
+++ b/core/src/services/gdrive/builder.rs
@@ -27,10 +27,13 @@ use serde::Deserialize;
 use tokio::sync::Mutex;
 
 use super::backend::GdriveBackend;
-use crate::raw::{normalize_root, PathCacher};
-use crate::raw::{ConfigDeserializer, HttpClient};
+use crate::raw::normalize_root;
+use crate::raw::ConfigDeserializer;
+use crate::raw::HttpClient;
+use crate::raw::PathCacher;
+use crate::services::gdrive::core::GdriveCore;
+use crate::services::gdrive::core::GdrivePathQuery;
 use crate::services::gdrive::core::GdriveSigner;
-use crate::services::gdrive::core::{GdriveCore, GdrivePathQuery};
 use crate::Scheme;
 use crate::*;
 
diff --git a/core/src/services/gdrive/core.rs b/core/src/services/gdrive/core.rs
index 96ad5f1e11..0f6211666d 100644
--- a/core/src/services/gdrive/core.rs
+++ b/core/src/services/gdrive/core.rs
@@ -15,11 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use async_trait::async_trait;
 use std::fmt::Debug;
 use std::fmt::Formatter;
 use std::sync::Arc;
 
+use async_trait::async_trait;
 use bytes;
 use bytes::Bytes;
 use chrono::DateTime;
diff --git a/core/src/services/gdrive/writer.rs 
b/core/src/services/gdrive/writer.rs
index 251787064e..037b87c23d 100644
--- a/core/src/services/gdrive/writer.rs
+++ b/core/src/services/gdrive/writer.rs
@@ -20,7 +20,8 @@ use std::sync::Arc;
 use async_trait::async_trait;
 use http::StatusCode;
 
-use super::core::{GdriveCore, GdriveFile};
+use super::core::GdriveCore;
+use super::core::GdriveFile;
 use super::error::parse_error;
 use crate::raw::oio::WriteBuf;
 use crate::raw::*;
diff --git a/core/src/services/ghac/backend.rs 
b/core/src/services/ghac/backend.rs
index 61b8b2598a..6319ae7f43 100644
--- a/core/src/services/ghac/backend.rs
+++ b/core/src/services/ghac/backend.rs
@@ -20,15 +20,16 @@ use std::env;
 
 use async_trait::async_trait;
 use bytes::Bytes;
+use http::header;
 use http::header::ACCEPT;
 use http::header::AUTHORIZATION;
 use http::header::CONTENT_LENGTH;
 use http::header::CONTENT_RANGE;
 use http::header::CONTENT_TYPE;
 use http::header::USER_AGENT;
+use http::Request;
 use http::Response;
 use http::StatusCode;
-use http::{header, Request};
 use log::debug;
 use serde::Deserialize;
 use serde::Serialize;
diff --git a/core/src/services/hdfs_native/backend.rs 
b/core/src/services/hdfs_native/backend.rs
index 5c5412b3d8..48ef1caae6 100644
--- a/core/src/services/hdfs_native/backend.rs
+++ b/core/src/services/hdfs_native/backend.rs
@@ -16,15 +16,16 @@
 // under the License.
 
 use std::collections::HashMap;
-use std::fmt::{Debug, Formatter};
+use std::fmt::Debug;
+use std::fmt::Formatter;
 use std::sync::Arc;
 
 use async_trait::async_trait;
 use hdfs_native::WriteOptions;
 use log::debug;
 use serde::Deserialize;
-// use uuid::Uuid;
 
+// use uuid::Uuid;
 use super::error::parse_hdfs_error;
 use super::lister::HdfsNativeLister;
 use super::reader::HdfsNativeReader;
diff --git a/core/src/services/hdfs_native/error.rs 
b/core/src/services/hdfs_native/error.rs
index 4432716535..215f319cf8 100644
--- a/core/src/services/hdfs_native/error.rs
+++ b/core/src/services/hdfs_native/error.rs
@@ -15,9 +15,10 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::*;
 use hdfs_native::HdfsError;
 
+use crate::*;
+
 /// Parse hdfs-native error into opendal::Error.
 pub fn parse_hdfs_error(hdfs_error: HdfsError) -> Error {
     let (kind, retryable, msg) = match &hdfs_error {
diff --git a/core/src/services/hdfs_native/lister.rs 
b/core/src/services/hdfs_native/lister.rs
index deb4336446..65c916c280 100644
--- a/core/src/services/hdfs_native/lister.rs
+++ b/core/src/services/hdfs_native/lister.rs
@@ -15,11 +15,13 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use std::sync::Arc;
+use std::task::Context;
+use std::task::Poll;
+
 use crate::raw::oio;
 use crate::raw::oio::Entry;
 use crate::*;
-use std::sync::Arc;
-use std::task::{Context, Poll};
 
 pub struct HdfsNativeLister {
     _path: String,
diff --git a/core/src/services/hdfs_native/reader.rs 
b/core/src/services/hdfs_native/reader.rs
index babbbf32b1..784d0678df 100644
--- a/core/src/services/hdfs_native/reader.rs
+++ b/core/src/services/hdfs_native/reader.rs
@@ -15,12 +15,15 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::raw::oio::Read;
-use crate::*;
+use std::io::SeekFrom;
+use std::task::Context;
+use std::task::Poll;
+
 use bytes::Bytes;
 use hdfs_native::file::FileReader;
-use std::io::SeekFrom;
-use std::task::{Context, Poll};
+
+use crate::raw::oio::Read;
+use crate::*;
 
 pub struct HdfsNativeReader {
     _f: FileReader,
diff --git a/core/src/services/hdfs_native/writer.rs 
b/core/src/services/hdfs_native/writer.rs
index de0349eacf..e781b463cb 100644
--- a/core/src/services/hdfs_native/writer.rs
+++ b/core/src/services/hdfs_native/writer.rs
@@ -15,11 +15,14 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use std::task::Context;
+use std::task::Poll;
+
+use hdfs_native::file::FileWriter;
+
 use crate::raw::oio;
 use crate::raw::oio::WriteBuf;
 use crate::*;
-use hdfs_native::file::FileWriter;
-use std::task::{Context, Poll};
 
 pub struct HdfsNativeWriter {
     _f: FileWriter,
diff --git a/core/src/services/icloud/backend.rs 
b/core/src/services/icloud/backend.rs
index 52886dfa98..8f6628ae0e 100644
--- a/core/src/services/icloud/backend.rs
+++ b/core/src/services/icloud/backend.rs
@@ -15,12 +15,14 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use std::collections::HashMap;
+use std::fmt::Debug;
+use std::fmt::Formatter;
+use std::sync::Arc;
+
 use async_trait::async_trait;
 use http::StatusCode;
 use serde::Deserialize;
-use std::collections::HashMap;
-use std::fmt::{Debug, Formatter};
-use std::sync::Arc;
 use tokio::sync::Mutex;
 
 use super::core::*;
diff --git a/core/src/services/icloud/core.rs b/core/src/services/icloud/core.rs
index 0430e954fb..77f747a1bf 100644
--- a/core/src/services/icloud/core.rs
+++ b/core/src/services/icloud/core.rs
@@ -15,18 +15,22 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use async_trait::async_trait;
-use bytes::{Buf, Bytes};
 use std::collections::BTreeMap;
-use std::fmt::{Debug, Formatter};
+use std::fmt::Debug;
+use std::fmt::Formatter;
 use std::sync::Arc;
 
+use async_trait::async_trait;
+use bytes::Buf;
+use bytes::Bytes;
 use http::header;
-use http::header::{IF_MATCH, IF_NONE_MATCH};
+use http::header::IF_MATCH;
+use http::header::IF_NONE_MATCH;
 use http::Request;
 use http::Response;
 use http::StatusCode;
-use serde::{Deserialize, Serialize};
+use serde::Deserialize;
+use serde::Serialize;
 use serde_json::json;
 use tokio::sync::Mutex;
 
@@ -706,7 +710,8 @@ pub struct IcloudCreateFolder {
 
 #[cfg(test)]
 mod tests {
-    use super::{IcloudRoot, IcloudWebservicesResponse};
+    use super::IcloudRoot;
+    use super::IcloudWebservicesResponse;
 
     #[test]
     fn test_parse_icloud_drive_root_json() {
diff --git a/core/src/services/koofr/core.rs b/core/src/services/koofr/core.rs
index d998ba750f..441c3ffb01 100644
--- a/core/src/services/koofr/core.rs
+++ b/core/src/services/koofr/core.rs
@@ -31,11 +31,10 @@ use serde_json::json;
 use tokio::sync::Mutex;
 use tokio::sync::OnceCell;
 
+use super::error::parse_error;
 use crate::raw::*;
 use crate::*;
 
-use super::error::parse_error;
-
 #[derive(Clone)]
 pub struct KoofrCore {
     /// The root of this core.
diff --git a/core/src/services/mod.rs b/core/src/services/mod.rs
index c95556dbc3..e7ffb00844 100644
--- a/core/src/services/mod.rs
+++ b/core/src/services/mod.rs
@@ -235,7 +235,6 @@ mod dropbox;
 pub use dropbox::Dropbox;
 #[cfg(feature = "services-dropbox")]
 pub use dropbox::DropboxConfig;
-
 #[cfg(feature = "services-webhdfs")]
 pub use webhdfs::Webhdfs;
 
diff --git a/core/src/services/sftp/lister.rs b/core/src/services/sftp/lister.rs
index 6192fa3fcc..f7fe5aac9f 100644
--- a/core/src/services/sftp/lister.rs
+++ b/core/src/services/sftp/lister.rs
@@ -25,11 +25,10 @@ use futures::StreamExt;
 use openssh_sftp_client::fs::DirEntry;
 use openssh_sftp_client::fs::ReadDir;
 
+use super::error::parse_sftp_error;
 use crate::raw::oio;
 use crate::Result;
 
-use super::error::parse_sftp_error;
-
 pub struct SftpLister {
     dir: Pin<Box<ReadDir>>,
     prefix: String,
diff --git a/core/src/services/yandex_disk/backend.rs 
b/core/src/services/yandex_disk/backend.rs
index d22032bc91..d581e8fd4d 100644
--- a/core/src/services/yandex_disk/backend.rs
+++ b/core/src/services/yandex_disk/backend.rs
@@ -15,15 +15,16 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use std::collections::HashMap;
+use std::fmt::Debug;
+use std::fmt::Formatter;
+use std::sync::Arc;
+
 use async_trait::async_trait;
 use http::Request;
 use http::StatusCode;
 use log::debug;
 use serde::Deserialize;
-use std::collections::HashMap;
-use std::fmt::Debug;
-use std::fmt::Formatter;
-use std::sync::Arc;
 
 use super::core::*;
 use super::error::parse_error;
diff --git a/core/src/services/yandex_disk/core.rs 
b/core/src/services/yandex_disk/core.rs
index d3852ea79e..f206a52c0e 100644
--- a/core/src/services/yandex_disk/core.rs
+++ b/core/src/services/yandex_disk/core.rs
@@ -15,16 +15,20 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use std::fmt::{Debug, Formatter};
-
-use http::{header, request, Request, Response, StatusCode};
+use std::fmt::Debug;
+use std::fmt::Formatter;
+
+use http::header;
+use http::request;
+use http::Request;
+use http::Response;
+use http::StatusCode;
 use serde::Deserialize;
 
+use super::error::parse_error;
 use crate::raw::*;
 use crate::*;
 
-use super::error::parse_error;
-
 #[derive(Clone)]
 pub struct YandexDiskCore {
     /// The root of this core.
diff --git a/core/src/services/yandex_disk/writer.rs 
b/core/src/services/yandex_disk/writer.rs
index b25d770098..33633593e8 100644
--- a/core/src/services/yandex_disk/writer.rs
+++ b/core/src/services/yandex_disk/writer.rs
@@ -18,13 +18,13 @@
 use std::sync::Arc;
 
 use async_trait::async_trait;
-use http::{Request, StatusCode};
-
-use crate::raw::*;
-use crate::*;
+use http::Request;
+use http::StatusCode;
 
 use super::core::YandexDiskCore;
 use super::error::parse_error;
+use crate::raw::*;
+use crate::*;
 
 pub type YandexDiskWriters = oio::OneShotWriter<YandexDiskWriter>;
 
diff --git a/core/src/types/operator/blocking_operator.rs 
b/core/src/types/operator/blocking_operator.rs
index babacdf471..9cb46efa30 100644
--- a/core/src/types/operator/blocking_operator.rs
+++ b/core/src/types/operator/blocking_operator.rs
@@ -58,7 +58,6 @@ use crate::*;
 ///
 /// Some services like s3, gcs doesn't have native blocking supports, we can 
use [`layers::BlockingLayer`]
 /// to wrap the async operator to make it blocking.
-///
 #[cfg_attr(feature = "layers-blocking", doc = "```rust")]
 #[cfg_attr(not(feature = "layers-blocking"), doc = "```ignore")]
 /// # use anyhow::Result;
diff --git a/core/src/types/operator/operator.rs 
b/core/src/types/operator/operator.rs
index 8c50d7db4c..f3039c0bf9 100644
--- a/core/src/types/operator/operator.rs
+++ b/core/src/types/operator/operator.rs
@@ -37,12 +37,13 @@ use crate::*;
 /// Developer should manipulate the data from storage service through Operator 
only by right.
 ///
 /// We will usually do some general checks and data transformations in this 
layer,
-/// like normalizing path from input, checking whether the path refers to one 
file or one directory, and so on.
-/// Read [`concepts`][docs::concepts] for more about [`Operator`].
+/// like normalizing path from input, checking whether the path refers to one 
file or one directory,
+/// and so on.
+/// Read [`Operator::concepts`][docs::concepts] for more about 
[`Operator::Operator`].
 ///
 /// # Examples
 ///
-/// Read more backend init examples in [`services`]
+/// Read more backend init examples in [`Operator::services`]
 ///
 /// ```
 /// # use anyhow::Result;
@@ -133,7 +134,7 @@ impl Operator {
     }
 }
 
-/// Operator async API.
+/// # Operator async API.
 impl Operator {
     /// Check if this operator can work correctly.
     ///
@@ -163,35 +164,16 @@ impl Operator {
     ///
     /// # Notes
     ///
-    /// For fetch metadata of entries returned by [`Lister`], it's better to 
use [`list_with`] and
-    /// [`lister_with`] with `metakey` query like `Metakey::ContentLength | 
Metakey::LastModified`
-    /// so that we can avoid extra stat requests.
+    /// ## Extra Options
     ///
-    /// # Behavior
-    ///
-    /// ## Services that support `create_dir`
-    ///
-    /// `test` and `test/` may vary in some services such as S3. However, on a 
local file system,
-    /// they're identical. Therefore, the behavior of `stat("test")` and 
`stat("test/")` might differ
-    /// in certain edge cases. Always use `stat("test/")` when you need to 
access a directory if possible.
+    /// [`Operator::stat`] is a wrapper of [`Operator::stat_with`] without any 
options. To use extra
+    /// options like `if_match` and `if_none_match`, please use 
[`Operator::stat_with`] instead.
     ///
-    /// Here are the behavior list:
-    ///
-    /// | Case                   | Path            | Result                    
                 |
-    /// 
|------------------------|-----------------|--------------------------------------------|
-    /// | stat existing dir      | `abc/`          | Metadata with dir mode    
                 |
-    /// | stat existing file     | `abc/def_file`  | Metadata with file mode   
                 |
-    /// | stat dir without `/`   | `abc/def_dir`   | Error `NotFound` or 
metadata with dir mode |
-    /// | stat file with `/`     | `abc/def_file/` | Error `NotFound`          
                 |
-    /// | stat not existing path | `xyz`           | Error `NotFound`          
                 |
-    ///
-    /// Refer to [RFC: List Prefix][crate::docs::rfcs::rfc_3243_list_prefix] 
for more details.
+    /// ## Reuse Metadata
     ///
-    /// ## Services that not support `create_dir`
-    ///
-    /// For services that not support `create_dir`, `stat("test/")` will 
return `NotFound` even
-    /// when `test/abc` exists since the service won't have the concept of 
dir. There is nothing
-    /// we can do about this.
+    /// For fetch metadata of entries returned by [`Operator::Lister`], it's 
better to use
+    /// [`Operator::list_with`] and [`Operator::lister_with`] with `metakey` 
query like
+    /// `Metakey::ContentLength | Metakey::LastModified` so that we can avoid 
extra stat requests.
     ///
     /// # Examples
     ///
@@ -221,35 +203,51 @@ impl Operator {
     ///
     /// # Notes
     ///
-    /// For fetch metadata of entries returned by [`Lister`], it's better to 
use [`list_with`] and
-    /// [`lister_with`] with `metakey` query like `Metakey::ContentLength | 
Metakey::LastModified`
-    /// so that we can avoid extra requests.
+    /// ## Reuse Metadata
     ///
-    /// # Behavior
+    /// For fetch metadata of entries returned by [`Operator::Lister`], it's 
better to use
+    /// [`Operator::list_with`] and [`Operator::lister_with`] with `metakey` 
query like
+    /// `Metakey::ContentLength | Metakey::LastModified` so that we can avoid 
extra requests.
     ///
-    /// ## Services that support `create_dir`
+    /// # Options
     ///
-    /// `test` and `test/` may vary in some services such as S3. However, on a 
local file system,
-    /// they're identical. Therefore, the behavior of `stat("test")` and 
`stat("test/")` might differ
-    /// in certain edge cases. Always use `stat("test/")` when you need to 
access a directory if possible.
+    /// ## `if_match`
     ///
-    /// Here are the behavior list:
+    /// Set `if_match` for this `stat` request.
     ///
-    /// | Case                   | Path            | Result                    
                 |
-    /// 
|------------------------|-----------------|--------------------------------------------|
-    /// | stat existing dir      | `abc/`          | Metadata with dir mode    
                 |
-    /// | stat existing file     | `abc/def_file`  | Metadata with file mode   
                 |
-    /// | stat dir without `/`   | `abc/def_dir`   | Error `NotFound` or 
metadata with dir mode |
-    /// | stat file with `/`     | `abc/def_file/` | Error `NotFound`          
                 |
-    /// | stat not existing path | `xyz`           | Error `NotFound`          
                 |
+    /// This feature can be used to check if the file's `ETag` matches the 
given `ETag`.
     ///
-    /// Refer to [RFC: List Prefix][crate::docs::rfcs::rfc_3243_list_prefix] 
for more details.
+    /// If file exists and it's etag doesn't match, an error with kind 
[`ErrorKind::ConditionNotMatch`]
+    /// will be returned.
     ///
-    /// ## Services that not support `create_dir`
+    /// ```no_run
+    /// # use opendal::Result;
+    /// use opendal::Operator;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator, etag: &str) -> Result<()> {
+    /// let mut metadata = op.stat_with("path/to/file").if_match(etag).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
     ///
-    /// For services that not support `create_dir`, `stat("test/")` will 
return `NotFound` even
-    /// when `test/abc` exists since the service won't have the concept of 
dir. There is nothing
-    /// we can do about this.
+    /// ## `if_none_match`
+    ///
+    /// Set `if_none_match` for this `stat` request.
+    ///
+    /// This feature can be used to check if the file's `ETag` doesn't match 
the given `ETag`.
+    ///
+    /// If file exists and it's etag match, an error with kind 
[`ErrorKind::ConditionNotMatch`]
+    /// will be returned.
+    ///
+    /// ```no_run
+    /// # use opendal::Result;
+    /// use opendal::Operator;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator, etag: &str) -> Result<()> {
+    /// let mut metadata = 
op.stat_with("path/to/file").if_none_match(etag).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
     ///
     /// # Examples
     ///
@@ -281,6 +279,34 @@ impl Operator {
     /// # Ok(())
     /// # }
     /// ```
+    ///
+    /// ---
+    ///
+    /// # Behavior
+    ///
+    /// ## Services that support `create_dir`
+    ///
+    /// `test` and `test/` may vary in some services such as S3. However, on a 
local file system,
+    /// they're identical. Therefore, the behavior of `stat("test")` and 
`stat("test/")` might differ
+    /// in certain edge cases. Always use `stat("test/")` when you need to 
access a directory if possible.
+    ///
+    /// Here are the behavior list:
+    ///
+    /// | Case                   | Path            | Result                    
                 |
+    /// 
|------------------------|-----------------|--------------------------------------------|
+    /// | stat existing dir      | `abc/`          | Metadata with dir mode    
                 |
+    /// | stat existing file     | `abc/def_file`  | Metadata with file mode   
                 |
+    /// | stat dir without `/`   | `abc/def_dir`   | Error `NotFound` or 
metadata with dir mode |
+    /// | stat file with `/`     | `abc/def_file/` | Error `NotFound`          
                 |
+    /// | stat not existing path | `xyz`           | Error `NotFound`          
                 |
+    ///
+    /// Refer to [RFC: List Prefix][crate::docs::rfcs::rfc_3243_list_prefix] 
for more details.
+    ///
+    /// ## Services that not support `create_dir`
+    ///
+    /// For services that not support `create_dir`, `stat("test/")` will 
return `NotFound` even
+    /// when `test/abc` exists since the service won't have the concept of 
dir. There is nothing
+    /// we can do about this.
     pub fn stat_with(&self, path: &str) -> FutureStat<impl Future<Output = 
Result<Metadata>>> {
         let path = normalize_path(path);
 
@@ -367,6 +393,15 @@ impl Operator {
 
     /// Read the whole path into a bytes.
     ///
+    /// # Notes
+    ///
+    /// ## Extra Options
+    ///
+    /// [`Operator::read`] is a wrapper of [`Operator::read_with`] without any 
options. To use
+    /// extra options like `range` and `if_match`, please use 
[`Operator::read_with`] instead.
+    ///
+    /// ## Streaming Read
+    ///
     /// This function will allocate a new bytes internally. For more precise 
memory control or
     /// reading data lazily, please use [`Operator::reader`]
     ///
@@ -391,8 +426,79 @@ impl Operator {
     /// This function will allocate a new bytes internally. For more precise 
memory control or
     /// reading data lazily, please use [`Operator::reader`]
     ///
+    /// # Notes
+    ///
+    /// ## Streaming Read
+    ///
+    /// This function will allocate a new bytes internally. For more precise 
memory control or
+    /// reading data lazily, please use [`Operator::reader`]
+    ///
+    /// # Options
+    ///
+    /// ## `range`
+    ///
+    /// Set `range` for this `read` request.
+    ///
+    /// If we have a file with size `n`.
+    ///
+    /// - `..` means read bytes in range `[0, n)` of file.
+    /// - `0..1024` means read bytes in range `[0, 1024)` of file
+    /// - `1024..` means read bytes in range `[1024, n)` of file
+    /// - `..1024` means read bytes in range `(n - 1024, n)` of file
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::TryStreamExt;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let bs = op.read_with("path/to/file").range(0..1024).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `if_match`
+    ///
+    /// Set `if_match` for this `read` request.
+    ///
+    /// This feature can be used to check if the file's `ETag` matches the 
given `ETag`.
+    ///
+    /// If file exists and it's etag doesn't match, an error with kind 
[`ErrorKind::ConditionNotMatch`]
+    /// will be returned.
+    ///
+    /// ```no_run
+    /// # use opendal::Result;
+    /// use opendal::Operator;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator, etag: &str) -> Result<()> {
+    /// let mut metadata = op.read_with("path/to/file").if_match(etag).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `if_none_match`
+    ///
+    /// Set `if_none_match` for this `read` request.
+    ///
+    /// This feature can be used to check if the file's `ETag` doesn't match 
the given `ETag`.
+    ///
+    /// If file exists and it's etag match, an error with kind 
[`ErrorKind::ConditionNotMatch`]
+    /// will be returned.
+    ///
+    /// ```no_run
+    /// # use opendal::Result;
+    /// use opendal::Operator;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator, etag: &str) -> Result<()> {
+    /// let mut metadata = 
op.read_with("path/to/file").if_none_match(etag).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
     /// # Examples
     ///
+    /// Read the whole path into a bytes.
+    ///
     /// ```
     /// # use std::io::Result;
     /// # use opendal::Operator;
@@ -445,6 +551,13 @@ impl Operator {
 
     /// Create a new reader which can read the whole path.
     ///
+    /// # Notes
+    ///
+    /// ## Extra Options
+    ///
+    /// [`Operator::reader`] is a wrapper of [`Operator::reader_with`] without 
any options. To use
+    /// extra options like `range` and `if_match`, please use 
[`Operator::reader_with`] instead.
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -464,6 +577,99 @@ impl Operator {
 
     /// Create a new reader with extra options
     ///
+    /// # Notes
+    ///
+    /// ## Extra Options
+    ///
+    /// [`Operator::reader`] is a wrapper of [`Operator::reader_with`] without 
any options. To use
+    /// extra options like `range` and `if_match`, please use 
[`Operator::reader_with`] instead.
+    ///
+    /// # Options
+    ///
+    /// ## `range`
+    ///
+    /// Set `range` for this `read` request.
+    ///
+    /// If we have a file with size `n`.
+    ///
+    /// - `..` means read bytes in range `[0, n)` of file.
+    /// - `0..1024` means read bytes in range `[0, 1024)` of file
+    /// - `1024..` means read bytes in range `[1024, n)` of file
+    /// - `..1024` means read bytes in range `(n - 1024, n)` of file
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::TryStreamExt;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let bs = op.reader_with("path/to/file").range(0..1024).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `buffer`
+    ///
+    /// Set `buffer` for the reader.
+    ///
+    /// OpenDAL by default to read file without buffer. This is not efficient 
for cases like `seek`
+    /// after read or reading file with small chunks. To improve performance, 
we can set a buffer.
+    ///
+    /// The following example will create a reader with 4 MiB buffer 
internally. All seek operations
+    /// happened in buffered data will be zero cost.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::TryStreamExt;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let bs = op
+    ///     .reader_with("path/to/file")
+    ///     .buffer(4 * 1024 * 1024)
+    ///     .await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `if_match`
+    ///
+    /// Set `if_match` for this `read` request.
+    ///
+    /// This feature can be used to check if the file's `ETag` matches the 
given `ETag`.
+    ///
+    /// If file exists and it's etag doesn't match, an error with kind 
[`ErrorKind::ConditionNotMatch`]
+    /// will be returned.
+    ///
+    /// ```no_run
+    /// # use opendal::Result;
+    /// use opendal::Operator;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator, etag: &str) -> Result<()> {
+    /// let mut metadata = 
op.reader_with("path/to/file").if_match(etag).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `if_none_match`
+    ///
+    /// Set `if_none_match` for this `read` request.
+    ///
+    /// This feature can be used to check if the file's `ETag` doesn't match 
the given `ETag`.
+    ///
+    /// If file exists and it's etag match, an error with kind 
[`ErrorKind::ConditionNotMatch`]
+    /// will be returned.
+    ///
+    /// ```no_run
+    /// # use opendal::Result;
+    /// use opendal::Operator;
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator, etag: &str) -> Result<()> {
+    /// let mut metadata = 
op.reader_with("path/to/file").if_none_match(etag).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -473,7 +679,7 @@ impl Operator {
     /// # use opendal::Scheme;
     /// # #[tokio::main]
     /// # async fn test(op: Operator) -> Result<()> {
-    /// let r = op.reader_with("path/to/file").range((0..10)).await?;
+    /// let r = op.reader_with("path/to/file").range(0..10).await?;
     /// # Ok(())
     /// # }
     /// ```
@@ -503,7 +709,16 @@ impl Operator {
     ///
     /// # Notes
     ///
-    /// - Write will make sure all bytes has been written, or an error will be 
returned.
+    /// ## Extra Options
+    ///
+    /// [`Operator::write`] is a wrapper of [`Operator::write_with`] without 
any options. To use
+    /// extra options like `content_type` and `cache_control`, please use 
[`Operator::write_with`]
+    /// instead.
+    ///
+    /// ## Streaming Write
+    ///
+    /// This function will write all bytes at once. For more precise memory 
control or
+    /// writing data lazily, please use [`Operator::writer`].
     ///
     /// # Examples
     ///
@@ -644,7 +859,13 @@ impl Operator {
 
     /// Write multiple bytes into path.
     ///
-    /// Refer to [`Writer`] for more details.
+    /// # Notes
+    ///
+    /// ## Extra Options
+    ///
+    /// [`Operator::write`] is a wrapper of [`Operator::write_with`] without 
any options. To use
+    /// extra options like `content_type` and `cache_control`, please use 
[`Operator::write_with`]
+    /// instead.
     ///
     /// # Examples
     ///
@@ -670,7 +891,176 @@ impl Operator {
 
     /// Write multiple bytes into path with extra options.
     ///
-    /// Refer to [`Writer`] for more details.
+    /// # Options
+    ///
+    /// ## `append`
+    ///
+    /// Set `append` for this `write` request.
+    ///
+    /// `write` by default to overwrite existing files. To append to the end 
of file instead,
+    /// please set `append` to true.
+    ///
+    /// The following example will append data to existing file instead.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::StreamExt;
+    /// # use futures::SinkExt;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let mut w = op.writer_with("path/to/file").append(true).await?;
+    /// w.write(vec![0; 4096]).await?;
+    /// w.write(vec![1; 4096]).await?;
+    /// w.close().await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `buffer`
+    ///
+    /// Set `buffer` for the writer.
+    ///
+    /// OpenDAL by default to write file without buffer. This is not efficient 
for cases when users
+    /// write small chunks of data. Some storage services like `s3` could even 
return hard errors
+    /// like `EntityTooSmall`. To improve performance, we can set a buffer.
+    ///
+    /// Besides, cloud storage services will cost more money if we write data 
in small chunks. Set
+    /// a good buffer size might reduce the API calls and save money.
+    ///
+    /// The following example will set the writer buffer to 8MiB. Only one API 
call will be sent at
+    /// `close` instead.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::StreamExt;
+    /// # use futures::SinkExt;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let mut w = op
+    ///     .writer_with("path/to/file")
+    ///     .buffer(8 * 1024 * 1024)
+    ///     .await?;
+    /// w.write(vec![0; 4096]).await?;
+    /// w.write(vec![1; 4096]).await?;
+    /// w.close().await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `concurrent`
+    ///
+    /// Set `concurrent` for the writer.
+    ///
+    /// OpenDAL by default to write file without concurrent. This is not 
efficient for cases when users
+    /// write large chunks of data. By setting `concurrent`, opendal will 
writing files concurrently
+    /// on support storage services.
+    ///
+    /// The following example will set the writer concurrent to 8.
+    ///
+    /// - The first write will start and return immediately.
+    /// - The second write will start and return immediately.
+    /// - The close will make sure all writes are done in order and return 
result.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::StreamExt;
+    /// # use futures::SinkExt;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let mut w = op.writer_with("path/to/file").concurrent(8).await?;
+    /// w.write(vec![0; 4096]).await?; // Start the first write
+    /// w.write(vec![1; 4096]).await?; // Second write will be concurrent 
without wait
+    /// w.close().await?; // Close will make sure all writes are done and 
success
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `cache_control`
+    ///
+    /// Set the `cache_control` for this `write` request.
+    ///
+    /// Some storage services support setting `cache_control` as system 
metadata.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::StreamExt;
+    /// # use futures::SinkExt;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let mut w = op
+    ///     .writer_with("path/to/file")
+    ///     .cache_control("max-age=604800")
+    ///     .await?;
+    /// w.write(vec![0; 4096]).await?;
+    /// w.write(vec![1; 4096]).await?;
+    /// w.close().await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `content_type`
+    ///
+    /// Set the `content_type` for this `write` request.
+    ///
+    /// Some storage services support setting `content_type` as system 
metadata.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::StreamExt;
+    /// # use futures::SinkExt;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let mut w = op
+    ///     .writer_with("path/to/file")
+    ///     .content_type("text/plain")
+    ///     .await?;
+    /// w.write(vec![0; 4096]).await?;
+    /// w.write(vec![1; 4096]).await?;
+    /// w.close().await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `content_disposition`
+    ///
+    /// Set the `content_disposition` for this `write` request.
+    ///
+    /// Some storage services support setting `content_disposition` as system 
metadata.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// # use futures::StreamExt;
+    /// # use futures::SinkExt;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let mut w = op
+    ///     .writer_with("path/to/file")
+    ///     .content_disposition("attachment; filename=\"filename.jpg\"")
+    ///     .await?;
+    /// w.write(vec![0; 4096]).await?;
+    /// w.write(vec![1; 4096]).await?;
+    /// w.close().await?;
+    /// # Ok(())
+    /// # }
+    /// ```
     ///
     /// # Examples
     ///
@@ -719,11 +1109,104 @@ impl Operator {
     ///
     /// # Notes
     ///
-    /// - Write will make sure all bytes has been written, or an error will be 
returned.
+    /// ## Streaming Write
+    ///
+    /// This function will write all bytes at once. For more precise memory 
control or
+    /// writing data lazily, please use [`Operator::writer_with`].
+    ///
+    /// # Options
+    ///
+    /// ## `append`
+    ///
+    /// Set `append` for this `write` request.
+    ///
+    /// `write` by default to overwrite existing files. To append to the end 
of file instead,
+    /// please set `append` to true.
+    ///
+    /// The following example will append data to existing file instead.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let bs = b"hello, world!".to_vec();
+    /// let _ = op.write_with("path/to/file", bs).append(true).await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `cache_control`
+    ///
+    /// Set the `cache_control` for this `write` request.
+    ///
+    /// Some storage services support setting `cache_control` as system 
metadata.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let bs = b"hello, world!".to_vec();
+    /// let _ = op
+    ///     .write_with("path/to/file", bs)
+    ///     .cache_control("max-age=604800")
+    ///     .await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `content_type`
+    ///
+    /// Set the `content_type` for this `write` request.
+    ///
+    /// Some storage services support setting `content_type` as system 
metadata.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let bs = b"hello, world!".to_vec();
+    /// let _ = op
+    ///     .write_with("path/to/file", bs)
+    ///     .content_type("text/plain")
+    ///     .await?;
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// ## `content_disposition`
+    ///
+    /// Set the `content_disposition` for this `write` request.
+    ///
+    /// Some storage services support setting `content_disposition` as system 
metadata.
+    ///
+    /// ```
+    /// # use std::io::Result;
+    /// # use opendal::Operator;
+    /// use bytes::Bytes;
+    ///
+    /// # #[tokio::main]
+    /// # async fn test(op: Operator) -> Result<()> {
+    /// let bs = b"hello, world!".to_vec();
+    /// let _ = op
+    ///     .write_with("path/to/file", bs)
+    ///     .content_disposition("attachment; filename=\"filename.jpg\"")
+    ///     .await?;
+    /// # Ok(())
+    /// # }
+    /// ```
     ///
     /// # Examples
     ///
-    /// ```no_run
+    /// ```
     /// # use std::io::Result;
     /// # use opendal::Operator;
     /// use bytes::Bytes;
@@ -985,13 +1468,13 @@ impl Operator {
     ///
     /// # Notes
     ///
-    /// ## Recursively list
+    /// ## Recursively List
     ///
     /// This function only read the children of the given directory. To read
     /// all entries recursively, use 
`Operator::list_with("path").recursive(true)`
     /// instead.
     ///
-    /// ## Streaming list
+    /// ## Streaming List
     ///
     /// This function will read all entries in the given directory. It could
     /// take very long time and consume a lot of memory if the directory
@@ -1239,8 +1722,8 @@ impl Operator {
 
     /// List entries that starts with given `path` in parent dir.
     ///
-    /// This function will create a new [`Lister`] to list entries. Users can 
stop listing via
-    /// dropping this [`Lister`].
+    /// This function will create a new [`Operator::Lister`] to list entries. 
Users can stop
+    /// listing via dropping this [`Operator::Lister`].
     ///
     /// # Notes
     ///
@@ -1287,8 +1770,8 @@ impl Operator {
 
     /// List entries that starts with given `path` in parent dir with options.
     ///
-    /// This function will create a new [`Lister`] to list entries. Users can 
stop listing via
-    /// dropping this [`Lister`].
+    /// This function will create a new [`Operator::Lister`] to list entries. 
Users can stop listing via
+    /// dropping this [`Operator::Lister`].
     ///
     /// # Options
     ///
diff --git a/core/src/types/operator/operator_futures.rs 
b/core/src/types/operator/operator_futures.rs
index 15ce16e0c6..2822db84cc 100644
--- a/core/src/types/operator/operator_futures.rs
+++ b/core/src/types/operator/operator_futures.rs
@@ -213,6 +213,21 @@ impl<F> FutureRead<F> {
         self.map(|args| args.with_range(range.into()))
     }
 
+    /// Set the buffer capability to enable buffer for reader.
+    pub fn buffer(self, v: usize) -> Self {
+        self.map(|args| args.with_buffer(v))
+    }
+
+    /// Set the If-Match for this operation.
+    pub fn if_match(self, v: &str) -> Self {
+        self.map(|args| args.with_if_match(v))
+    }
+
+    /// Set the If-None-Match for this operation.
+    pub fn if_none_match(self, v: &str) -> Self {
+        self.map(|args| args.with_if_none_match(v))
+    }
+
     /// Sets the content-disposition header that should be send back by the 
remote read operation.
     pub fn override_content_disposition(self, v: &str) -> Self {
         self.map(|args| args.with_override_content_disposition(v))
@@ -228,25 +243,10 @@ impl<F> FutureRead<F> {
         self.map(|args| args.with_override_content_type(v))
     }
 
-    /// Set the If-Match for this operation.
-    pub fn if_match(self, v: &str) -> Self {
-        self.map(|args| args.with_if_match(v))
-    }
-
-    /// Set the If-None-Match for this operation.
-    pub fn if_none_match(self, v: &str) -> Self {
-        self.map(|args| args.with_if_none_match(v))
-    }
-
     /// Set the version for this operation.
     pub fn version(self, v: &str) -> Self {
         self.map(|args| args.with_version(v))
     }
-
-    /// Set the buffer capability to enable buffer for reader.
-    pub fn buffer(self, v: usize) -> Self {
-        self.map(|args| args.with_buffer(v))
-    }
 }
 
 /// Future that generated by [`Operator::write_with`].
@@ -278,6 +278,16 @@ impl<F> FutureWrite<F> {
         self.map(|(args, bs)| (args.with_buffer(v), bs))
     }
 
+    /// Set the maximum concurrent write task amount.
+    pub fn concurrent(self, v: usize) -> Self {
+        self.map(|(args, bs)| (args.with_buffer(v), bs))
+    }
+
+    /// Set the content type of option
+    pub fn cache_control(self, v: &str) -> Self {
+        self.map(|(args, bs)| (args.with_cache_control(v), bs))
+    }
+
     /// Set the content type of option
     pub fn content_type(self, v: &str) -> Self {
         self.map(|(args, bs)| (args.with_content_type(v), bs))
@@ -287,16 +297,6 @@ impl<F> FutureWrite<F> {
     pub fn content_disposition(self, v: &str) -> Self {
         self.map(|(args, bs)| (args.with_content_disposition(v), bs))
     }
-
-    /// Set the content type of option
-    pub fn cache_control(self, v: &str) -> Self {
-        self.map(|(args, bs)| (args.with_cache_control(v), bs))
-    }
-
-    /// Set the maximum concurrent write task amount.
-    pub fn concurrent(self, v: usize) -> Self {
-        self.map(|(args, bs)| (args.with_buffer(v), bs))
-    }
 }
 
 /// Future that generated by [`Operator::writer_with`].
@@ -335,6 +335,16 @@ impl<F> FutureWriter<F> {
         self.map(|args| args.with_buffer(v))
     }
 
+    /// Set the maximum concurrent write task amount.
+    pub fn concurrent(self, v: usize) -> Self {
+        self.map(|args| args.with_concurrent(v))
+    }
+
+    /// Set the content type of option
+    pub fn cache_control(self, v: &str) -> Self {
+        self.map(|args| args.with_cache_control(v))
+    }
+
     /// Set the content type of option
     pub fn content_type(self, v: &str) -> Self {
         self.map(|args| args.with_content_type(v))
@@ -344,16 +354,6 @@ impl<F> FutureWriter<F> {
     pub fn content_disposition(self, v: &str) -> Self {
         self.map(|args| args.with_content_disposition(v))
     }
-
-    /// Set the content type of option
-    pub fn cache_control(self, v: &str) -> Self {
-        self.map(|args| args.with_cache_control(v))
-    }
-
-    /// Set the maximum concurrent write task amount.
-    pub fn concurrent(self, v: usize) -> Self {
-        self.map(|args| args.with_concurrent(v))
-    }
 }
 
 /// Future that generated by [`Operator::delete_with`].

Reply via email to