use self::ProducerState::*;
use std::fs::File;
use std::path::Path;
use std::io;
use std::io::{Read,Seek,SeekFrom};
use std::iter::repeat;
#[derive(Debug,PartialEq,Eq)]
pub enum ProducerState<O> {
Eof(O),
Continue,
Data(O),
ProducerError(u32),
}
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]> {
let len = self.v.len();
self.v.extend(repeat(0).take(self.size - len));
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(_) => {
panic!("SeekFrom::End not implemented");
}
}
}
}
#[macro_export]
macro_rules! pusher (
($name:ident, $f:expr) => (
#[allow(unused_variables)]
fn $name(producer: &mut $crate::Producer) {
let mut acc: Vec<u8> = Vec::new();
loop {
let state = producer.produce();
match state {
$crate::ProducerState::Data(v) => {
acc.extend(v.iter().cloned())
},
$crate::ProducerState::Eof(v) => {
if v.is_empty() {
break;
} else {
acc.extend(v.iter().cloned())
}
}
_ => {break;}
}
let mut v2: Vec<u8> = Vec::new();
v2.extend(acc[..].iter().cloned());
match $f(&v2[..]) {
$crate::IResult::Error(e) => {
break;
},
$crate::IResult::Incomplete(_) => {
},
$crate::IResult::Done(i, _) => {
acc.clear();
acc.extend(i.iter().cloned());
}
}
}
}
);
);
#[cfg(test)]
mod tests {
use super::*;
use internal::{Needed,IResult};
use std::fmt::Debug;
fn local_print<'a,T: Debug>(input: T) -> IResult<'a,T, ()> {
println!("{:?}", input);
IResult::Done(input, ())
}
#[test]
fn mem_producer() {
let mut p = MemProducer::new(&b"abcdefgh"[..], 4);
assert_eq!(p.produce(), ProducerState::Data(&b"abcd"[..]));
}
#[test]
fn mem_producer_2() {
let mut p = MemProducer::new(&b"abcdefgh"[..], 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;
pusher!(ps, local_print);
ps(&mut p);
});
}
#[test]
fn accu() {
fn f(input:&[u8]) -> IResult<&[u8],&[u8]> {
if input.len() <= 4 {
IResult::Incomplete(Needed::Size(4))
} else {
IResult::Done(b"", input)
}
}
let mut p = MemProducer::new(b"abcdefgh", 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] != b"abcde" {
IResult::Incomplete(Needed::Size(4))
} else {
IResult::Done(&input[5..], &input[0..5])
}
}
let mut p = MemProducer::new(b"abcdefgh", 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);
}
}