winnow-rs / winnow

Making parsing a breeze
https://docs.rs/winnow
Other
572 stars 44 forks source link

Add "with_state" parser #530

Closed g-plane closed 5 months ago

g-plane commented 5 months ago

Please complete the following tasks

winnow version

0.6.8

Describe your use case

Can we add a with_state method to the Parser trait when input is Stateful? (Simliar to with_span)

Describe the solution you'd like

Here is my current implementation in my code:

struct WithState<S, O, E, P>
where
    S: Clone,
    P: Parser<Stateful<S>, O, E>,
{
    parser: P,
    s: PhantomData<S>,
    o: PhantomData<O>,
    e: PhantomData<E>,
}

impl<S, O, E, P> Parser<Stateful<S>, (O, S), E> for WithState<S, O, E, P>
where
    S: Clone,
    P: Parser<Stateful<S>, O, E>,
{
    fn parse_next(&mut self, input: &mut Stateful<S>) -> PResult<(O, S), E> {
        match self.parser.parse_next(input) {
            Ok(output) => Ok((output, input.state.clone())),
            Err(err) => Err(err),
        }
    }
}

trait ParserExtForWithState<S, O, E, P>
where
    S: Clone,
    P: Parser<Stateful<S>, O, E>,
{
    fn with_state(self) -> WithState<S, O, E, P>;
}

impl<S, O, E, P> ParserExtForWithState<S, O, E, P> for P
where
    S: Clone,
    P: Parser<Stateful<S>, O, E>,
{
    fn with_state(self) -> WithState<S, O, E, P> {
        WithState {
            parser: self,
            s: PhantomData,
            o: PhantomData,
            e: PhantomData,
        }
    }
}

This can work in most cases. However, I prefer returning the reference of the state (which is &input.state) but I'm not able to achieve that.

If we really can't return a reference, I hope the code above can be added to this library, so we can remove the ParserExtForWithState in our code.

Alternatives, if applicable

No response

Additional Context

No response

epage commented 5 months ago

So you are wanting a Parser::with_state(self) that, when parsing, returns (Output, State)?

Could you expand on the use case for why capturing an owned State during parsing is useful?

g-plane commented 5 months ago

It doesn't need to capture an owned State, but I need to read the state, for example, I use it in Parser::verify to do some checks. I tried to let it return reference of State, but I failed.

epage commented 5 months ago

Sounds like this might be the same underlying need as #231 with a different proposal? Should we merge the discussions so we focus on the broader conversation on how to solve the need, regardless of the solution?

g-plane commented 5 months ago

It can be merged.