Function combine::parser::combinator::opaque

source ·
pub fn opaque<Input, F, O, S>(f: F) -> Opaque<F, Input, O, S>
where Input: Stream, S: Default, F: FnMut(&mut dyn FnMut(&mut dyn Parser<Input, Output = O, PartialState = S>)),
Expand description

Creates a parser from a function which takes a function that are given the actual parser. Though convoluted this makes it possible to hide the concrete parser type without Box or losing the full information about the parser as is the case of parser.

Since this hides the type this can also be useful for writing mutually recursive impl Parser parsers to break the otherwise arbitrarily large type that rustc creates internally.

If you need a more general version (that does not need trait objects) try the parser! macro.



#[derive(PartialEq, Debug)]
enum Expr {
    Number(i64),
    Pair(Box<Expr>, Box<Expr>),
}

fn expr<Input>() -> FnOpaque<Input, Expr>
where
    Input: Stream<Token = char>,
{
    opaque!(
        // `no_partial` disables partial parsing and replaces the partial state with `()`,
        // letting us avoid naming that type
        no_partial(choice((
            from_str(many1::<String, _, _>(digit()))
                .map(Expr::Number),
            (char('('), expr(), char(','), expr(), char(')'))
                .map(|(_, l, _, r, _)| Expr::Pair(Box::new(l), Box::new(r)))
        ))),
    )
}

assert_eq!(
    expr().easy_parse("123"),
    Ok((Expr::Number(123), ""))
);