Skip to content

Commit 00b5f4c

Browse files
poliorceticsmladedav
authored andcommitted
fix(axum-extra): don't require S generic param when using FileStream::from_path() (#3437)
1 parent 492a924 commit 00b5f4c

File tree

1 file changed

+48
-47
lines changed

1 file changed

+48
-47
lines changed

axum-extra/src/response/file_stream.rs

Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -70,52 +70,6 @@ where
7070
}
7171
}
7272

73-
/// Create a [`FileStream`] from a file path.
74-
///
75-
/// # Examples
76-
///
77-
/// ```
78-
/// use axum::{
79-
/// http::StatusCode,
80-
/// response::IntoResponse,
81-
/// Router,
82-
/// routing::get
83-
/// };
84-
/// use axum_extra::response::file_stream::FileStream;
85-
/// use tokio::fs::File;
86-
/// use tokio_util::io::ReaderStream;
87-
///
88-
/// async fn file_stream() -> impl IntoResponse {
89-
/// FileStream::<ReaderStream<File>>::from_path("test.txt")
90-
/// .await
91-
/// .map_err(|e| (StatusCode::NOT_FOUND, format!("File not found: {e}")))
92-
/// }
93-
///
94-
/// let app = Router::new().route("/file-stream", get(file_stream));
95-
/// # let _: Router = app;
96-
/// ```
97-
pub async fn from_path(path: impl AsRef<Path>) -> io::Result<FileStream<ReaderStream<File>>> {
98-
let file = File::open(&path).await?;
99-
let mut content_size = None;
100-
let mut file_name = None;
101-
102-
if let Ok(metadata) = file.metadata().await {
103-
content_size = Some(metadata.len());
104-
}
105-
106-
if let Some(file_name_os) = path.as_ref().file_name() {
107-
if let Some(file_name_str) = file_name_os.to_str() {
108-
file_name = Some(file_name_str.to_owned());
109-
}
110-
}
111-
112-
Ok(FileStream {
113-
stream: ReaderStream::new(file),
114-
file_name,
115-
content_size,
116-
})
117-
}
118-
11973
/// Set the file name of the [`FileStream`].
12074
///
12175
/// This adds the attachment `Content-Disposition` header with the given `file_name`.
@@ -259,6 +213,53 @@ where
259213
}
260214
}
261215

216+
// Split because the general impl requires to specify `S` and this one does not.
217+
impl FileStream<ReaderStream<File>> {
218+
/// Create a [`FileStream`] from a file path.
219+
///
220+
/// # Examples
221+
///
222+
/// ```
223+
/// use axum::{
224+
/// http::StatusCode,
225+
/// response::IntoResponse,
226+
/// Router,
227+
/// routing::get
228+
/// };
229+
/// use axum_extra::response::file_stream::FileStream;
230+
///
231+
/// async fn file_stream() -> impl IntoResponse {
232+
/// FileStream::from_path("test.txt")
233+
/// .await
234+
/// .map_err(|e| (StatusCode::NOT_FOUND, format!("File not found: {e}")))
235+
/// }
236+
///
237+
/// let app = Router::new().route("/file-stream", get(file_stream));
238+
/// # let _: Router = app;
239+
/// ```
240+
pub async fn from_path(path: impl AsRef<Path>) -> io::Result<Self> {
241+
let file = File::open(&path).await?;
242+
let mut content_size = None;
243+
let mut file_name = None;
244+
245+
if let Ok(metadata) = file.metadata().await {
246+
content_size = Some(metadata.len());
247+
}
248+
249+
if let Some(file_name_os) = path.as_ref().file_name() {
250+
if let Some(file_name_str) = file_name_os.to_str() {
251+
file_name = Some(file_name_str.to_owned());
252+
}
253+
}
254+
255+
Ok(Self {
256+
stream: ReaderStream::new(file),
257+
file_name,
258+
content_size,
259+
})
260+
}
261+
}
262+
262263
impl<S> IntoResponse for FileStream<S>
263264
where
264265
S: TryStream + Send + 'static,
@@ -474,7 +475,7 @@ mod tests {
474475
let app = Router::new().route(
475476
"/from_path",
476477
get(move || async move {
477-
FileStream::<ReaderStream<File>>::from_path(Path::new("CHANGELOG.md"))
478+
FileStream::from_path(Path::new("CHANGELOG.md"))
478479
.await
479480
.unwrap()
480481
.into_response()

0 commit comments

Comments
 (0)