use crate::entry_data::{EntryData, EntrySize};
use futures_util::future::TryFutureExt;
use std::{future::Future, io::Result, path::PathBuf, pin::Pin};
use tokio::fs::{metadata, File};
pub struct TokioFileEntry(PathBuf);
impl TokioFileEntry {
pub fn new(path: PathBuf) -> TokioFileEntry {
TokioFileEntry(path)
}
}
impl From<PathBuf> for TokioFileEntry {
fn from(path: PathBuf) -> Self {
TokioFileEntry::new(path)
}
}
impl EntryData for TokioFileEntry {
type Reader = File;
type Future = Pin<Box<dyn Future<Output = Result<File>>>>;
fn get_reader(&self) -> Self::Future {
Box::pin(File::open(self.0.clone()))
}
}
impl EntrySize for TokioFileEntry {
type Future = Pin<Box<dyn Future<Output = Result<u64>>>>;
fn size(&self) -> Self::Future {
Box::pin(metadata(self.0.clone()).map_ok(|m| m.len()))
}
}
#[cfg(test)]
mod test {
use super::*;
use std::io::Write;
use std::pin::pin;
use crate::test_util::read_to_vec;
use test_strategy::proptest;
#[proptest(async = "tokio")]
async fn can_determine_file_size(content: Vec<u8>) {
let (mut tempfile, tempfile_name) = tempfile::NamedTempFile::new().unwrap().into_parts();
tempfile.write_all(content.as_slice()).unwrap();
drop(tempfile);
let entry = TokioFileEntry::new(tempfile_name.to_path_buf());
assert!(entry.size().await.unwrap() == content.len() as u64);
}
#[proptest(async = "tokio")]
async fn can_read_content(content: Vec<u8>) {
let (mut tempfile, tempfile_name) = tempfile::NamedTempFile::new().unwrap().into_parts();
tempfile.write_all(content.as_slice()).unwrap();
drop(tempfile);
let entry = TokioFileEntry::new(tempfile_name.to_path_buf());
let reader = pin!(entry.get_reader().await.unwrap());
assert!(read_to_vec(reader, 8192).await.unwrap() == content);
}
}