pub trait Parser<In, Out, E> {
    // Required method
    fn try_parse(&self, input: In) -> Res<In, Out, E>;

    // Provided methods
    fn map<F, Mapped>(self, f: F) -> Map<Self, F, Out>
       where Self: Sized,
             F: Fn(Out) -> Mapped { ... }
    fn map_err<F, M>(self, f: F) -> MapErr<Self, F, E>
       where Self: Sized,
             F: Fn(Error<E>) -> Error<M> { ... }
    fn or<P>(self, next: P) -> Or<Self, P>
       where Self: Sized { ... }
    fn when<F>(self, pred: F) -> Predicate<Self, F>
       where Self: Sized,
             F: Fn(Out) -> bool { ... }
    fn repeated<R: RepetitionArgument>(self, count: R) -> Repeat<Self, R>
       where Self: Sized { ... }
    fn optional(self) -> Optional<Self>
       where Self: Sized { ... }
    fn peeked(self) -> Peeked<Self>
       where Self: Sized { ... }
    fn not_peeked(self) -> NotPeeked<Self, Out>
       where Self: Sized { ... }
    fn and_then<F, U>(self, f: F) -> AndThen<Self, F, Out>
       where Self: Sized,
             F: Fn(Out) -> Result<U, Error<E>> { ... }
}
Expand description

A trait for parsers

A parser takes in input and either outputs a value or reports an error.

Implementing the trait

  1. Decide what types to provide for the input, output and error. For example a type that implements Parser<&str, u8, String> can accept &str as input to try_parse(), and is expected to output u8s. If an error occurs, it is reported as Error\<String\>.
  2. Implement try_parse()
  3. Use combinators.
  4. ??profit??

The Parser trait is already implemented for a couple primitive types. Check out the impl sections below for more concrete examples

Required Methods§

source

fn try_parse(&self, input: In) -> Res<In, Out, E>

Recognizes a value from the input and returns the result

Reports an error if the input could not be matched.

Provided Methods§

source

fn map<F, Mapped>(self, f: F) -> Map<Self, F, Out>where Self: Sized, F: Fn(Out) -> Mapped,

Returns a parser that maps a Parser<In, Out, E> to Parser<In, Mapped, E> by applying a function to the result of the parser if it succeeded.

use parser_compose::Parser;

let msg = "a";

let (value, _) = "a".map(str::to_ascii_uppercase).try_parse(msg).unwrap();

assert_eq!(value, "A");
source

fn map_err<F, M>(self, f: F) -> MapErr<Self, F, E>where Self: Sized, F: Fn(Error<E>) -> Error<M>,

Returns a parser that maps a Parser<In, Out, E> to Parser<In, Out, Mapped> by applying a function to the error reported by the parser if it failed.

use parser_compose::{Error, Parser};

enum MyError { Fail }

let msg = "a";

let result = "b".map_err(|_| Error::Custom(MyError::Fail)).try_parse(msg);

assert!(result.is_err());
assert!(matches!(result, Err(Error::Custom(MyError::Fail))));
source

fn or<P>(self, next: P) -> Or<Self, P>where Self: Sized,

Returns a parser that succeeds if self does. Otherwise, it’s outcome is that of next.

use  parser_compose::Parser;

let msg = "a";

let (value, _) = "1".or("a").try_parse(msg).unwrap();

assert_eq!(value, "a");
source

fn when<F>(self, pred: F) -> Predicate<Self, F>where Self: Sized, F: Fn(Out) -> bool,

Returns a new parser that succeeds if the predicate returns true. The predicate is given the extracted value of the current parser as an argument

use parser_compose::{any_str,Parser};

let msg = "boo";

let (value, _) = any_str.when(|s| s == "b").try_parse(msg).unwrap();

assert_eq!(value, "b");
source

fn repeated<R: RepetitionArgument>(self, count: R) -> Repeat<Self, R>where Self: Sized,

Returns a parser that suceeds if it is able to repeat count times.

count can be:

  • A single usize (e.g. 8): The parser will try to match at least 8 times and return a Vec of length 8 if it succeeds
use parser_compose::Parser;

let msg = "AAAA";

let (value, rest) = "A".repeated(3).try_parse(msg).unwrap();

assert_eq!(value, vec!["A", "A", "A"]);
assert_eq!(rest, "A");
  • A range bounded inclusively from below (e.g. 3..): The parser will try to match at least 3 times, but possibly more. If it succeeds, the returned Vec is be guaranteed to have a value greater than 3.
use parser_compose::Parser;

let msg = "AAAA";
let (value, rest) = "A".repeated(2..).try_parse(msg).unwrap();

assert_eq!(value, vec!["A", "A", "A", "A"]);
assert_eq!(rest, "");
  • A range bounded inclusively from above (e.g. ..=4): The parser will try to match at most 4 times, but possibly less (including zero times!). If it succeeds, the returned Vec will have at most 4 elements
use parser_compose::Parser;

let msg = "AA";
let (value, rest) = "A".repeated(..=4).try_parse(msg).unwrap();

assert_eq!(value, vec!["A", "A"]);
assert_eq!(rest, "");
  • A range bounded inclusively from above and below (e.g. 3..=5): The parser will try to match at least 3 times and at most 5 times. If it succeeds, the returned Vec will have a length between 3 and 5
use parser_compose::Parser;

let msg = "AAAA";
let (value, rest) = "A".repeated(2..=3).try_parse(msg).unwrap();

assert_eq!(value, vec!["A", "A", "A"]);
assert_eq!(rest, "A");
source

fn optional(self) -> Optional<Self>where Self: Sized,

Returns a parser always succeeds but wraps the output in an Option<Out>. If the original parser would have failed, the parser outputs a None.

use parser_compose::Parser;

let msg = "a";

let ((b, a), _) = ("b".optional(), "a").try_parse(msg).unwrap();

assert_eq!(b, None);
assert_eq!(a, "a");
source

fn peeked(self) -> Peeked<Self>where Self: Sized,

Returns a parser that succeeds or fails as normal, but never consumes any input regardless of the outcome. This can be used to look ahead.

It corresponds to the “and-predicate” operator in Parsing Expression Grammars.

use parser_compose::Parser;

// Recognize the sequence "a" followed by "b", but only if it is followed by a "c"
let a_then_b = ("a", "b", "c".peeked());

let (value, rest) = a_then_b.try_parse("abc").unwrap();
// note: the value gets recognized and returned, but it does not consume it.
assert_eq!(value, ("a", "b", "c"));
assert_eq!(rest, "c");

let result = a_then_b.try_parse("abb");
assert!(result.is_err());
source

fn not_peeked(self) -> NotPeeked<Self, Out>where Self: Sized,

Reverse of peeked(). Returns a parse that succeeds if it was not able to recognize the input and fails if it was able to.

It corresponds to the “not-predicate” operator in Parsing Expression Grammars.

use parser_compose::Parser;

// This parser matches "foo", but only if it is not followed by  "bar"
let parser = ("foo", "bar".not_peeked());

let msg = "foobar";

let result = parser.try_parse(msg);

assert!(result.is_err());

let (value, rest) = parser.try_parse("foobaz").unwrap();

assert_eq!(value, ("foo", ()));
assert_eq!(rest, "baz");
source

fn and_then<F, U>(self, f: F) -> AndThen<Self, F, Out>where Self: Sized, F: Fn(Out) -> Result<U, Error<E>>,

Returns a parser that is similar to map() in its behavior, except that the provided closure may fail, which affects the outcome of the parser.

use std::str::from_utf8;
use parser_compose::{Error,Parser};

let msg = [98].as_slice();

let (value, _) = [98].and_then(|b| {
    // converting to utf8 can fail
    from_utf8(b).map_err(|_| Error::Mismatch)
}).try_parse(msg).unwrap();

assert_eq!("b", value);

Implementations on Foreign Types§

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, P5, O5, E> Parser<In, (O0, O1, O2, O3, O4, O5), E> for (P0, P1, P2, P3, P4, P5)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>, P5: Parser<In, O5, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

fn try_parse(&self, input: In) -> Res<In, (O0, O1, O2, O3, O4, O5), E>

source§

impl<'pat, 'input, T> Parser<&'input [T], &'pat [T], ()> for &'pat [T]where T: PartialEq,

A slice is treated as a parser that tries to match itself at the start of some longer slice

The Parser trait is implemented for all slices, which all &[T] will have the try_parse() method for all T.

Calling it will try to do a prefix match of the input with the slice used as the pattern.

use parser_compose::Parser;

let msg = &['H', 'E', 'L', 'L', 'O'][..];

let (res, rest) = ['H', 'E'].as_slice().try_parse(msg).unwrap();


assert_eq!(res, &['H', 'E'][..]);
assert_eq!(rest, &['L', 'L', 'O'][..]);
source§

fn try_parse(&self, input: &'input [T]) -> Res<&'input [T], &'pat [T], ()>

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, E> Parser<In, (O0, O1, O2, O3, O4), E> for (P0, P1, P2, P3, P4)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

fn try_parse(&self, input: In) -> Res<In, (O0, O1, O2, O3, O4), E>

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, P5, O5, P6, O6, E> Parser<In, (O0, O1, O2, O3, O4, O5, O6), E> for (P0, P1, P2, P3, P4, P5, P6)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>, P5: Parser<In, O5, E>, P6: Parser<In, O6, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

fn try_parse(&self, input: In) -> Res<In, (O0, O1, O2, O3, O4, O5, O6), E>

source§

impl<In, P0, O0, P1, O1, E> Parser<In, (O0, O1), E> for (P0, P1)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

fn try_parse(&self, input: In) -> Res<In, (O0, O1), E>

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, P5, O5, P6, O6, P7, O7, P8, O8, P9, O9, E> Parser<In, (O0, O1, O2, O3, O4, O5, O6, O7, O8, O9), E> for (P0, P1, P2, P3, P4, P5, P6, P7, P8, P9)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>, P5: Parser<In, O5, E>, P6: Parser<In, O6, E>, P7: Parser<In, O7, E>, P8: Parser<In, O8, E>, P9: Parser<In, O9, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

impl<In, P0, O0, E> Parser<In, (O0,), E> for (P0,)where P0: Parser<In, O0, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

fn try_parse(&self, input: In) -> Res<In, (O0,), E>

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, P5, O5, P6, O6, P7, O7, E> Parser<In, (O0, O1, O2, O3, O4, O5, O6, O7), E> for (P0, P1, P2, P3, P4, P5, P6, P7)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>, P5: Parser<In, O5, E>, P6: Parser<In, O6, E>, P7: Parser<In, O7, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, P5, O5, P6, O6, P7, O7, P8, O8, P9, O9, P10, O10, P11, O11, E> Parser<In, (O0, O1, O2, O3, O4, O5, O6, O7, O8, O9, O10, O11), E> for (P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>, P5: Parser<In, O5, E>, P6: Parser<In, O6, E>, P7: Parser<In, O7, E>, P8: Parser<In, O8, E>, P9: Parser<In, O9, E>, P10: Parser<In, O10, E>, P11: Parser<In, O11, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

impl<In, P0, O0, P1, O1, P2, O2, E> Parser<In, (O0, O1, O2), E> for (P0, P1, P2)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

fn try_parse(&self, input: In) -> Res<In, (O0, O1, O2), E>

source§

impl<'input, 'pat> Parser<&'input str, &'pat str, ()> for &'pat str

The Parser trait is implemented for string slices, which means all &strs will have the try_parse() method.

Calling it will try to do a prefix match of the input with the &str used as the pattern.

use parser_compose::Parser;

let msg = "HELLO";

let (res, rest) = "HE".try_parse(msg).unwrap();

assert_eq!(res, "HE");
assert_eq!(rest, "LLO");
source§

fn try_parse(&self, input: &'input str) -> Res<&'input str, &'pat str, ()>

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, E> Parser<In, (O0, O1, O2, O3), E> for (P0, P1, P2, P3)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

fn try_parse(&self, input: In) -> Res<In, (O0, O1, O2, O3), E>

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, P5, O5, P6, O6, P7, O7, P8, O8, P9, O9, P10, O10, E> Parser<In, (O0, O1, O2, O3, O4, O5, O6, O7, O8, O9, O10), E> for (P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>, P5: Parser<In, O5, E>, P6: Parser<In, O6, E>, P7: Parser<In, O7, E>, P8: Parser<In, O8, E>, P9: Parser<In, O9, E>, P10: Parser<In, O10, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

source§

impl<In, P0, O0, P1, O1, P2, O2, P3, O3, P4, O4, P5, O5, P6, O6, P7, O7, P8, O8, E> Parser<In, (O0, O1, O2, O3, O4, O5, O6, O7, O8), E> for (P0, P1, P2, P3, P4, P5, P6, P7, P8)where P0: Parser<In, O0, E>, P1: Parser<In, O1, E>, P2: Parser<In, O2, E>, P3: Parser<In, O3, E>, P4: Parser<In, O4, E>, P5: Parser<In, O5, E>, P6: Parser<In, O6, E>, P7: Parser<In, O7, E>, P8: Parser<In, O8, E>,

A tuple of parsers is treated as a parser that tries its inner parsers in turn, feeding the leftover input from the first as the input to the other and so on

Calling the .try_parse() on the tuple returns a new tuple containing the extracted values.

This is implemented for tuples up to 12 items long

Implementors§

source§

impl<'input> Parser<&'input str, &'input str, ()> for AsciiStr

source§

impl<'input> Parser<&'input [u8], &'input [u8], ()> for Byte

source§

impl<In, Out, E, F> Parser<In, Out, E> for Fwhere F: Fn(In) -> Res<In, Out, E>,

The Parser trait is automatically implemented for any function with the following signature:

Fn(In) -> parser_compose::Res<In, Out, Err>

See the trait documentation for more info about the type parameters.

Let’s say you have a VecDeque<String>that you want to parse. No methods in this crate explicitly take a VecDeque<String>, but that is not a problem. All the combinators are generic over input, output and errors. So you only need to implement one parser:

use parser_compose::{Parser, Error, Res} ;
use std::collections::vec_deque::VecDeque;

// A parser that matches any string at the start of the input.
fn any_string(mut input: VecDeque<String>) -> Res<VecDeque<String>, String, ()> {
    let first = input.pop_front().ok_or(Error::Mismatch)?;
    Ok((first, input))
}

let msg = VecDeque::from([
    String::from("Hello"),
    String::from("Hello"),
    String::from("World"),
]);

// The function can be used with combinators
let parse_hellos = any_string.when(|s| s == "Hello").repeated(2);
let parse_world = any_string.when(|s| s == "World");

let ((hellos, world), rest) = (parse_hellos, parse_world).try_parse(msg).unwrap();

assert_eq!(hellos, vec!["Hello", "Hello"]);
assert_eq!(world, "World");
assert_eq!(rest, VecDeque::<String>::new());
source§

impl<In, Out, E, P1, P2> Parser<In, Out, E> for Or<P1, P2>where P1: Parser<In, Out, E>, P2: Parser<In, Out, E>, In: Clone,

source§

impl<In, Out, E, P> Parser<In, Option<Out>, E> for Optional<P>where In: Clone, P: Parser<In, Out, E>,

source§

impl<In, Out, E, P> Parser<In, Out, E> for Peeked<P>where In: Clone, P: Parser<In, Out, E>,

source§

impl<In, Out, E, P, F> Parser<In, Out, E> for Predicate<P, F>where P: Parser<In, Out, E>, F: Fn(Out) -> bool, Out: Clone,

source§

impl<In, Out, E, P, F, M> Parser<In, M, E> for Map<P, F, Out>where P: Parser<In, Out, E>, F: Fn(Out) -> M,

source§

impl<In, Out, E, P, F, M> Parser<In, Out, M> for MapErr<P, F, E>where P: Parser<In, Out, E>, F: Fn(Error<E>) -> Error<M>,

source§

impl<In, Out, E, P, F, U> Parser<In, U, E> for AndThen<P, F, Out>where P: Parser<In, Out, E>, F: Fn(Out) -> Result<U, Error<E>>,

source§

impl<In, Out, E, P, R> Parser<In, Vec<Out, Global>, E> for Repeat<P, R>where P: Parser<In, Out, E>, R: RepetitionArgument, In: Clone,