use async_std::{
fs,
io::{self, ReadExt as _, WriteExt as _},
path::{Path, PathBuf},
stream::StreamExt as _,
};
use crate::merge::{Merge, MergeError};
pub trait MergeAsyncExt {
fn run_async(
&self
) -> impl std::future::Future<Output = Result<(), MergeError>> + Send;
}
impl MergeAsyncExt for Merge {
async fn run_async(&self) -> Result<(), MergeError> {
let in_dir: &Path = match self.in_dir {
| Some(ref p) => {
let p: &Path = p.as_ref();
if !p.exists().await {
return Err(MergeError::InDirNotFound);
}
if !p.is_dir().await {
return Err(MergeError::InDirNotDir);
}
p
},
| None => return Err(MergeError::InDirNotSet),
};
let out_file: &Path = match self.out_file {
| Some(ref p) => {
let p: &Path = p.as_ref();
if p.exists().await {
if p.is_dir().await {
fs::remove_dir_all(p)
.await
.map_err(|_| MergeError::OutFileNotRemoved)?;
} else {
fs::remove_file(p)
.await
.map_err(|_| MergeError::OutFileNotRemoved)?;
}
}
if let Some(parent) = p.parent() {
fs::create_dir_all(parent)
.await
.map_err(|_| MergeError::OutDirNotCreated)?;
}
p
},
| None => return Err(MergeError::OutFileNotSet),
};
let buffer_capacity: usize = self.buffer_capacity;
let output: fs::File = fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(out_file)
.await
.map_err(|_| MergeError::OutFileNotOpened)?;
let mut writer: io::BufWriter<fs::File> =
io::BufWriter::with_capacity(buffer_capacity, output);
let mut entries: Vec<PathBuf> = Vec::new();
let mut read_dir: fs::ReadDir =
fs::read_dir(in_dir).await.map_err(|_| MergeError::InDirNotRead)?;
while let Some(ref entry) = read_dir
.next()
.await
.transpose()
.map_err(|_| MergeError::InDirNotRead)?
{
let path: PathBuf = entry.path();
if path.is_file().await {
entries.push(path);
}
}
if entries.is_empty() {
return Err(MergeError::InDirNoFile);
}
entries.sort_by_key(|entry| {
entry
.file_name()
.unwrap()
.to_str()
.unwrap()
.parse::<usize>()
.unwrap()
});
for entry in entries {
let input: fs::File = fs::OpenOptions::new()
.read(true)
.open(&entry)
.await
.map_err(|_| MergeError::InFileNotOpened)?;
let mut reader: io::BufReader<fs::File> =
io::BufReader::with_capacity(buffer_capacity, input);
let mut buffer: Vec<u8> = vec![0; buffer_capacity];
loop {
let read: usize = reader
.read(&mut buffer)
.await
.map_err(|_| MergeError::InFileNotRead)?;
if read == 0 {
break;
}
writer
.write_all(&buffer[..read])
.await
.map_err(|_| MergeError::OutFileNotWritten)?;
}
}
writer.flush().await.map_err(|_| MergeError::OutFileNotWritten)?;
Ok(())
}
}