use internal::*;
use self::ProducerState::*;
use std::fs::File;
use std::path::Path;
use std::num::Int;
use std::io;
use std::io::{Read,Seek,SeekFrom};
#[derive(Debug,PartialEq,Eq)]
pub enum ProducerState<O> {
Eof(O),
Continue,
Data(O),
ProducerError(Err),
}
pub trait Producer {
fn produce(&mut self) -> ProducerState<&[u8]>;
fn seek(&mut self, position:SeekFrom) -> Option<u64>;
}
pub struct FileProducer {
size: usize,
file: File,
v: Vec<u8>
}
impl FileProducer {
pub fn new(filename: &str, buffer_size: usize) -> io::Result<FileProducer> {
File::open(&Path::new(filename)).map(|f| {
FileProducer {size: buffer_size, file: f, v: Vec::with_capacity(buffer_size)}
})
}
}
impl Producer for FileProducer {
fn produce(&mut self) -> ProducerState<&[u8]> {
self.v.resize(self.size, 0);
match self.file.read(&mut self.v) {
Err(e) => {
match e.kind() {
_ => ProducerError(0)
}
},
Ok(n) => {
self.v.truncate(n);
if n == 0 {
Eof(&self.v[..])
} else {
Data(&self.v[..])
}
}
}
}
fn seek(&mut self, position: SeekFrom) -> Option<u64> {
self.file.seek(position).ok()
}
}
pub struct MemProducer<'x> {
buffer: &'x [u8],
chunk_size: usize,
length: usize,
index: usize
}
impl<'x> MemProducer<'x> {
pub fn new(buffer: &'x[u8], chunk_size: usize) -> MemProducer {
MemProducer {
buffer: buffer,
chunk_size: chunk_size,
length: buffer.len(),
index: 0
}
}
}
impl<'x> Producer for MemProducer<'x> {
fn produce(&mut self) -> ProducerState<&[u8]> {
if self.index + self.chunk_size < self.length {
let new_index = self.index+self.chunk_size;
let res = Data(&self.buffer[self.index..new_index]);
self.index = new_index;
res
} else if self.index < self.length {
let res = Eof(&self.buffer[self.index..self.length]);
self.index = self.length;
res
} else {
ProducerError(0)
}
}
fn seek(&mut self, position: SeekFrom) -> Option<u64> {
match position {
SeekFrom::Start(pos) => {
if pos as usize > self.length {
self.index = self.length
} else {
self.index = pos as usize
}
Some(self.index as u64)
},
SeekFrom::Current(offset) => {
let next = if offset >= 0 {
(self.index as u64).checked_add(offset as u64)
} else {
(self.index as u64).checked_sub(-offset as u64)
};
match next {
None => None,
Some(u) => {
if u as usize > self.length {
self.index = self.length
} else {
self.index = u as usize
}
Some(self.index as u64)
}
}
},
SeekFrom::End(pos) => {
panic!("SeekFrom::End not implemented");
}
}
}
}
#[macro_export]
macro_rules! pusher (
($name:ident, $f:expr) => (
#[allow(unused_variables)]
fn $name(producer: &mut Producer) {
let mut acc: Vec<u8> = Vec::new();
loop {
let state = producer.produce();
match state {
ProducerState::Data(v) => {
acc.push_all(v)
},
ProducerState::Eof([]) => {
break;
}
ProducerState::Eof(v) => {
acc.push_all(v)
}
_ => {break;}
}
let mut v2: Vec<u8> = Vec::new();
v2.push_all(acc.as_slice());
match $f(v2.as_slice()) {
IResult::Error(e) => {
break;
},
IResult::Incomplete(_) => {
},
IResult::Done(i, _) => {
acc.clear();
acc.push_all(i);
}
}
}
}
);
);
#[cfg(test)]
mod tests {
use super::*;
use internal::IResult;
use internal::IResult::*;
use std::fmt::Debug;
use std::str;
use map::*;
fn local_print<'a,T: Debug>(input: T) -> IResult<T, ()> {
println!("{:?}", input);
Done(input, ())
}
#[test]
fn mem_producer() {
let mut p = MemProducer::new("abcdefgh".as_bytes(), 4);
assert_eq!(p.produce(), ProducerState::Data("abcd".as_bytes()));
}
#[test]
fn mem_producer_2() {
let mut p = MemProducer::new("abcdefgh".as_bytes(), 8);
fn pr<'a,'b>(data: &'a [u8]) -> IResult<&'a [u8],()> {
local_print(data)
}
pusher!(ps, pr);
ps(&mut p);
}
#[test]
#[allow(unused_must_use)]
fn file() {
FileProducer::new("links.txt", 20).map(|producer: FileProducer| {
let mut p = producer;
fn pr<'a,'b,'c>(data: &[u8]) -> IResult<&[u8], &[u8]> {
Done("".as_bytes(), data).map_res(str::from_utf8); Done("".as_bytes(),"".as_bytes())
}
pusher!(ps, pr);
ps(&mut p);
});
}
#[test]
fn accu() {
fn f(input:&[u8]) -> IResult<&[u8],&[u8]> {
if input.len() <= 4 {
Incomplete(0)
} else {
Done("".as_bytes(), input)
}
}
let mut p = MemProducer::new("abcdefgh".as_bytes(), 4);
fn pr<'a,'b>(data: &'b [u8]) -> IResult<&'b [u8],&'b [u8]> {
let r = f(data);
println!("f: {:?}", r);
r
}
pusher!(ps, pr );
ps(&mut p);
}
#[test]
fn accu_2() {
fn f(input:&[u8]) -> IResult<&[u8],&[u8]> {
if input.len() <= 4 || &input[0..5] != "abcde".as_bytes() {
Incomplete(0)
} else {
Done(&input[5..], &input[0..5])
}
}
let mut p = MemProducer::new("abcdefgh".as_bytes(), 4);
fn pr<'a,'b,'c>(data: &'b [u8]) -> IResult<&'b [u8],&'b [u8]> {
let r = f(data);
println!("f: {:?}", r);
r
}
pusher!(ps, pr );
ps(&mut p);
}
}