I am trying to make the Iteratee
structure generic so I can pass in a different parsing function and get an different Iteratee
. This is the non-generic version that works:
use std::io::{BufRead, BufReader};
use std::str::{from_utf8, Utf8Error};
#[derive(PartialEq, Debug)]
struct Cat<'a> {
name: &'a str,
}
fn parse<'a>(slice: &'a [u8]) -> Result<Cat<'a>, Utf8Error> {
from_utf8(slice).map(|name| Cat { name: name })
}
struct Iteratee<R>
where R: BufRead + Sized
{
read: R,
}
impl<R> Iteratee<R>
where R: BufRead + Sized
{
fn next<'a, F>(&'a mut self, fun: F)
where F: Fn(Option<Result<Cat<'a>, Utf8Error>>) -> () + Sized
{
let slice = self.read.fill_buf().unwrap();
fun(Some(parse(slice)))
// ^^^^^^^^^^^ How do I pull 'parse' up as a function of Iteratee
}
}
fn main() {
let data = &b"felix"[..];
let read = BufReader::new(data);
let mut iterator = Iteratee { read: read };
iterator.next(|cat| assert_eq!(cat.unwrap().unwrap(), Cat { name: "felix" }));
}
This is my attempt at making it generic, but I can't construct IterateeFun
with either a reference to the function or passing in a closure.
struct IterateeFun<R, P, T>
where R: BufRead + Sized,
P: Fn(&[u8]) -> (Result<T, Utf8Error>) + Sized
{
read: R,
parser: P,
}
impl<R, P, T> IterateeFun<R, P, T>
where R: BufRead + Sized,
P: Fn(&[u8]) -> (Result<T, Utf8Error>) + Sized
{
fn next<'a, F>(&'a mut self, fun: F)
where F: Fn(Option<Result<T, Utf8Error>>) -> () + Sized
{
let slice = self.read.fill_buf().unwrap();
fun(Some((self.parser)(slice)))
}
}
fn main() {
let data = &b"felix"[..];
let read = BufReader::new(data);
let mut iterator = IterateeFun {
read: read,
parser: parse, // What can I put here?
// I've tried a closure but then I get error[E0495]/ lifetime issues
};
iterator.next(|cat| assert_eq!(cat.unwrap().unwrap(), Cat { name: "felix" }));
}
I'd like to know how to pass a function into a structure as shown. Or should I be doing this as a trait instead?