use util::HexDisplay;
use internal::*;
use self::ProducerState::*;
use std::old_io::fs::File;
use std::old_io::{IoResult, IoErrorKind};
#[derive(Debug,PartialEq,Eq)]
pub enum ProducerState<O> {
Eof(O),
Continue,
Data(O),
ProducerError(Err),
}
pub trait Producer {
fn produce(&mut self) -> ProducerState<&[u8]>;
}
pub struct FileProducer {
size: usize,
file: File,
v: Vec<u8>
}
impl FileProducer {
pub fn new(filename: &str, buffer_size: usize) -> IoResult<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.clear();
match self.file.push(self.size, &mut self.v) {
Err(e) => {
match e.kind {
IoErrorKind::NoProgress => Continue,
IoErrorKind::EndOfFile => Eof(&self.v[]),
_ => ProducerError(0)
}
},
Ok(i) => {
Data(&self.v[])
}
}
}
}
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 {
println!("self.index + {} < self.length", self.chunk_size);
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 {
println!("self.index < self.length - 1");
let res = Eof(&self.buffer[self.index..self.length]);
self.index = self.length;
res
} else {
ProducerError(0)
}
}
}
#[macro_export]
macro_rules! pusher (
($name:ident, $f:expr) => (
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<'a,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<'b,&'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<'b,&[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,&'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,&'b [u8],&'b [u8]> {
let r = f(data);
println!("f: {:?}", r);
r
}
pusher!(ps, pr );
ps(&mut p);
}
}