rsbx 2.0.0

Enhanced implementation of SeqBox in Rust
Documentation
#![allow(dead_code)]
use general_error::Error;
use file_error::FileError;
use file_error::to_err;
use std::io::Read;
use std::io::Write;
use std::io::BufReader;
use std::io::SeekFrom;
use std::fs::File;
use std::io::Seek;
use std::fs::Metadata;
use std::fs::OpenOptions;

use reader::ReadResult;

const READ_RETRIES : usize = 5;

macro_rules! file_op {
    (
        $self:ident write => $input:expr
    ) => {{
        use self::FileHandle::*;
        match $self.file {
            Buffered(ref mut f)   => {
                // drop the internal buffer by seeking
                match f.seek(SeekFrom::Current(0)) {
                    Ok(_)  => {},
                    Err(e) => { return Err(to_err(FileError::new(e.kind(), &$self.path))); },
                }

                f.get_mut().write($input)
            },
            Unbuffered(ref mut f) => {
                f.write($input)
            },
        }
    }};
    (
        $self:ident $op:ident => $input:expr
    ) => {{
        use self::FileHandle::*;
        match $self.file {
            Buffered(ref mut f)   => f.$op($input),
            Unbuffered(ref mut f) => f.$op($input),
        }
    }};
    (
        $self:ident get_metadata
    ) => {{
        use self::FileHandle::*;
        match $self.file {
            Buffered(ref f)   => f.get_ref().metadata(),
            Unbuffered(ref f) => f.metadata(),
        }
    }}
}

pub struct FileReaderParam {
    pub write    : bool,
    pub buffered : bool,
}

enum FileHandle {
    Buffered(BufReader<File>),
    Unbuffered(File),
}

pub struct FileReader {
    file          : FileHandle,
    path          : String,
    write_enabled : bool,
}

impl FileReader {
    pub fn new(path  : &str,
               param : FileReaderParam) -> Result<FileReader, Error> {
        let write_enabled = param.write;
        let file =
            OpenOptions::new()
            .write(write_enabled)
            .read(true)
            .open(&path);
        let file = match file {
            Ok(f)  => f,
            Err(e) => { return Err(to_err(FileError::new(e.kind(), path))); }
        };
        Ok (FileReader {
            file :
            if param.buffered {
                FileHandle::Buffered(BufReader::new(file))
            } else {
                FileHandle::Unbuffered(file)
            },
            path : String::from(path),
            write_enabled,
        })
    }

    pub fn read(&mut self, buf : &mut [u8]) -> Result<ReadResult, Error> {
        let mut len_read = 0;
        let mut tries    = 0;
        while len_read < buf.len() && tries < READ_RETRIES {
            match file_op!(self read => &mut buf[len_read..]) {
                Ok(len) => { len_read += len; },
                Err(e)  => { return Err(to_err(FileError::new(e.kind(), &self.path))); }
            }

            tries += 1;
        }

        Ok(ReadResult { len_read,
                        eof_seen : len_read < buf.len() })
    }

    pub fn write(&mut self, buf : &[u8]) -> Result<usize, Error> {
        if !self.write_enabled {
            panic!("Write not enabled");
        }

        match file_op!(self write => buf) {
            Ok(len) => Ok(len),
            Err(e)  => Err(to_err(FileError::new(e.kind(), &self.path)))
        }
    }

    pub fn seek(&mut self, pos : SeekFrom)
                -> Result<u64, Error> {
        match file_op!(self seek => pos) {
            Ok(pos) => Ok(pos),
            Err(e)  => Err(to_err(FileError::new(e.kind(), &self.path)))
        }
    }

    pub fn cur_pos(&mut self) -> Result<u64, Error> {
        match file_op!(self seek => SeekFrom::Current(0)) {
            Ok(pos) => Ok(pos),
            Err(e)  => Err(to_err(FileError::new(e.kind(), &self.path)))
        }
    }

    pub fn metadata(&self) -> Result<Metadata, Error> {
        match file_op!(self get_metadata) {
            Ok(data) => Ok(data),
            Err(e)   => Err(to_err(FileError::new(e.kind(), &self.path)))
        }
    }

    pub fn get_file_size(&mut self) -> Result<u64, Error> {
        let cur_pos = self.cur_pos()?;

        let last_pos = self.seek(SeekFrom::End(0))?;

        self.seek(SeekFrom::Start(cur_pos))?;

        Ok(last_pos)
    }
}