use std::path::{Path, PathBuf};
use std::pin::Pin;
use tokio::io::AsyncRead;
#[non_exhaustive]
pub enum FileSource {
#[non_exhaustive]
Bytes {
filename: String,
bytes: Vec<u8>,
content_type: String,
},
#[non_exhaustive]
Path(PathBuf),
#[non_exhaustive]
Stream {
filename: String,
reader: Pin<Box<dyn AsyncRead + Send>>,
content_type: String,
},
}
impl std::fmt::Debug for FileSource {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Bytes {
filename,
bytes,
content_type,
} => f
.debug_struct("Bytes")
.field("filename", filename)
.field("bytes", &bytes.len())
.field("content_type", content_type)
.finish(),
Self::Path(p) => f.debug_tuple("Path").field(p).finish(),
Self::Stream {
filename,
content_type,
..
} => f
.debug_struct("Stream")
.field("filename", filename)
.field("content_type", content_type)
.finish_non_exhaustive(),
}
}
}
impl FileSource {
pub fn bytes(
filename: impl Into<String>,
data: impl Into<Vec<u8>>,
content_type: impl Into<String>,
) -> Self {
Self::Bytes {
filename: filename.into(),
bytes: data.into(),
content_type: content_type.into(),
}
}
pub fn path(path: impl Into<PathBuf>) -> Self {
Self::Path(path.into())
}
pub fn stream(
filename: impl Into<String>,
reader: impl AsyncRead + Send + 'static,
content_type: impl Into<String>,
) -> Self {
Self::Stream {
filename: filename.into(),
reader: Box::pin(reader),
content_type: content_type.into(),
}
}
}
impl From<PathBuf> for FileSource {
fn from(p: PathBuf) -> Self {
Self::Path(p)
}
}
impl From<&Path> for FileSource {
fn from(p: &Path) -> Self {
Self::Path(p.to_path_buf())
}
}
#[cfg(test)]
mod tests {
use static_assertions::assert_impl_all;
use super::*;
assert_impl_all!(FileSource: Send);
}