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

token and SliceStream do not play together well #74

Closed
ncalexan opened this issue Jan 5, 2017 · 2 comments
Closed

token and SliceStream do not play together well #74

ncalexan opened this issue Jan 5, 2017 · 2 comments

Comments

@ncalexan
Copy link
Contributor

ncalexan commented Jan 5, 2017

First, thanks for the library. It's a fun way to learn Rust!

I'd like to understand some of the API decisions the library makes. First, my motivating use case is to parse a token stream (not a character stream), and my token's do not implement Copy because they include String data, like:

struct Token {
    Keyword(String),
    ...
}

If I use SliceStream, I can parse &[Token]. However, I can't really use token, because the Item type of SliceStream is &'a Token and that's not something I can create with the correct lifetime. It seems to me like token should have where Item : Clone and explicitly .clone() it's argument. I see at https://github.com/Marwes/combine/blob/master/src/combinator.rs#L200 that we can't actually parse without Item : Clone.

Is this deliberate? Oversight? Am I using SliceStream incorrectly?

@Marwes
Copy link
Owner

Marwes commented Jan 6, 2017

The reason for the Clone bound is that combine assumes that Stream is a type that can be cloned (which is necessary for the or parser which implements alternation). Since Stream can be cloned it follows that its tokens must be cloneable as well (any token that does not implement Clone could still be duplicated by cloning the stream stream.uncons().clone() vs stream.clone().uncons() so there is no reason that they would not be possible to clone). If we then also assume that streams and tokens are cheap to clone (if they were expensive to clone then parsing would be slow) then it follows that the predicates might as well take Item instead of &Item as it is much more convenient in common cases such as Item = u8 or Item = char.

That was my reasoning in any case :).

As for the lifetime problem, that is not something I had considered actually. I can't think of anyway to make token available for that case as the token requires exactly the Item type since that is used to construct the error message if the parser fails

error.errors.push(Error::Expected(Info::Token(self.c.clone())));
. Using the the satisfy parser instead should work though.

@Marwes
Copy link
Owner

Marwes commented Jan 6, 2017

Reasoning for Copy #44

ncalexan added a commit to ncalexan/combine that referenced this issue Jan 6, 2017
Clone is a super-type of Copy, so everything that implements Copy
already implements Clone.  Therefore, this is strictly more general.
In addition, .clone() on things that implement Copy should be
inlined (to `return *self`) and essentially zero cost.  And per
Marwes#74 (comment),
.clone() already be fast in order for parsing to be fast, so the
performance assumptions in the non-Copy case should be similar.
ncalexan added a commit to ncalexan/combine that referenced this issue Jan 6, 2017
Parser is defined for Token<I> only when I::Item: Clone, so there's no
functional loss of generality when we restrict token() to only
I::Item: Clone.  The cost of .clone() should be negligible.

With this, we can use token() with a StreamSlice.
ncalexan added a commit to ncalexan/combine that referenced this issue Jan 6, 2017
…arwes#74.

This test verifies we can use token() with a StreamSlice.
@Marwes Marwes closed this as completed in 1004cbe Jan 6, 2017
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

2 participants