Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ForEach macro/method/function to make it easier to use Stream #7

Open
m4rw3r opened this issue Nov 23, 2015 · 0 comments
Open

ForEach macro/method/function to make it easier to use Stream #7

m4rw3r opened this issue Nov 23, 2015 · 0 comments

Comments

@m4rw3r
Copy link
Owner

m4rw3r commented Nov 23, 2015

Problem

Cannot use a normal for loop with Source or Stream, the Iterator interface is not compatible with either.

Preferably there should be a for_each method on the Stream trait:

pub trait Stream<'a, 'i> {
    type Item: 'i;

    fn for_each<P, F, T, E>(&'a mut self, mut parser: P, mut body: F)
      where P: FnMut(Input<'i, Self::Item>) -> ParseResult<'i, Self::Item, T, E>,
            F: FnMut(T),
            T: 'i,
            E: 'i;
}

NOTE: Does not work as written above.

Design considerations

The current stream implementation necessitates a mutable borrow for each iteration, since Source might need to fill/reallocate/move data in the internal buffer as well as modify the state of the reader. This makes each return value from Stream::parse prevent any more attempts to parse data until after the first return value has gone out of scope.

Copy types or cloning circumvents this, but then we are not doing zero-copy parsing, and the signature cannot be very general either.

let a = iterator.next();
let b = iterator.next();
println!("a: {:?}, b: {:?}", a, b);

vs:

{
    let a = stream.parse(my_parser);

    print!("a: {:?},", a);
}
{
    let b = stream.parse(my_parser);

    println!("b: {:?},", b);
}

Function calls are also an issue, any call passing stream-data to a generic closure will borrow the return from Stream::parse until the variable storing the function goes out of scope which also borrows the stream itself. This prevents any attempt to write a function or method managing this.

Macro

Writing it as a macro has a few merits, it will avoid most of the issues with generics as all types are known.

The issue with macros is that sometimes some function-calls still cause issues with borrowck, and the panic! macro is among them. So no exit of the loop using panic! with a dump of the error (ParseError carries a reference to the input buffer and panic! seems to be borrowing that for the rest of the function, making it impossible to loop.

The macro also needs to be aware of the autofill feature of any possible Stream, if it needs to invoke a method causing it to prepare more data for the parser (of course the user has to want it to automatically fill itself while looping).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant