use std::fmt::Debug;
use std::fs::File;
use std::io::{Cursor, Error, ErrorKind, Read, Seek, SeekFrom};
use crate::constant::DEFAULT_READ_BUFFER_SIZE;
use crate::error::{GenericError, TosError};
pub(crate) fn read_at_most(reader: &mut dyn Read, buf: &mut Vec<u8>, most: usize) -> Result<usize, TosError> {
if most == 0 {
return Ok(0);
}
let mut temp_buf = [0u8; DEFAULT_READ_BUFFER_SIZE];
let mut read_total = 0usize;
loop {
match reader.read(&mut temp_buf) {
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(TosError::client_error_with_cause("io read error", GenericError::IoError(e.to_string()))),
Ok(mut read_once) => {
if read_once == 0 {
return Ok(read_total);
}
if read_total + read_once > most {
read_once = most - read_total;
}
buf.extend_from_slice(&temp_buf[0..read_once]);
read_total += read_once;
if read_total >= most {
return Ok(read_total);
}
}
}
}
}
pub(crate) trait BuildFileReader: Read + Sized {
fn new(input: &str) -> Result<(Self, Option<usize>), TosError>;
fn new_with_offset(input: &str, offset: i64) -> Result<(Self, Option<usize>), TosError>;
}
impl BuildFileReader for InternalReader<File> {
fn new(input: &str) -> Result<(Self, Option<usize>), TosError> {
match File::open(input) {
Ok(fd) => {
if let Ok(x) = fd.metadata() {
let len = x.len() as usize;
return Ok((Self { b: fd, total_size: Some(len), read_size: 0 }, Some(len)));
}
Ok((Self { b: fd, total_size: None, read_size: 0 }, None))
}
Err(e) => Err(TosError::client_error_with_cause("open file error", GenericError::IoError(e.to_string()))),
}
}
fn new_with_offset(input: &str, offset: i64) -> Result<(Self, Option<usize>), TosError> {
let (mut fd, len) = <Self as BuildFileReader>::new(input)?;
if offset > 0 {
if let Err(e) = fd.seek(SeekFrom::Start(offset as u64)) {
return Err(TosError::client_error_with_cause("seek file error", GenericError::IoError(e.to_string())));
}
}
Ok((fd, len))
}
}
pub(crate) trait BuildBufferReader: Sized {
fn new(input: Vec<u8>) -> Result<(Self, usize), TosError>;
}
impl BuildBufferReader for InternalReader<Cursor<Vec<u8>>> {
fn new(input: Vec<u8>) -> Result<(Self, usize), TosError> {
let len = input.len();
Ok(
(Self {
b: Cursor::new(input),
total_size: Some(len),
read_size: 0,
}, len)
)
}
}
#[derive(Debug)]
pub(crate) struct InternalReader<B> {
pub(crate) b: B,
pub(crate) total_size: Option<usize>,
pub(crate) read_size: usize,
}
impl<B> InternalReader<B> {
pub(crate) fn new(b: B) -> Self {
Self {
b,
total_size: None,
read_size: 0,
}
}
pub(crate) fn sized(b: B, len: usize) -> Self {
Self {
b,
total_size: Some(len),
read_size: 0,
}
}
}
impl<B> Read for InternalReader<B> where B: Read {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
if buf.len() == 0 {
return Ok(0);
}
let read_once = self.b.read(buf)?;
self.read_size += read_once;
if read_once == 0 {
if let Some(total_size) = self.total_size {
if self.read_size < total_size {
return Err(Error::new(ErrorKind::UnexpectedEof,
format!("premature end, expected {}, actual {}", total_size, self.read_size)));
}
}
}
Ok(read_once)
}
}
impl<B> Seek for InternalReader<B> where B: Seek {
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
self.b.seek(pos)
}
fn rewind(&mut self) -> std::io::Result<()> {
self.b.rewind()
}
fn stream_position(&mut self) -> std::io::Result<u64> {
self.b.stream_position()
}
}
unsafe impl<B> Send for InternalReader<B> where B: Send {}