blob: 4aa3750cfa72f0615b164b0f00a9ae7addeb85bf [file]
use futures::Future;
use monoio::{
buf::{IoBufMut, IoVecBufMut, IoVecWrapper},
fs::File,
io::{AsyncReadRent, AsyncWriteRent, BufReader, BufWriter},
BufResult,
};
use std::io::SeekFrom;
pub struct IggyReader<R: AsyncReadRent> {
inner: BufReader<R>,
}
pub struct IggyWriter<W: AsyncWriteRent> {
inner: BufWriter<W>,
}
pub struct IggyFile {
file: File,
position: u64,
}
impl IggyFile {
pub fn new(file: File) -> Self {
Self { file, position: 0 }
}
// Maintaining the api compatibility, this is mostly used with the Start variant.
/// This method doesn't verify the file bounds, it just sets the position.
pub fn seek(&mut self, pos: SeekFrom) {
self.position = match pos {
SeekFrom::Start(n) => n as i64,
SeekFrom::End(n) => n,
SeekFrom::Current(n) => self.position as i64 + n,
} as u64;
}
}
impl IggyReader<IggyFile> {
pub fn new(file: File) -> Self {
let file = IggyFile::new(file);
Self {
inner: BufReader::new(file),
}
}
pub fn with_capacity(capacity: usize, file: File) -> Self {
let file = IggyFile::new(file);
Self {
inner: BufReader::with_capacity(capacity, file),
}
}
// Maintaining the api compatibility, this is mostly used with the Start variant.
/// This method doesn't verify the file bounds, it just sets the position.
pub fn seek(&mut self, pos: SeekFrom) {
self.inner.get_mut().seek(pos);
}
}
impl IggyWriter<IggyFile> {
pub fn new(file: File) -> Self {
let file = IggyFile::new(file);
Self {
inner: BufWriter::new(file),
}
}
pub fn with_capacity(capacity: usize, file: File) -> Self {
let file = IggyFile::new(file);
Self {
inner: BufWriter::with_capacity(capacity, file),
}
}
}
impl AsyncReadRent for IggyFile {
async fn read<T: IoBufMut>(&mut self, buf: T) -> BufResult<usize, T> {
let (res, buf) = self.file.read_at(buf, self.position).await;
let n = match res {
Ok(n) => n,
Err(e) => return (Err(e), buf),
};
self.position += n as u64;
(Ok(n), buf)
}
//TODO(numinex) - maybe implement this ?
fn readv<T: IoVecBufMut>(&mut self, buf: T) -> impl Future<Output = BufResult<usize, T>> {
async move { (Ok(0), buf) }
}
}
impl AsyncWriteRent for IggyFile {
async fn write<T: monoio::buf::IoBuf>(&mut self, buf: T) -> BufResult<usize, T> {
let (res, buf) = self.file.write_at(buf, self.position).await;
let n = match res {
Ok(n) => n,
Err(e) => return (Err(e), buf),
};
self.position += n as u64;
(Ok(n), buf)
}
async fn writev<T: monoio::buf::IoVecBuf>(&mut self, buf_vec: T) -> BufResult<usize, T> {
let slice = match IoVecWrapper::new(buf_vec) {
Ok(slice) => slice,
Err(buf) => return (Ok(0), buf),
};
let (result, slice) = self.write(slice).await;
(result, slice.into_inner())
}
async fn flush(&mut self) -> std::io::Result<()> {
self.file.sync_all().await
}
//TODO(numinex) - How to implement this ?
async fn shutdown(&mut self) -> std::io::Result<()> {
panic!("shutdown is not supported for IggyFile");
/*
self.file.sync_all().await;
unsafe {
let file = *self.file;
file.close().await
}
*/
}
}
impl<R> AsyncReadRent for IggyReader<R>
where
R: AsyncReadRent,
{
fn read<T: IoBufMut>(&mut self, buf: T) -> impl Future<Output = BufResult<usize, T>> {
self.inner.read(buf)
}
fn readv<T: IoVecBufMut>(&mut self, buf: T) -> impl Future<Output = BufResult<usize, T>> {
self.inner.readv(buf)
}
}
impl<W> AsyncWriteRent for IggyWriter<W>
where
W: AsyncWriteRent,
{
fn write<T: monoio::buf::IoBuf>(
&mut self,
buf: T,
) -> impl Future<Output = BufResult<usize, T>> {
self.inner.write(buf)
}
fn writev<T: monoio::buf::IoVecBuf>(
&mut self,
buf_vec: T,
) -> impl Future<Output = BufResult<usize, T>> {
self.inner.writev(buf_vec)
}
fn flush(&mut self) -> impl Future<Output = std::io::Result<()>> {
self.inner.flush()
}
fn shutdown(&mut self) -> impl Future<Output = std::io::Result<()>> {
self.inner.shutdown()
}
}