chumsky/
stream.rs

1use super::*;
2
3/// An input that dynamically pulls tokens from a cached [`Iterator`].
4///
5/// Internally, the stream will pull tokens in batches and cache the results on the heap so as to avoid invoking the
6/// iterator every time a new token is required.
7///
8/// Note: This input type should be used when the internal iterator type, `I`, is *expensive* to clone. This is usually
9/// not the case: you might find that [`IterInput`] performs better.
10pub struct Stream<I: Iterator> {
11    tokens: Vec<I::Item>,
12    iter: I,
13}
14
15impl<I: Iterator> Stream<I> {
16    /// Create a new stream from an [`Iterator`].
17    ///
18    /// # Example
19    ///
20    /// ```
21    /// # use chumsky::{prelude::*, input::Stream};
22    /// let stream = Stream::from_iter((0..10).map(|i| char::from_digit(i, 10).unwrap()));
23    ///
24    /// let parser = any::<_, extra::Err<Simple<_>>>().filter(|c: &char| c.is_ascii_digit()).repeated().collect::<String>();
25    ///
26    /// assert_eq!(parser.parse(stream).into_result().as_deref(), Ok("0123456789"));
27    /// ```
28    pub fn from_iter<J: IntoIterator<IntoIter = I>>(iter: J) -> Self {
29        Self {
30            tokens: Vec::new(),
31            iter: iter.into_iter(),
32        }
33    }
34
35    /// Box this stream, turning it into a [BoxedStream]. This can be useful in cases where your parser accepts input
36    /// from several different sources and it needs to work with all of them.
37    pub fn boxed<'a>(self) -> BoxedStream<'a, I::Item>
38    where
39        I: 'a,
40    {
41        Stream {
42            tokens: self.tokens,
43            iter: Box::new(self.iter),
44        }
45    }
46
47    /// Like [`Stream::boxed`], but yields an [`BoxedExactSizeStream`], which implements [`ExactSizeInput`].
48    pub fn exact_size_boxed<'a>(self) -> BoxedExactSizeStream<'a, I::Item>
49    where
50        I: ExactSizeIterator + 'a,
51    {
52        Stream {
53            tokens: self.tokens,
54            iter: Box::new(self.iter),
55        }
56    }
57}
58
59/// A stream containing a boxed iterator. See [`Stream::boxed`].
60pub type BoxedStream<'a, T> = Stream<Box<dyn Iterator<Item = T> + 'a>>;
61
62/// A stream containing a boxed exact-sized iterator. See [`Stream::exact_size_boxed`].
63pub type BoxedExactSizeStream<'a, T> = Stream<Box<dyn ExactSizeIterator<Item = T> + 'a>>;
64
65impl<I: Iterator> Sealed for Stream<I> {}
66impl<'src, I: Iterator + 'src> Input<'src> for Stream<I>
67where
68    I::Item: Clone,
69{
70    type Span = SimpleSpan<usize>;
71
72    type Token = I::Item;
73    type MaybeToken = I::Item;
74
75    type Cursor = usize;
76
77    type Cache = Self;
78
79    #[inline(always)]
80    fn begin(self) -> (Self::Cursor, Self::Cache) {
81        (0, self)
82    }
83
84    #[inline]
85    fn cursor_location(cursor: &Self::Cursor) -> usize {
86        *cursor
87    }
88
89    #[inline(always)]
90    unsafe fn next_maybe(
91        this: &mut Self::Cache,
92        cursor: &mut Self::Cursor,
93    ) -> Option<Self::MaybeToken> {
94        Self::next(this, cursor)
95    }
96
97    #[inline(always)]
98    unsafe fn span(_this: &mut Self::Cache, range: Range<&Self::Cursor>) -> Self::Span {
99        (*range.start..*range.end).into()
100    }
101}
102
103impl<'src, I: ExactSizeIterator + 'src> ExactSizeInput<'src> for Stream<I>
104where
105    I::Item: Clone,
106{
107    #[inline(always)]
108    unsafe fn span_from(this: &mut Self::Cache, range: RangeFrom<&Self::Cursor>) -> Self::Span {
109        (*range.start..this.tokens.len() + this.iter.len()).into()
110    }
111}
112
113impl<'src, I: Iterator + 'src> ValueInput<'src> for Stream<I>
114where
115    I::Item: Clone,
116{
117    #[inline]
118    unsafe fn next(this: &mut Self::Cache, cursor: &mut Self::Cursor) -> Option<Self::Token> {
119        // Pull new items into the vector if we need them
120        if this.tokens.len() <= *cursor {
121            this.tokens.extend((&mut this.iter).take(512));
122        }
123
124        // Get the token at the given cursor
125        this.tokens.get(*cursor).map(|tok| {
126            *cursor += 1;
127            tok.clone()
128        })
129    }
130}
131
132/// An input that dynamically pulls tokens from an [`Iterator`].
133///
134/// This input type supports rewinding by [`Clone`]-ing the iterator. It is recommended that your iterator is very
135/// cheap to clone. If this is not the case, consider using [`Stream`] instead, which caches generated tokens
136/// internally.
137pub struct IterInput<I, S> {
138    iter: I,
139    eoi: S,
140}
141
142impl<I, S> IterInput<I, S> {
143    /// Create a new [`IterInput`] with the given iterator, and end of input span.
144    pub fn new(iter: I, eoi: S) -> Self {
145        Self { iter, eoi }
146    }
147}
148
149impl<'src, I, T: 'src, S> Input<'src> for IterInput<I, S>
150where
151    I: Iterator<Item = (T, S)> + Clone + 'src,
152    S: Span + 'src,
153{
154    type Cursor = (I, usize, Option<S::Offset>);
155    type Span = S;
156
157    type Token = T;
158    type MaybeToken = T;
159
160    type Cache = S; // eoi
161
162    #[inline]
163    fn begin(self) -> (Self::Cursor, Self::Cache) {
164        ((self.iter, 0, None), self.eoi)
165    }
166
167    #[inline]
168    fn cursor_location(cursor: &Self::Cursor) -> usize {
169        cursor.1
170    }
171
172    unsafe fn next_maybe(
173        _eoi: &mut Self::Cache,
174        cursor: &mut Self::Cursor,
175    ) -> Option<Self::MaybeToken> {
176        cursor.0.next().map(|(tok, span)| {
177            cursor.1 += 1;
178            cursor.2 = Some(span.end());
179            tok
180        })
181    }
182
183    unsafe fn span(eoi: &mut Self::Cache, range: Range<&Self::Cursor>) -> Self::Span {
184        match range.start.0.clone().next() {
185            Some((_, s)) => {
186                let end = range.end.2.clone().unwrap_or_else(|| eoi.end());
187                S::new(eoi.context(), s.start()..end)
188            }
189            None => S::new(eoi.context(), eoi.end()..eoi.end()),
190        }
191    }
192}
193
194// impl<'src, I, S> ExactSizeInput<'src> for IterInput<I, S>
195// where
196//     I: Iterator<Item = (T, S)> + Clone + 'src,
197//     S: Span + 'src,
198// {
199//     #[inline(always)]
200//     unsafe fn span_from(this: &mut Self::Cache, range: RangeFrom<&Self::Cursor>) -> Self::Span {
201//         (*range.start..this.tokens.len() + cursor.0.len()).into()
202//     }
203// }
204
205impl<'src, I, T: 'src, S> ValueInput<'src> for IterInput<I, S>
206where
207    I: Iterator<Item = (T, S)> + Clone + 'src,
208    S: Span + 'src,
209{
210    #[inline]
211    unsafe fn next(this: &mut Self::Cache, cursor: &mut Self::Cursor) -> Option<Self::Token> {
212        Self::next_maybe(this, cursor)
213    }
214}
215
216#[test]
217fn map_tuple() {
218    fn parser<'src, I: Input<'src, Token = char>>() -> impl Parser<'src, I, char> {
219        just('h')
220    }
221
222    let stream = Stream::from_iter(core::iter::once(('h', 0..1))).boxed();
223    let stream = stream.map(0..10, |(t, s)| (t, s));
224
225    assert_eq!(parser().parse(stream).into_result(), Ok('h'));
226}