use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use futures::FutureExt;
use glaredb_error::{DbError, Result};
use super::FileHandle;
pub trait FileExt: FileHandle {
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> {
Read { file: self, buf }
}
#[must_use]
fn read_fill<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadFill<'a, Self> {
ReadFill {
file: self,
read_count: 0,
buf,
}
}
#[must_use]
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self> {
ReadExact {
fill: ReadFill {
file: self,
read_count: 0,
buf,
},
}
}
#[must_use]
fn seek(&mut self, seek: io::SeekFrom) -> Seek<'_, Self> {
Seek { seek, file: self }
}
}
impl<F> FileExt for F where F: FileHandle {}
#[derive(Debug)]
pub struct Read<'a, F: FileHandle + ?Sized> {
file: &'a mut F,
buf: &'a mut [u8],
}
impl<F> Future for Read<'_, F>
where
F: FileHandle + ?Sized,
{
type Output = Result<usize>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
this.file.poll_read(cx, this.buf)
}
}
#[derive(Debug)]
pub struct ReadFill<'a, F: FileHandle + ?Sized> {
file: &'a mut F,
read_count: usize,
buf: &'a mut [u8],
}
impl<F> Future for ReadFill<'_, F>
where
F: FileHandle + ?Sized,
{
type Output = Result<usize>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.get_mut();
loop {
let read_buf = &mut this.buf[this.read_count..];
if read_buf.is_empty() {
return Poll::Ready(Ok(this.read_count));
}
let n = match this.file.poll_read(cx, read_buf) {
Poll::Ready(Ok(n)) => n,
Poll::Ready(Err(e)) => return Poll::Ready(Err(e)),
Poll::Pending => return Poll::Pending,
};
this.read_count += n;
if n == 0 {
return Poll::Ready(Ok(this.read_count));
}
}
}
}
#[derive(Debug)]
pub struct ReadExact<'a, F: FileHandle + ?Sized> {
fill: ReadFill<'a, F>,
}
impl<F> Future for ReadExact<'_, F>
where
F: FileHandle + ?Sized,
{
type Output = Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match self.fill.poll_unpin(cx) {
Poll::Ready(Ok(n)) => {
if n == self.fill.buf.len() {
Poll::Ready(Ok(()))
} else {
Poll::Ready(Err(DbError::new(format!(
"Unexpected EOF, read {} bytes, expected to read {} bytes",
n,
self.fill.buf.len()
))))
}
}
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => Poll::Pending,
}
}
}
#[derive(Debug)]
pub struct Seek<'a, F: FileHandle + ?Sized> {
seek: io::SeekFrom,
file: &'a mut F,
}
impl<F> Future for Seek<'_, F>
where
F: FileHandle + ?Sized,
{
type Output = Result<()>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let seek = self.seek;
self.file.poll_seek(cx, seek)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::buffer::buffer_manager::DefaultBufferManager;
use crate::runtime::filesystem::memory::MemoryFileHandle;
use crate::util::future::block_on;
#[test]
fn read_fill_small_buffer() {
let mut handle = MemoryFileHandle::from_bytes(&DefaultBufferManager, b"hello").unwrap();
let mut out = vec![0; 4];
let count = block_on(handle.read_fill(&mut out)).unwrap();
assert_eq!(4, count);
assert_eq!(b"hell", &out[0..4]);
}
#[test]
fn read_fill_small_file() {
let mut handle = MemoryFileHandle::from_bytes(&DefaultBufferManager, b"hello").unwrap();
let mut out = vec![0; 10];
let count = block_on(handle.read_fill(&mut out)).unwrap();
assert_eq!(5, count);
assert_eq!(b"hello", &out[0..5]);
}
}