1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#![feature(assert_matches)]
#![feature(associated_type_defaults)]
#![feature(str_internals)]

use repeatable::Repeatable;

mod byte_stream;
mod extract_byte;
mod extract_utf8;
mod iterable;
mod repeatable;
mod tuple;

#[cfg(test)]
mod tests;

pub use self::byte_stream::ByteStream;
pub use self::extract_byte::byte;
pub use self::iterable::{Collectable, Mappable};
pub use self::tuple::ExtractTuple;

pub enum ParseResult<State, Output> {
    NoMatch,
    Partial(State),
    Match(Output, ByteStream),
}

impl<State, Output> std::fmt::Debug for ParseResult<State, Output> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::NoMatch => write!(f, "NoMatch"),
            Self::Partial(_arg0) => write!(f, "Partial"),
            Self::Match(_arg0, _arg1) => write!(f, "Match"),
        }
    }
}

/// A trait to extract a type from a `ByteStream`. The `extract` method is initially called with a
/// state of `None`. If the type is extracted fully, the method returns `ParseResult::Match` with
/// the extracted type and the remaining `ByteStream`. If the type cannot be extracted because it
/// does not match, the `ParseResult::NoMatch` is returned. If the extraction reads to the end of
/// the `ByteStream` but needs more data to extract the type it returns `ParseResult::Partial` with
/// a state. The next call to `extract` with a new `ByteStream` must pass in the returned state to
/// continue parsing the type. If the end of the stream is reached while the state is `Partial` call
/// `stop` with the state as some extractors can return `ParseResult::Match` in this case. e.g.
/// `'a'.repeated(2..5)` will return Partial for "aaa" since it may be part of a longer pattern, but
/// on end of stream, will return the 3 characters as a match.
pub trait Extract {
    type State;
    type Output = ByteStream;

    fn extract(
        &self,
        input: ByteStream,
        state: Option<Self::State>,
        last: bool,
    ) -> ParseResult<Self::State, Self::Output>;
}

impl<T> Extract for &T
where
    T: Extract,
{
    type State = T::State;

    type Output = T::Output;

    fn extract(
        &self,
        input: ByteStream,
        state: Option<Self::State>,
        last: bool,
    ) -> ParseResult<Self::State, Self::Output> {
        (*self).extract(input, state, last)
    }
}
pub trait ParseAny {
    type Parser: Extract;

    fn any() -> Self::Parser;
}

pub trait ParseWhen<T, F>
where
    F: Fn(T) -> bool,
{
    type Parser: Extract;

    fn when(f: F) -> Self::Parser;
}