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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
use std::ops::{Index, RangeFrom};

/// Container for input into parsers
///
/// All parsers accept a `ParserContext` as input and [_must_](crate::Res) return one if they
/// succeed.
///
/// The structure contains [whatever input is yet to be parsed](crate::ParserContext::input) as
/// well as our [absolute position within the original input](crate::ParserContext::get_position),
/// which is useful for reporting errors.
///
/// **Note**: if you are manually extracting the values from the input, you will need to update the
/// position before returning the context. An example will clarify:
///
/// ```
/// use parser_compose::{Parser, ParserContext, Res};
///
/// fn easy(ctx: ParserContext<&str>) -> Res<&str, (&str, &str)> {
///     // Here, the sequence combinator will take care of updating the context
///     // before returning if both parsers matched.
///     ("A", "B").try_parse(ctx)
/// }
///
/// fn manual(mut ctx: ParserContext<&str>) -> Res<&str, &str> {
///     let (offset, _) = ("A", "B").peek().try_parse(ctx)?;
///
///     // In some cases, you might want to manually extract the value yourself.
///     // In this contrived example, doing so lets you return a single string
///     // slice instead of a tuple.
///     let value = &ctx.input()[..offset];
///     // But make sure you update the position in the context before passing it on
///     ctx.advance_by(offset);
///
///     Ok((value, ctx))
/// }
///
/// let msg = "AB";
///
/// let (value, rest) = easy.try_parse(msg.into()).unwrap();
///
/// assert_eq!(value, ("A", "B"));
/// assert_eq!(rest.input(), "");
///
/// let (value, rest) = manual.try_parse(msg.into()).unwrap();
/// assert_eq!(value, "AB");
/// assert_eq!(rest.input(), "");
/// ```
///
/// Regular slices (i.e. `&[T]`) and string slices (i.e. `&str`) can be converted into this
/// structure by using [`ParserContext::from()`](crate::ParserContext::from), or using `.into()` in
/// contexts where the compiler can infer the type.
///
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct ParserContext<T> {
    // The full input to parse
    input: T,
    // The input length
    length: usize,
    // Our current position with the input
    position: usize,
}

impl<'i> From<&'i str> for ParserContext<&'i str> {
    fn from(value: &'i str) -> Self {
        ParserContext {
            input: value,
            length: value.len(),
            position: 0,
        }
    }
}

impl<'i, T> From<&'i [T]> for ParserContext<&'i [T]> {
    fn from(value: &'i [T]) -> Self {
        ParserContext {
            input: value,
            length: value.len(),
            position: 0,
        }
    }
}

// Note: You might be tempted to think the `Deref` trait would be cleaner to use here. However, the
// reference obtained through the `Deref` trait has the lifetime of the container. Parsers always
// accept an owned `ParserContext`, so returning a reference to it is not a allowed. We instead want
// to tell the compiler that we are returning a reference to the inner value
impl<'a, T: ?Sized> ParserContext<&'a T>
where
    T: Index<RangeFrom<usize>>,
{
    /// Returns the input being parsed. The first parser will see the entire input. Subsequent
    /// parsers will only see whatever is left to parse
    pub fn input(&self) -> &'a <T as Index<RangeFrom<usize>>>::Output {
        // This is where the magic of the `ParseContext` struct comes from. It holds the entire parse
        // input, but to individual parsers, will only appear to hold the part of the input they
        // care about.
        &self.input[self.position..]
    }
}

impl<T> ParserContext<T>
where
    T: Clone,
{
    /// Increments the input position by `count`. If there is less than `count` elements left in
    /// the input, the position will be set to the length of the input.
    ///
    /// Advancing the position affects what subsequent calls to `.input()` return
    pub fn advance_by(&mut self, count: usize) {
        let offset = if self.position + count <= self.length {
            count
        } else {
            self.length - self.position
        };

        self.position += offset;
    }
}

impl<T> ParserContext<T> {
    /// Returns `true` if this instance's position is at the end of the input
    pub fn end_of_input(&self) -> bool {
        self.position == self.length
    }

    /// Returns the current input position
    pub fn get_position(&self) -> usize {
        self.position
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_equality() {
        let str = "A";
        let ctx = ParserContext::from(str);
        assert_eq!(ctx.input(), str);
        assert_eq!(ctx.input(), "A");

        let slice = &[0, 2, 4][..];
        let ctx = ParserContext::from(slice);
        assert_eq!(ctx.input(), slice);
        assert_eq!(ctx.input(), &[0, 2, 4]);
    }

    #[test]
    fn test_deref_magic() {
        let str = "ABC";

        let mut ctx = ParserContext::from(str);

        assert_eq!(ctx.input(), "ABC");

        ctx.advance_by(1);
        assert_eq!(ctx.input(), "BC");
        assert_eq!(&ctx.input()[0..], "BC");

        ctx.advance_by(1);
        assert_eq!(ctx.input(), "C");
        assert_eq!(&ctx.input()[0..], "C");

        ctx.advance_by(1);
        assert_eq!(ctx.input(), "");
        assert_eq!(&ctx.input()[0..], "");

        ctx.advance_by(1);
        ctx.advance_by(10);
        ctx.advance_by(3);

        assert_eq!(ctx.input(), "");
        assert_eq!(&ctx.input()[0..], "");
    }
}