`
-* `actix_web::Method`, `actix_web::StatusCode`, `actix_web::Version`
+- `actix_web::Method`, `actix_web::StatusCode`, `actix_web::Version`
moved to `actix_web::http` module
-* `actix_web::header` moved to `actix_web::http::header`
+- `actix_web::header` moved to `actix_web::http::header`
-* `NormalizePath` moved to `actix_web::http` module
+- `NormalizePath` moved to `actix_web::http` module
-* `HttpServer` moved to `actix_web::server`, added new `actix_web::server::new()` function,
+- `HttpServer` moved to `actix_web::server`, added new `actix_web::server::new()` function,
shortcut for `actix_web::server::HttpServer::new()`
-* `DefaultHeaders` middleware does not use separate builder, all builder methods moved to type itself
+- `DefaultHeaders` middleware does not use separate builder, all builder methods moved to type itself
-* `StaticFiles::new()`'s show_index parameter removed, use `show_files_listing()` method instead.
+- `StaticFiles::new()`'s show_index parameter removed, use `show_files_listing()` method instead.
-* `CookieSessionBackendBuilder` removed, all methods moved to `CookieSessionBackend` type
+- `CookieSessionBackendBuilder` removed, all methods moved to `CookieSessionBackend` type
-* `actix_web::httpcodes` module is deprecated, `HttpResponse::Ok()`, `HttpResponse::Found()` and other `HttpResponse::XXX()`
+- `actix_web::httpcodes` module is deprecated, `HttpResponse::Ok()`, `HttpResponse::Found()` and other `HttpResponse::XXX()`
functions should be used instead
-* `ClientRequestBuilder::body()` returns `Result<_, actix_web::Error>`
+- `ClientRequestBuilder::body()` returns `Result<_, actix_web::Error>`
instead of `Result<_, http::Error>`
-* `Application` renamed to a `App`
+- `Application` renamed to a `App`
-* `actix_web::Reply`, `actix_web::Resource` moved to `actix_web::dev`
+- `actix_web::Reply`, `actix_web::Resource` moved to `actix_web::dev`
diff --git a/README.md b/README.md
index cc7c4cd52..5c5a55743 100644
--- a/README.md
+++ b/README.md
@@ -6,13 +6,13 @@
[](https://crates.io/crates/actix-web)
-[](https://docs.rs/actix-web/4.0.0-beta.2)
-[](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)
+[](https://docs.rs/actix-web/4.0.0-beta.19)
+

-[](https://deps.rs/crate/actix-web/4.0.0-beta.2)
+[](https://deps.rs/crate/actix-web/4.0.0-beta.19)
-[](https://github.com/actix/actix-web/actions)
-[](https://codecov.io/gh/actix/actix-web)
+[](https://github.com/actix/actix-web/actions/workflows/ci.yml)
+[](https://codecov.io/gh/actix/actix-web)

[](https://discord.gg/NWpN5mmg3x)
@@ -21,25 +21,25 @@
## Features
-* Supports *HTTP/1.x* and *HTTP/2*
-* Streaming and pipelining
-* Keep-alive and slow requests handling
-* Client/server [WebSockets](https://actix.rs/docs/websockets/) support
-* Transparent content compression/decompression (br, gzip, deflate)
-* Powerful [request routing](https://actix.rs/docs/url-dispatch/)
-* Multipart streams
-* Static assets
-* SSL support using OpenSSL or Rustls
-* Middlewares ([Logger, Session, CORS, etc](https://actix.rs/docs/middleware/))
-* Includes an async [HTTP client](https://actix.rs/actix-web/actix_web/client/index.html)
-* Runs on stable Rust 1.46+
+- Supports *HTTP/1.x* and *HTTP/2*
+- Streaming and pipelining
+- Keep-alive and slow requests handling
+- Client/server [WebSockets](https://actix.rs/docs/websockets/) support
+- Transparent content compression/decompression (br, gzip, deflate, zstd)
+- Powerful [request routing](https://actix.rs/docs/url-dispatch/)
+- Multipart streams
+- Static assets
+- SSL support using OpenSSL or Rustls
+- Middlewares ([Logger, Session, CORS, etc](https://actix.rs/docs/middleware/))
+- Includes an async [HTTP client](https://docs.rs/awc/)
+- Runs on stable Rust 1.54+
## Documentation
-* [Website & User Guide](https://actix.rs)
-* [Examples Repository](https://github.com/actix/examples)
-* [API Documentation](https://docs.rs/actix-web)
-* [API Documentation (master branch)](https://actix.rs/actix-web/actix_web)
+- [Website & User Guide](https://actix.rs)
+- [Examples Repository](https://github.com/actix/examples)
+- [API Documentation](https://docs.rs/actix-web)
+- [API Documentation (master branch)](https://actix.rs/actix-web/actix_web)
## Example
@@ -71,18 +71,18 @@ async fn main() -> std::io::Result<()> {
### More examples
-* [Basic Setup](https://github.com/actix/examples/tree/master/basics/)
-* [Application State](https://github.com/actix/examples/tree/master/state/)
-* [JSON Handling](https://github.com/actix/examples/tree/master/json/)
-* [Multipart Streams](https://github.com/actix/examples/tree/master/multipart/)
-* [Diesel Integration](https://github.com/actix/examples/tree/master/diesel/)
-* [r2d2 Integration](https://github.com/actix/examples/tree/master/r2d2/)
-* [Simple WebSocket](https://github.com/actix/examples/tree/master/websocket/)
-* [Tera Templates](https://github.com/actix/examples/tree/master/template_tera/)
-* [Askama Templates](https://github.com/actix/examples/tree/master/template_askama/)
-* [HTTPS using Rustls](https://github.com/actix/examples/tree/master/rustls/)
-* [HTTPS using OpenSSL](https://github.com/actix/examples/tree/master/openssl/)
-* [WebSocket Chat](https://github.com/actix/examples/tree/master/websocket-chat/)
+- [Basic Setup](https://github.com/actix/examples/tree/master/basics/basics/)
+- [Application State](https://github.com/actix/examples/tree/master/basics/state/)
+- [JSON Handling](https://github.com/actix/examples/tree/master/json/json/)
+- [Multipart Streams](https://github.com/actix/examples/tree/master/forms/multipart/)
+- [Diesel Integration](https://github.com/actix/examples/tree/master/database_interactions/diesel/)
+- [r2d2 Integration](https://github.com/actix/examples/tree/master/database_interactions/r2d2/)
+- [Simple WebSocket](https://github.com/actix/examples/tree/master/websockets/websocket/)
+- [Tera Templates](https://github.com/actix/examples/tree/master/template_engines/tera/)
+- [Askama Templates](https://github.com/actix/examples/tree/master/template_engines/askama/)
+- [HTTPS using Rustls](https://github.com/actix/examples/tree/master/security/rustls/)
+- [HTTPS using OpenSSL](https://github.com/actix/examples/tree/master/security/openssl/)
+- [WebSocket Chat](https://github.com/actix/examples/tree/master/websockets/chat/)
You may consider checking out
[this directory](https://github.com/actix/examples/tree/master/) for more examples.
@@ -90,15 +90,15 @@ You may consider checking out
## Benchmarks
One of the fastest web frameworks available according to the
-[TechEmpower Framework Benchmark](https://www.techempower.com/benchmarks/#section=data-r19).
+[TechEmpower Framework Benchmark](https://www.techempower.com/benchmarks/#section=data-r20&test=composite).
## License
This project is licensed under either of
-* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
+- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
[http://www.apache.org/licenses/LICENSE-2.0])
-* MIT license ([LICENSE-MIT](LICENSE-MIT) or
+- MIT license ([LICENSE-MIT](LICENSE-MIT) or
[http://opensource.org/licenses/MIT])
at your option.
diff --git a/actix-files/CHANGES.md b/actix-files/CHANGES.md
index 6e2a241ac..e8a07d884 100644
--- a/actix-files/CHANGES.md
+++ b/actix-files/CHANGES.md
@@ -3,121 +3,191 @@
## Unreleased - 2021-xx-xx
+## 0.6.0-beta.13 - 2022-01-04
+- The `Files` service now rejects requests with URL paths that include `%2F` (decoded: `/`). [#2398]
+- The `Files` service now correctly decodes `%25` in the URL path to `%` for the file path. [#2398]
+- Minimum supported Rust version (MSRV) is now 1.54.
+
+[#2398]: https://github.com/actix/actix-web/pull/2398
+
+
+## 0.6.0-beta.12 - 2021-12-29
+- No significant changes since `0.6.0-beta.11`.
+
+
+## 0.6.0-beta.11 - 2021-12-27
+- No significant changes since `0.6.0-beta.10`.
+
+
+## 0.6.0-beta.10 - 2021-12-11
+- No significant changes since `0.6.0-beta.9`.
+
+
+## 0.6.0-beta.9 - 2021-11-22
+- Add crate feature `experimental-io-uring`, enabling async file I/O to be utilized. This feature is only available on Linux OSes with recent kernel versions. This feature is semver-exempt. [#2408]
+- Add `NamedFile::open_async`. [#2408]
+- Fix 304 Not Modified responses to omit the Content-Length header, as per the spec. [#2453]
+- The `Responder` impl for `NamedFile` now has a boxed future associated type. [#2408]
+- The `Service` impl for `NamedFileService` now has a boxed future associated type. [#2408]
+- Add `impl Clone` for `FilesService`. [#2408]
+
+[#2408]: https://github.com/actix/actix-web/pull/2408
+[#2453]: https://github.com/actix/actix-web/pull/2453
+
+
+## 0.6.0-beta.8 - 2021-10-20
+- Minimum supported Rust version (MSRV) is now 1.52.
+
+
+## 0.6.0-beta.7 - 2021-09-09
+- Minimum supported Rust version (MSRV) is now 1.51.
+
+
+## 0.6.0-beta.6 - 2021-06-26
+- Added `Files::path_filter()`. [#2274]
+- `Files::show_files_listing()` can now be used with `Files::index_file()` to show files listing as a fallback when the index file is not found. [#2228]
+
+[#2274]: https://github.com/actix/actix-web/pull/2274
+[#2228]: https://github.com/actix/actix-web/pull/2228
+
+
+## 0.6.0-beta.5 - 2021-06-17
+- `NamedFile` now implements `ServiceFactory` and `HttpServiceFactory` making it much more useful in routing. For example, it can be used directly as a default service. [#2135]
+- For symbolic links, `Content-Disposition` header no longer shows the filename of the original file. [#2156]
+- `Files::redirect_to_slash_directory()` now works as expected when used with `Files::show_files_listing()`. [#2225]
+- `application/{javascript, json, wasm}` mime type now have `inline` disposition by default. [#2257]
+
+[#2135]: https://github.com/actix/actix-web/pull/2135
+[#2156]: https://github.com/actix/actix-web/pull/2156
+[#2225]: https://github.com/actix/actix-web/pull/2225
+[#2257]: https://github.com/actix/actix-web/pull/2257
+
+
+## 0.6.0-beta.4 - 2021-04-02
+- Add support for `.guard` in `Files` to selectively filter `Files` services. [#2046]
+
+[#2046]: https://github.com/actix/actix-web/pull/2046
+
+
+## 0.6.0-beta.3 - 2021-03-09
+- No notable changes.
+
+
## 0.6.0-beta.2 - 2021-02-10
-* Fix If-Modified-Since and If-Unmodified-Since to not compare using sub-second timestamps. [#1887]
-* Replace `v_htmlescape` with `askama_escape`. [#1953]
+- Fix If-Modified-Since and If-Unmodified-Since to not compare using sub-second timestamps. [#1887]
+- Replace `v_htmlescape` with `askama_escape`. [#1953]
[#1887]: https://github.com/actix/actix-web/pull/1887
[#1953]: https://github.com/actix/actix-web/pull/1953
## 0.6.0-beta.1 - 2021-01-07
-* `HttpRange::parse` now has its own error type.
-* Update `bytes` to `1.0`. [#1813]
+- `HttpRange::parse` now has its own error type.
+- Update `bytes` to `1.0`. [#1813]
[#1813]: https://github.com/actix/actix-web/pull/1813
## 0.5.0 - 2020-12-26
-* Optionally support hidden files/directories. [#1811]
+- Optionally support hidden files/directories. [#1811]
[#1811]: https://github.com/actix/actix-web/pull/1811
## 0.4.1 - 2020-11-24
-* Clarify order of parameters in `Files::new` and improve docs.
+- Clarify order of parameters in `Files::new` and improve docs.
## 0.4.0 - 2020-10-06
-* Add `Files::prefer_utf8` option that adds UTF-8 charset on certain response types. [#1714]
+- Add `Files::prefer_utf8` option that adds UTF-8 charset on certain response types. [#1714]
[#1714]: https://github.com/actix/actix-web/pull/1714
## 0.3.0 - 2020-09-11
-* No significant changes from 0.3.0-beta.1.
+- No significant changes from 0.3.0-beta.1.
## 0.3.0-beta.1 - 2020-07-15
-* Update `v_htmlescape` to 0.10
-* Update `actix-web` and `actix-http` dependencies to beta.1
+- Update `v_htmlescape` to 0.10
+- Update `actix-web` and `actix-http` dependencies to beta.1
## 0.3.0-alpha.1 - 2020-05-23
-* Update `actix-web` and `actix-http` dependencies to alpha
-* Fix some typos in the docs
-* Bump minimum supported Rust version to 1.40
-* Support sending Content-Length when Content-Range is specified [#1384]
+- Update `actix-web` and `actix-http` dependencies to alpha
+- Fix some typos in the docs
+- Bump minimum supported Rust version to 1.40
+- Support sending Content-Length when Content-Range is specified [#1384]
[#1384]: https://github.com/actix/actix-web/pull/1384
## 0.2.1 - 2019-12-22
-* Use the same format for file URLs regardless of platforms
+- Use the same format for file URLs regardless of platforms
## 0.2.0 - 2019-12-20
-* Fix BodyEncoding trait import #1220
+- Fix BodyEncoding trait import #1220
## 0.2.0-alpha.1 - 2019-12-07
-* Migrate to `std::future`
+- Migrate to `std::future`
## 0.1.7 - 2019-11-06
-* Add an additional `filename*` param in the `Content-Disposition` header of
+- Add an additional `filename*` param in the `Content-Disposition` header of
`actix_files::NamedFile` to be more compatible. (#1151)
## 0.1.6 - 2019-10-14
-* Add option to redirect to a slash-ended path `Files` #1132
+- Add option to redirect to a slash-ended path `Files` #1132
## 0.1.5 - 2019-10-08
-* Bump up `mime_guess` crate version to 2.0.1
-* Bump up `percent-encoding` crate version to 2.1
-* Allow user defined request guards for `Files` #1113
+- Bump up `mime_guess` crate version to 2.0.1
+- Bump up `percent-encoding` crate version to 2.1
+- Allow user defined request guards for `Files` #1113
## 0.1.4 - 2019-07-20
-* Allow to disable `Content-Disposition` header #686
+- Allow to disable `Content-Disposition` header #686
## 0.1.3 - 2019-06-28
-* Do not set `Content-Length` header, let actix-http set it #930
+- Do not set `Content-Length` header, let actix-http set it #930
## 0.1.2 - 2019-06-13
-* Content-Length is 0 for NamedFile HEAD request #914
-* Fix ring dependency from actix-web default features for #741
+- Content-Length is 0 for NamedFile HEAD request #914
+- Fix ring dependency from actix-web default features for #741
## 0.1.1 - 2019-06-01
-* Static files are incorrectly served as both chunked and with length #812
+- Static files are incorrectly served as both chunked and with length #812
## 0.1.0 - 2019-05-25
-* NamedFile last-modified check always fails due to nano-seconds in file modified date #820
+- NamedFile last-modified check always fails due to nano-seconds in file modified date #820
## 0.1.0-beta.4 - 2019-05-12
-* Update actix-web to beta.4
+- Update actix-web to beta.4
## 0.1.0-beta.1 - 2019-04-20
-* Update actix-web to beta.1
+- Update actix-web to beta.1
## 0.1.0-alpha.6 - 2019-04-14
-* Update actix-web to alpha6
+- Update actix-web to alpha6
## 0.1.0-alpha.4 - 2019-04-08
-* Update actix-web to alpha4
+- Update actix-web to alpha4
## 0.1.0-alpha.2 - 2019-04-02
-* Add default handler support
+- Add default handler support
## 0.1.0-alpha.1 - 2019-03-28
-* Initial impl
+- Initial impl
diff --git a/actix-files/Cargo.toml b/actix-files/Cargo.toml
index 45fa18a69..fe780f5ab 100644
--- a/actix-files/Cargo.toml
+++ b/actix-files/Cargo.toml
@@ -1,13 +1,15 @@
[package]
name = "actix-files"
-version = "0.6.0-beta.2"
-authors = ["Nikolay Kim "]
+version = "0.6.0-beta.13"
+authors = [
+ "Nikolay Kim ",
+ "fakeshadow <24548779@qq.com>",
+ "Rob Ede ",
+]
description = "Static file serving for Actix Web"
-readme = "README.md"
keywords = ["actix", "http", "async", "futures"]
homepage = "https://actix.rs"
-repository = "https://github.com/actix/actix-web.git"
-documentation = "https://docs.rs/actix-files/"
+repository = "https://github.com/actix/actix-web"
categories = ["asynchronous", "web-programming::http-server"]
license = "MIT OR Apache-2.0"
edition = "2018"
@@ -16,21 +18,31 @@ edition = "2018"
name = "actix_files"
path = "src/lib.rs"
+[features]
+experimental-io-uring = ["actix-web/experimental-io-uring", "tokio-uring"]
+
[dependencies]
-actix-web = { version = "4.0.0-beta.3", default-features = false }
-actix-service = "2.0.0-beta.4"
+actix-http = "3.0.0-beta.18"
+actix-service = "2"
+actix-utils = "3"
+actix-web = { version = "4.0.0-beta.19", default-features = false }
askama_escape = "0.10"
bitflags = "1"
bytes = "1"
-futures-core = { version = "0.3.7", default-features = false }
-futures-util = { version = "0.3.7", default-features = false }
derive_more = "0.99.5"
+futures-core = { version = "0.3.7", default-features = false, features = ["alloc"] }
+http-range = "0.1.4"
log = "0.4"
mime = "0.3"
mime_guess = "2.0.1"
percent-encoding = "2.1"
+pin-project-lite = "0.2.7"
+
+tokio-uring = { version = "0.1", optional = true }
[dev-dependencies]
-actix-rt = "2"
-actix-web = "4.0.0-beta.3"
+actix-rt = "2.2"
+actix-test = "0.1.0-beta.11"
+actix-web = "4.0.0-beta.19"
+tempfile = "3.2"
diff --git a/actix-files/README.md b/actix-files/README.md
index 463f20224..be878d958 100644
--- a/actix-files/README.md
+++ b/actix-files/README.md
@@ -3,17 +3,16 @@
> Static file serving for Actix Web
[](https://crates.io/crates/actix-files)
-[](https://docs.rs/actix-files/0.5.0)
-[](https://blog.rust-lang.org/2020/03/12/Rust-1.46.html)
+[](https://docs.rs/actix-files/0.6.0-beta.13)
+[](https://blog.rust-lang.org/2021/05/06/Rust-1.54.0.html)

-[](https://deps.rs/crate/actix-files/0.5.0)
+[](https://deps.rs/crate/actix-files/0.6.0-beta.13)
[](https://crates.io/crates/actix-files)
-[](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[](https://discord.gg/NWpN5mmg3x)
## Documentation & Resources
- [API Documentation](https://docs.rs/actix-files/)
-- [Example Project](https://github.com/actix/examples/tree/master/static_index)
-- [Chat on Gitter](https://gitter.im/actix/actix-web)
-- Minimum supported Rust version: 1.46 or later
+- [Example Project](https://github.com/actix/examples/tree/master/basics/static_index)
+- Minimum Supported Rust Version (MSRV): 1.54
diff --git a/actix-files/src/chunked.rs b/actix-files/src/chunked.rs
index f639848c9..68221ccc3 100644
--- a/actix-files/src/chunked.rs
+++ b/actix-files/src/chunked.rs
@@ -1,98 +1,277 @@
use std::{
cmp, fmt,
- fs::File,
future::Future,
- io::{self, Read, Seek},
+ io,
pin::Pin,
task::{Context, Poll},
};
-use actix_web::{
- error::{BlockingError, Error},
- rt::task::{spawn_blocking, JoinHandle},
-};
-use bytes::Bytes;
+use actix_web::{error::Error, web::Bytes};
use futures_core::{ready, Stream};
+use pin_project_lite::pin_project;
-#[doc(hidden)]
-/// A helper created from a `std::fs::File` which reads the file
-/// chunk-by-chunk on a `ThreadPool`.
-pub struct ChunkedReadFile {
- size: u64,
- offset: u64,
- state: ChunkedReadFileState,
- counter: u64,
-}
+use super::named::File;
-enum ChunkedReadFileState {
- File(Option),
- Future(JoinHandle>),
-}
-
-impl ChunkedReadFile {
- pub(crate) fn new(size: u64, offset: u64, file: File) -> Self {
- Self {
- size,
- offset,
- state: ChunkedReadFileState::File(Some(file)),
- counter: 0,
- }
+pin_project! {
+ /// Adapter to read a `std::file::File` in chunks.
+ #[doc(hidden)]
+ pub struct ChunkedReadFile {
+ size: u64,
+ offset: u64,
+ #[pin]
+ state: ChunkedReadFileState,
+ counter: u64,
+ callback: F,
}
}
-impl fmt::Debug for ChunkedReadFile {
+#[cfg(not(feature = "experimental-io-uring"))]
+pin_project! {
+ #[project = ChunkedReadFileStateProj]
+ #[project_replace = ChunkedReadFileStateProjReplace]
+ enum ChunkedReadFileState {
+ File { file: Option, },
+ Future { #[pin] fut: Fut },
+ }
+}
+
+#[cfg(feature = "experimental-io-uring")]
+pin_project! {
+ #[project = ChunkedReadFileStateProj]
+ #[project_replace = ChunkedReadFileStateProjReplace]
+ enum ChunkedReadFileState {
+ File { file: Option<(File, BytesMut)> },
+ Future { #[pin] fut: Fut },
+ }
+}
+
+impl fmt::Debug for ChunkedReadFile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("ChunkedReadFile")
}
}
-impl Stream for ChunkedReadFile {
+pub(crate) fn new_chunked_read(
+ size: u64,
+ offset: u64,
+ file: File,
+) -> impl Stream- > {
+ ChunkedReadFile {
+ size,
+ offset,
+ #[cfg(not(feature = "experimental-io-uring"))]
+ state: ChunkedReadFileState::File { file: Some(file) },
+ #[cfg(feature = "experimental-io-uring")]
+ state: ChunkedReadFileState::File {
+ file: Some((file, BytesMut::new())),
+ },
+ counter: 0,
+ callback: chunked_read_file_callback,
+ }
+}
+
+#[cfg(not(feature = "experimental-io-uring"))]
+async fn chunked_read_file_callback(
+ mut file: File,
+ offset: u64,
+ max_bytes: usize,
+) -> Result<(File, Bytes), Error> {
+ use io::{Read as _, Seek as _};
+
+ let res = actix_web::rt::task::spawn_blocking(move || {
+ let mut buf = Vec::with_capacity(max_bytes);
+
+ file.seek(io::SeekFrom::Start(offset))?;
+
+ let n_bytes = file.by_ref().take(max_bytes as u64).read_to_end(&mut buf)?;
+
+ if n_bytes == 0 {
+ Err(io::Error::from(io::ErrorKind::UnexpectedEof))
+ } else {
+ Ok((file, Bytes::from(buf)))
+ }
+ })
+ .await
+ .map_err(|_| actix_web::error::BlockingError)??;
+
+ Ok(res)
+}
+
+#[cfg(feature = "experimental-io-uring")]
+async fn chunked_read_file_callback(
+ file: File,
+ offset: u64,
+ max_bytes: usize,
+ mut bytes_mut: BytesMut,
+) -> io::Result<(File, Bytes, BytesMut)> {
+ bytes_mut.reserve(max_bytes);
+
+ let (res, mut bytes_mut) = file.read_at(bytes_mut, offset).await;
+ let n_bytes = res?;
+
+ if n_bytes == 0 {
+ return Err(io::ErrorKind::UnexpectedEof.into());
+ }
+
+ let bytes = bytes_mut.split_to(n_bytes).freeze();
+
+ Ok((file, bytes, bytes_mut))
+}
+
+#[cfg(feature = "experimental-io-uring")]
+impl Stream for ChunkedReadFile
+where
+ F: Fn(File, u64, usize, BytesMut) -> Fut,
+ Fut: Future