use std::fs::File;
use std::future::Future;
use std::io;
use std::io::Write;
use std::path::Path;
use std::sync::Arc;
use parking_lot::Mutex;
use crate::IoBuf;
use crate::VortexWrite;
use crate::runtime::Handle;
pub struct FileWrite {
file: Arc<Mutex<File>>,
handle: Handle,
}
impl FileWrite {
pub async fn create(path: impl AsRef<Path>, handle: Handle) -> io::Result<Self> {
let path = path.as_ref().to_path_buf();
let file = handle.spawn_blocking(move || File::create(path)).await?;
Ok(Self {
file: Arc::new(Mutex::new(file)),
handle,
})
}
}
impl VortexWrite for FileWrite {
fn write_all<B: IoBuf>(&mut self, buffer: B) -> impl Future<Output = io::Result<B>> + Send {
let file = Arc::clone(&self.file);
let handle = self.handle.clone();
async move {
handle
.spawn_blocking(move || {
file.lock().write_all(buffer.as_slice())?;
Ok(buffer)
})
.await
}
}
fn flush(&mut self) -> impl Future<Output = io::Result<()>> + Send {
let file = Arc::clone(&self.file);
let handle = self.handle.clone();
async move { handle.spawn_blocking(move || file.lock().flush()).await }
}
fn shutdown(&mut self) -> impl Future<Output = io::Result<()>> + Send {
self.flush()
}
}
#[cfg(test)]
mod tests {
use tempfile::tempdir;
use vortex_error::VortexResult;
use super::*;
use crate::runtime::BlockingRuntime;
use crate::runtime::current::CurrentThreadRuntime;
#[test]
fn test_write_file() -> VortexResult<()> {
let directory = tempdir()?;
let path = directory.path().join("write.vortex");
let runtime = CurrentThreadRuntime::new();
runtime.block_on(async {
let mut writer = FileWrite::create(&path, runtime.handle()).await?;
writer.write_all(vec![1, 2, 3]).await?;
writer.shutdown().await
})?;
assert_eq!(std::fs::read(path)?, vec![1, 2, 3]);
Ok(())
}
}