combine/stream/
position.rs

1use crate::{
2    error::{ParseError, ParseResult, StreamError},
3    lib::fmt,
4    stream::{
5        IteratorStream, Positioned, RangeStreamOnce, ResetStream, SliceStream, StreamErrorFor,
6        StreamOnce,
7    },
8};
9
10#[cfg(feature = "std")]
11use crate::stream::read;
12
13/// Trait for tracking the current position of a `Stream`.
14pub trait Positioner<Item> {
15    /// The type which keeps track of the position
16    type Position: Clone + Ord;
17
18    type Checkpoint: Clone;
19
20    /// Returns the current position
21    fn position(&self) -> Self::Position;
22    /// Updates the position given that `token` has been taken from the stream
23    fn update(&mut self, token: &Item);
24
25    fn checkpoint(&self) -> Self::Checkpoint;
26    fn reset(&mut self, checkpoint: Self::Checkpoint);
27}
28
29/// Trait for tracking the current position of a `RangeStream`.
30pub trait RangePositioner<Item, Range>: Positioner<Item> {
31    /// Updates the position given that `range` has been taken from the stream
32    fn update_range(&mut self, range: &Range);
33}
34
35/// Defines a default `Positioner` type for a particular `Stream` type.
36pub trait DefaultPositioned {
37    type Positioner: Default;
38}
39
40impl<'a> DefaultPositioned for &'a str {
41    type Positioner = SourcePosition;
42}
43
44impl<'a, T> DefaultPositioned for &'a [T] {
45    type Positioner = IndexPositioner;
46}
47
48impl<'a, T> DefaultPositioned for SliceStream<'a, T> {
49    type Positioner = IndexPositioner;
50}
51
52impl<T> DefaultPositioned for IteratorStream<T> {
53    type Positioner = IndexPositioner;
54}
55
56#[cfg(feature = "std")]
57impl<R> DefaultPositioned for read::Stream<R> {
58    type Positioner = IndexPositioner;
59}
60
61/// The `Stream<Input>` struct maintains the current position in the stream `Input` using
62/// the `Positioner` trait to track the position.
63///
64/// ```
65/// # #![cfg(feature = "std")]
66/// # extern crate combine;
67/// # use combine::*;
68/// # use combine::stream::easy;
69/// # use combine::stream::position;
70/// # fn main() {
71///     let result = token(b'9')
72///         .message("Not a nine")
73///         .easy_parse(position::Stream::new(&b"8"[..]));
74///     assert_eq!(result, Err(easy::Errors {
75///         position: 0,
76///         errors: vec![
77///             easy::Error::Unexpected(b'8'.into()),
78///             easy::Error::Expected(b'9'.into()),
79///             easy::Error::Message("Not a nine".into())
80///         ]
81///     }));
82/// # }
83/// ```
84#[derive(Clone, Debug, PartialEq)]
85pub struct Stream<Input, X> {
86    /// The input stream used when items are requested
87    pub input: Input,
88    /// The positioner used to update the current position
89    pub positioner: X,
90}
91
92impl<Input, X> Stream<Input, X>
93where
94    Input: StreamOnce,
95    X: Positioner<Input::Token>,
96{
97    /// Creates a new `Stream<Input, X>` from an input stream and a positioner.
98    pub fn with_positioner(input: Input, positioner: X) -> Stream<Input, X> {
99        Stream { input, positioner }
100    }
101}
102
103impl<Input> Stream<Input, Input::Positioner>
104where
105    Input: StreamOnce + DefaultPositioned,
106    Input::Positioner: Positioner<Input::Token>,
107{
108    /// Creates a new `Stream<Input, X>` from an input stream and its default positioner.
109    pub fn new(input: Input) -> Stream<Input, Input::Positioner> {
110        Stream::with_positioner(input, Input::Positioner::default())
111    }
112}
113
114impl<Input, X, S> Positioned for Stream<Input, X>
115where
116    Input: StreamOnce,
117    X: Positioner<Input::Token>,
118    S: StreamError<Input::Token, Input::Range>,
119    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
120    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
121{
122    #[inline]
123    fn position(&self) -> Self::Position {
124        self.positioner.position()
125    }
126}
127
128impl<Input, X, S> StreamOnce for Stream<Input, X>
129where
130    Input: StreamOnce,
131    X: Positioner<Input::Token>,
132    S: StreamError<Input::Token, Input::Range>,
133    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
134    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
135{
136    type Token = Input::Token;
137    type Range = Input::Range;
138    type Position = X::Position;
139    type Error = Input::Error;
140
141    #[inline]
142    fn uncons(&mut self) -> Result<Input::Token, StreamErrorFor<Self>> {
143        self.input.uncons().map(|c| {
144            self.positioner.update(&c);
145            c
146        })
147    }
148
149    fn is_partial(&self) -> bool {
150        self.input.is_partial()
151    }
152}
153
154impl<Item, T> Positioner<Item> for &'_ mut T
155where
156    Item: Clone,
157    T: ?Sized + Positioner<Item>,
158{
159    type Position = T::Position;
160    type Checkpoint = T::Checkpoint;
161
162    #[inline]
163    fn position(&self) -> T::Position {
164        (**self).position()
165    }
166
167    #[inline]
168    fn update(&mut self, item: &Item) {
169        (**self).update(item)
170    }
171
172    #[inline]
173    fn checkpoint(&self) -> Self::Checkpoint {
174        (**self).checkpoint()
175    }
176
177    #[inline]
178    fn reset(&mut self, checkpoint: Self::Checkpoint) {
179        (**self).reset(checkpoint)
180    }
181}
182
183impl<Item, Range, T> RangePositioner<Item, Range> for &'_ mut T
184where
185    Item: Clone,
186    Range: Clone + crate::stream::Range,
187    T: ?Sized + RangePositioner<Item, Range>,
188{
189    fn update_range(&mut self, range: &Range) {
190        (**self).update_range(range);
191    }
192}
193
194/// The `IndexPositioner<Item, Range>` struct maintains the current index into the stream `Input`.  The
195/// initial index is index 0.  Each `Item` committed increments the index by 1; each `range` committed
196/// increments the position by `range.len()`.
197#[derive(Clone, Debug, Default, PartialEq)]
198pub struct IndexPositioner(usize);
199
200impl<Item> Positioner<Item> for IndexPositioner
201where
202    Item: Clone,
203{
204    type Position = usize;
205    type Checkpoint = Self;
206
207    #[inline]
208    fn position(&self) -> usize {
209        self.0
210    }
211
212    #[inline]
213    fn update(&mut self, _item: &Item) {
214        self.0 += 1
215    }
216
217    #[inline]
218    fn checkpoint(&self) -> Self::Checkpoint {
219        self.clone()
220    }
221
222    #[inline]
223    fn reset(&mut self, checkpoint: Self::Checkpoint) {
224        *self = checkpoint;
225    }
226}
227
228impl IndexPositioner {
229    pub fn new() -> IndexPositioner {
230        IndexPositioner::new_with_position(0)
231    }
232
233    pub fn new_with_position(position: usize) -> IndexPositioner {
234        IndexPositioner(position)
235    }
236}
237
238impl<Item, Range> RangePositioner<Item, Range> for IndexPositioner
239where
240    Item: Clone,
241    Range: Clone + crate::stream::Range,
242{
243    fn update_range(&mut self, range: &Range) {
244        self.0 += range.len()
245    }
246}
247
248/// Struct which represents a position in a source file.
249#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
250pub struct SourcePosition {
251    /// Current line of the input
252    pub line: i32,
253    /// Current column of the input
254    pub column: i32,
255}
256
257impl Default for SourcePosition {
258    fn default() -> Self {
259        SourcePosition { line: 1, column: 1 }
260    }
261}
262
263impl fmt::Display for SourcePosition {
264    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265        write!(f, "line: {}, column: {}", self.line, self.column)
266    }
267}
268
269impl SourcePosition {
270    pub fn new() -> Self {
271        SourcePosition::default()
272    }
273}
274
275impl Positioner<char> for SourcePosition {
276    type Position = SourcePosition;
277    type Checkpoint = Self;
278
279    #[inline]
280    fn position(&self) -> SourcePosition {
281        *self
282    }
283
284    #[inline]
285    fn update(&mut self, token: &char) {
286        self.column += 1;
287        if *token == '\n' {
288            self.column = 1;
289            self.line += 1;
290        }
291    }
292
293    #[inline]
294    fn checkpoint(&self) -> Self::Checkpoint {
295        *self
296    }
297
298    #[inline]
299    fn reset(&mut self, checkpoint: Self::Checkpoint) {
300        *self = checkpoint;
301    }
302}
303
304impl Positioner<u8> for SourcePosition {
305    type Position = SourcePosition;
306    type Checkpoint = Self;
307
308    #[inline]
309    fn position(&self) -> SourcePosition {
310        *self
311    }
312
313    #[inline]
314    fn update(&mut self, token: &u8) {
315        self.column += 1;
316        if *token == b'\n' {
317            self.column = 1;
318            self.line += 1;
319        }
320    }
321
322    #[inline]
323    fn checkpoint(&self) -> Self::Checkpoint {
324        *self
325    }
326
327    #[inline]
328    fn reset(&mut self, checkpoint: Self::Checkpoint) {
329        *self = checkpoint;
330    }
331}
332
333impl<'a> RangePositioner<char, &'a str> for SourcePosition {
334    fn update_range(&mut self, range: &&'a str) {
335        for c in range.chars() {
336            self.update(&c);
337        }
338    }
339}
340
341impl<Input, X, S> RangeStreamOnce for Stream<Input, X>
342where
343    Input: RangeStreamOnce,
344    X: RangePositioner<Input::Token, Input::Range>,
345    S: StreamError<Input::Token, Input::Range>,
346    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
347    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
348    Input::Position: Clone + Ord,
349{
350    #[inline]
351    fn uncons_range(&mut self, size: usize) -> Result<Input::Range, StreamErrorFor<Self>> {
352        self.input.uncons_range(size).map(|range| {
353            self.positioner.update_range(&range);
354            range
355        })
356    }
357
358    #[inline]
359    fn uncons_while<F>(&mut self, mut predicate: F) -> Result<Input::Range, StreamErrorFor<Self>>
360    where
361        F: FnMut(Input::Token) -> bool,
362    {
363        let positioner = &mut self.positioner;
364        self.input.uncons_while(|t| {
365            if predicate(t.clone()) {
366                positioner.update(&t);
367                true
368            } else {
369                false
370            }
371        })
372    }
373
374    #[inline]
375    fn uncons_while1<F>(
376        &mut self,
377        mut predicate: F,
378    ) -> ParseResult<Self::Range, StreamErrorFor<Self>>
379    where
380        F: FnMut(Self::Token) -> bool,
381    {
382        let positioner = &mut self.positioner;
383        self.input.uncons_while1(|t| {
384            if predicate(t.clone()) {
385                positioner.update(&t);
386                true
387            } else {
388                false
389            }
390        })
391    }
392
393    #[inline]
394    fn distance(&self, end: &Self::Checkpoint) -> usize {
395        self.input.distance(&end.input)
396    }
397
398    fn range(&self) -> Self::Range {
399        self.input.range()
400    }
401}
402
403impl<Input, X, S> ResetStream for Stream<Input, X>
404where
405    Input: ResetStream,
406    X: Positioner<Input::Token>,
407    S: StreamError<Input::Token, Input::Range>,
408    Input::Error: ParseError<Input::Token, Input::Range, X::Position, StreamError = S>,
409    Input::Error: ParseError<Input::Token, Input::Range, Input::Position, StreamError = S>,
410{
411    type Checkpoint = Stream<Input::Checkpoint, X::Checkpoint>;
412    fn checkpoint(&self) -> Self::Checkpoint {
413        Stream {
414            input: self.input.checkpoint(),
415            positioner: self.positioner.checkpoint(),
416        }
417    }
418    fn reset(&mut self, checkpoint: Self::Checkpoint) -> Result<(), Self::Error> {
419        self.input.reset(checkpoint.input)?;
420        self.positioner.reset(checkpoint.positioner);
421        Ok(())
422    }
423}
424
425#[cfg(all(feature = "std", test))]
426mod tests {
427
428    use crate::Parser;
429
430    use super::*;
431
432    #[test]
433    fn test_positioner() {
434        let input = ["a".to_string(), "b".to_string()];
435        let mut parser = crate::any();
436        let result = parser.parse(Stream::new(&input[..]));
437        assert_eq!(
438            result,
439            Ok((
440                "a".to_string(),
441                Stream::with_positioner(
442                    &["b".to_string()][..],
443                    IndexPositioner::new_with_position(1)
444                )
445            ))
446        );
447    }
448
449    #[test]
450    fn test_range_positioner() {
451        let input = ["a".to_string(), "b".to_string(), "c".to_string()];
452        let mut parser = crate::parser::range::take(2);
453        let result = parser.parse(Stream::new(&input[..]));
454        assert_eq!(
455            result,
456            Ok((
457                &["a".to_string(), "b".to_string()][..],
458                Stream::with_positioner(
459                    &["c".to_string()][..],
460                    IndexPositioner::new_with_position(2)
461                )
462            ))
463        );
464    }
465}