Coverage Report

Created: 2026-08-13 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/combine-4.6.7/src/stream/position.rs
Line
Count
Source
1
use 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")]
11
use crate::stream::read;
12
13
/// Trait for tracking the current position of a `Stream`.
14
pub 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`.
30
pub 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.
36
pub trait DefaultPositioned {
37
    type Positioner: Default;
38
}
39
40
impl<'a> DefaultPositioned for &'a str {
41
    type Positioner = SourcePosition;
42
}
43
44
impl<'a, T> DefaultPositioned for &'a [T] {
45
    type Positioner = IndexPositioner;
46
}
47
48
impl<'a, T> DefaultPositioned for SliceStream<'a, T> {
49
    type Positioner = IndexPositioner;
50
}
51
52
impl<T> DefaultPositioned for IteratorStream<T> {
53
    type Positioner = IndexPositioner;
54
}
55
56
#[cfg(feature = "std")]
57
impl<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)]
85
pub 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
92
impl<Input, X> Stream<Input, X>
93
where
94
    Input: StreamOnce,
95
    X: Positioner<Input::Token>,
96
{
97
    /// Creates a new `Stream<Input, X>` from an input stream and a positioner.
98
0
    pub fn with_positioner(input: Input, positioner: X) -> Stream<Input, X> {
99
0
        Stream { input, positioner }
100
0
    }
101
}
102
103
impl<Input> Stream<Input, Input::Positioner>
104
where
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
0
    pub fn new(input: Input) -> Stream<Input, Input::Positioner> {
110
0
        Stream::with_positioner(input, Input::Positioner::default())
111
0
    }
112
}
113
114
impl<Input, X, S> Positioned for Stream<Input, X>
115
where
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
0
    fn position(&self) -> Self::Position {
124
0
        self.positioner.position()
125
0
    }
126
}
127
128
impl<Input, X, S> StreamOnce for Stream<Input, X>
129
where
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
0
    fn uncons(&mut self) -> Result<Input::Token, StreamErrorFor<Self>> {
143
0
        self.input.uncons().map(|c| {
144
0
            self.positioner.update(&c);
145
0
            c
146
0
        })
147
0
    }
148
149
0
    fn is_partial(&self) -> bool {
150
0
        self.input.is_partial()
151
0
    }
152
}
153
154
impl<Item, T> Positioner<Item> for &'_ mut T
155
where
156
    Item: Clone,
157
    T: ?Sized + Positioner<Item>,
158
{
159
    type Position = T::Position;
160
    type Checkpoint = T::Checkpoint;
161
162
    #[inline]
163
0
    fn position(&self) -> T::Position {
164
0
        (**self).position()
165
0
    }
166
167
    #[inline]
168
0
    fn update(&mut self, item: &Item) {
169
0
        (**self).update(item)
170
0
    }
171
172
    #[inline]
173
0
    fn checkpoint(&self) -> Self::Checkpoint {
174
0
        (**self).checkpoint()
175
0
    }
176
177
    #[inline]
178
0
    fn reset(&mut self, checkpoint: Self::Checkpoint) {
179
0
        (**self).reset(checkpoint)
180
0
    }
181
}
182
183
impl<Item, Range, T> RangePositioner<Item, Range> for &'_ mut T
184
where
185
    Item: Clone,
186
    Range: Clone + crate::stream::Range,
187
    T: ?Sized + RangePositioner<Item, Range>,
188
{
189
0
    fn update_range(&mut self, range: &Range) {
190
0
        (**self).update_range(range);
191
0
    }
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)]
198
pub struct IndexPositioner(usize);
199
200
impl<Item> Positioner<Item> for IndexPositioner
201
where
202
    Item: Clone,
203
{
204
    type Position = usize;
205
    type Checkpoint = Self;
206
207
    #[inline]
208
0
    fn position(&self) -> usize {
209
0
        self.0
210
0
    }
211
212
    #[inline]
213
0
    fn update(&mut self, _item: &Item) {
214
0
        self.0 += 1
215
0
    }
216
217
    #[inline]
218
0
    fn checkpoint(&self) -> Self::Checkpoint {
219
0
        self.clone()
220
0
    }
221
222
    #[inline]
223
0
    fn reset(&mut self, checkpoint: Self::Checkpoint) {
224
0
        *self = checkpoint;
225
0
    }
226
}
227
228
impl IndexPositioner {
229
0
    pub fn new() -> IndexPositioner {
230
0
        IndexPositioner::new_with_position(0)
231
0
    }
232
233
0
    pub fn new_with_position(position: usize) -> IndexPositioner {
234
0
        IndexPositioner(position)
235
0
    }
236
}
237
238
impl<Item, Range> RangePositioner<Item, Range> for IndexPositioner
239
where
240
    Item: Clone,
241
    Range: Clone + crate::stream::Range,
242
{
243
0
    fn update_range(&mut self, range: &Range) {
244
0
        self.0 += range.len()
245
0
    }
246
}
247
248
/// Struct which represents a position in a source file.
249
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
250
pub struct SourcePosition {
251
    /// Current line of the input
252
    pub line: i32,
253
    /// Current column of the input
254
    pub column: i32,
255
}
256
257
impl Default for SourcePosition {
258
0
    fn default() -> Self {
259
0
        SourcePosition { line: 1, column: 1 }
260
0
    }
261
}
262
263
impl fmt::Display for SourcePosition {
264
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265
0
        write!(f, "line: {}, column: {}", self.line, self.column)
266
0
    }
267
}
268
269
impl SourcePosition {
270
0
    pub fn new() -> Self {
271
0
        SourcePosition::default()
272
0
    }
273
}
274
275
impl Positioner<char> for SourcePosition {
276
    type Position = SourcePosition;
277
    type Checkpoint = Self;
278
279
    #[inline]
280
0
    fn position(&self) -> SourcePosition {
281
0
        *self
282
0
    }
283
284
    #[inline]
285
0
    fn update(&mut self, token: &char) {
286
0
        self.column += 1;
287
0
        if *token == '\n' {
288
0
            self.column = 1;
289
0
            self.line += 1;
290
0
        }
291
0
    }
292
293
    #[inline]
294
0
    fn checkpoint(&self) -> Self::Checkpoint {
295
0
        *self
296
0
    }
297
298
    #[inline]
299
0
    fn reset(&mut self, checkpoint: Self::Checkpoint) {
300
0
        *self = checkpoint;
301
0
    }
302
}
303
304
impl Positioner<u8> for SourcePosition {
305
    type Position = SourcePosition;
306
    type Checkpoint = Self;
307
308
    #[inline]
309
0
    fn position(&self) -> SourcePosition {
310
0
        *self
311
0
    }
312
313
    #[inline]
314
0
    fn update(&mut self, token: &u8) {
315
0
        self.column += 1;
316
0
        if *token == b'\n' {
317
0
            self.column = 1;
318
0
            self.line += 1;
319
0
        }
320
0
    }
321
322
    #[inline]
323
0
    fn checkpoint(&self) -> Self::Checkpoint {
324
0
        *self
325
0
    }
326
327
    #[inline]
328
0
    fn reset(&mut self, checkpoint: Self::Checkpoint) {
329
0
        *self = checkpoint;
330
0
    }
331
}
332
333
impl<'a> RangePositioner<char, &'a str> for SourcePosition {
334
0
    fn update_range(&mut self, range: &&'a str) {
335
0
        for c in range.chars() {
336
0
            self.update(&c);
337
0
        }
338
0
    }
339
}
340
341
impl<Input, X, S> RangeStreamOnce for Stream<Input, X>
342
where
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
0
    fn uncons_range(&mut self, size: usize) -> Result<Input::Range, StreamErrorFor<Self>> {
352
0
        self.input.uncons_range(size).map(|range| {
353
0
            self.positioner.update_range(&range);
354
0
            range
355
0
        })
356
0
    }
357
358
    #[inline]
359
0
    fn uncons_while<F>(&mut self, mut predicate: F) -> Result<Input::Range, StreamErrorFor<Self>>
360
0
    where
361
0
        F: FnMut(Input::Token) -> bool,
362
    {
363
0
        let positioner = &mut self.positioner;
364
0
        self.input.uncons_while(|t| {
365
0
            if predicate(t.clone()) {
366
0
                positioner.update(&t);
367
0
                true
368
            } else {
369
0
                false
370
            }
371
0
        })
372
0
    }
373
374
    #[inline]
375
0
    fn uncons_while1<F>(
376
0
        &mut self,
377
0
        mut predicate: F,
378
0
    ) -> ParseResult<Self::Range, StreamErrorFor<Self>>
379
0
    where
380
0
        F: FnMut(Self::Token) -> bool,
381
    {
382
0
        let positioner = &mut self.positioner;
383
0
        self.input.uncons_while1(|t| {
384
0
            if predicate(t.clone()) {
385
0
                positioner.update(&t);
386
0
                true
387
            } else {
388
0
                false
389
            }
390
0
        })
391
0
    }
392
393
    #[inline]
394
0
    fn distance(&self, end: &Self::Checkpoint) -> usize {
395
0
        self.input.distance(&end.input)
396
0
    }
397
398
0
    fn range(&self) -> Self::Range {
399
0
        self.input.range()
400
0
    }
401
}
402
403
impl<Input, X, S> ResetStream for Stream<Input, X>
404
where
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
0
    fn checkpoint(&self) -> Self::Checkpoint {
413
0
        Stream {
414
0
            input: self.input.checkpoint(),
415
0
            positioner: self.positioner.checkpoint(),
416
0
        }
417
0
    }
418
0
    fn reset(&mut self, checkpoint: Self::Checkpoint) -> Result<(), Self::Error> {
419
0
        self.input.reset(checkpoint.input)?;
420
0
        self.positioner.reset(checkpoint.positioner);
421
0
        Ok(())
422
0
    }
423
}
424
425
#[cfg(all(feature = "std", test))]
426
mod 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
}