Skip to main content

winnow/stream/
partial.rs

1use crate::stream::AsBStr;
2use crate::stream::AsBytes;
3use crate::stream::Checkpoint;
4use crate::stream::Compare;
5use crate::stream::CompareResult;
6use crate::stream::FindSlice;
7use crate::stream::Location;
8use crate::stream::Needed;
9use crate::stream::Offset;
10#[cfg(feature = "unstable-recover")]
11#[cfg(feature = "std")]
12use crate::stream::Recover;
13use crate::stream::SliceLen;
14use crate::stream::Stream;
15use crate::stream::StreamIsPartial;
16use crate::stream::UpdateSlice;
17
18/// Mark the input as a partial buffer for streaming input.
19///
20/// Complete input means that we already have all of the data. This will be the common case with
21/// small files that can be read entirely to memory.
22///
23/// In contrast, streaming input assumes that we might not have all of the data.
24/// This can happen with some network protocol or large file parsers, where the
25/// input buffer can be full and need to be resized or refilled.
26/// - [`ErrMode::Incomplete`][crate::error::ErrMode::Incomplete] will report how much more data is needed.
27/// - [`Parser::complete_err`][crate::Parser::complete_err] transform
28///   [`ErrMode::Incomplete`][crate::error::ErrMode::Incomplete] to
29///   [`ErrMode::Backtrack`][crate::error::ErrMode::Backtrack]
30///
31/// See also [`StreamIsPartial`] to tell whether the input supports complete or partial parsing.
32///
33/// See also [Special Topics: Parsing Partial Input][crate::_topic::partial].
34///
35/// # Example
36///
37/// Here is how it works in practice:
38///
39/// ```rust
40/// # #[cfg(feature = "ascii")] {
41/// # use winnow::{Result, error::ErrMode, error::Needed, error::ContextError, token, ascii, stream::Partial};
42/// # use winnow::prelude::*;
43///
44/// fn take_partial<'s>(i: &mut Partial<&'s [u8]>) -> ModalResult<&'s [u8], ContextError> {
45///   token::take(4u8).parse_next(i)
46/// }
47///
48/// fn take_complete<'s>(i: &mut &'s [u8]) -> ModalResult<&'s [u8], ContextError> {
49///   token::take(4u8).parse_next(i)
50/// }
51///
52/// // both parsers will take 4 bytes as expected
53/// assert_eq!(take_partial.parse_peek(Partial::new(&b"abcde"[..])), Ok((Partial::new(&b"e"[..]), &b"abcd"[..])));
54/// assert_eq!(take_complete.parse_peek(&b"abcde"[..]), Ok((&b"e"[..], &b"abcd"[..])));
55///
56/// // if the input is smaller than 4 bytes, the partial parser
57/// // will return `Incomplete` to indicate that we need more data
58/// assert_eq!(take_partial.parse_peek(Partial::new(&b"abc"[..])), Err(ErrMode::Incomplete(Needed::new(1))));
59///
60/// // but the complete parser will return an error
61/// assert!(take_complete.parse_peek(&b"abc"[..]).is_err());
62///
63/// // the alpha0 function takes 0 or more alphabetic characters
64/// fn alpha0_partial<'s>(i: &mut Partial<&'s str>) -> ModalResult<&'s str, ContextError> {
65///   ascii::alpha0.parse_next(i)
66/// }
67///
68/// fn alpha0_complete<'s>(i: &mut &'s str) -> ModalResult<&'s str, ContextError> {
69///   ascii::alpha0.parse_next(i)
70/// }
71///
72/// // if there's a clear limit to the taken characters, both parsers work the same way
73/// assert_eq!(alpha0_partial.parse_peek(Partial::new("abcd;")), Ok((Partial::new(";"), "abcd")));
74/// assert_eq!(alpha0_complete.parse_peek("abcd;"), Ok((";", "abcd")));
75///
76/// // but when there's no limit, the partial version returns `Incomplete`, because it cannot
77/// // know if more input data should be taken. The whole input could be "abcd;", or
78/// // "abcde;"
79/// assert_eq!(alpha0_partial.parse_peek(Partial::new("abcd")), Err(ErrMode::Incomplete(Needed::new(1))));
80///
81/// // while the complete version knows that all of the data is there
82/// assert_eq!(alpha0_complete.parse_peek("abcd"), Ok(("", "abcd")));
83/// # }
84/// ```
85#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
86pub struct Partial<I> {
87    input: I,
88    partial: bool,
89}
90
91impl<I> Partial<I>
92where
93    I: StreamIsPartial,
94{
95    /// Create a partial input
96    #[inline]
97    pub fn new(input: I) -> Self {
98        debug_assert!(
99            !I::is_partial_supported(),
100            "`Partial` can only wrap complete sources"
101        );
102        let partial = true;
103        Self { input, partial }
104    }
105
106    /// Extract the original [`Stream`]
107    #[inline(always)]
108    pub fn into_inner(self) -> I {
109        self.input
110    }
111}
112
113impl<I> Default for Partial<I>
114where
115    I: Default + StreamIsPartial,
116{
117    #[inline]
118    fn default() -> Self {
119        Self::new(I::default())
120    }
121}
122
123impl<I> core::ops::Deref for Partial<I> {
124    type Target = I;
125
126    #[inline(always)]
127    fn deref(&self) -> &Self::Target {
128        &self.input
129    }
130}
131
132impl<I: core::fmt::Display> core::fmt::Display for Partial<I> {
133    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
134        self.input.fmt(f)
135    }
136}
137
138impl<I> SliceLen for Partial<I>
139where
140    I: SliceLen,
141{
142    #[inline(always)]
143    fn slice_len(&self) -> usize {
144        self.input.slice_len()
145    }
146}
147
148impl<I: Stream> Stream for Partial<I> {
149    type Token = <I as Stream>::Token;
150    type Slice = <I as Stream>::Slice;
151
152    type IterOffsets = <I as Stream>::IterOffsets;
153
154    type Checkpoint = Checkpoint<I::Checkpoint, Self>;
155
156    #[inline(always)]
157    fn iter_offsets(&self) -> Self::IterOffsets {
158        self.input.iter_offsets()
159    }
160    #[inline(always)]
161    fn eof_offset(&self) -> usize {
162        self.input.eof_offset()
163    }
164
165    #[inline(always)]
166    fn next_token(&mut self) -> Option<Self::Token> {
167        self.input.next_token()
168    }
169
170    #[inline(always)]
171    fn peek_token(&self) -> Option<Self::Token> {
172        self.input.peek_token()
173    }
174
175    #[inline(always)]
176    fn offset_for<P>(&self, predicate: P) -> Option<usize>
177    where
178        P: Fn(Self::Token) -> bool,
179    {
180        self.input.offset_for(predicate)
181    }
182    #[inline(always)]
183    fn offset_at(&self, tokens: usize) -> Result<usize, Needed> {
184        self.input.offset_at(tokens)
185    }
186    #[inline(always)]
187    fn next_slice(&mut self, offset: usize) -> Self::Slice {
188        self.input.next_slice(offset)
189    }
190    #[inline(always)]
191    unsafe fn next_slice_unchecked(&mut self, offset: usize) -> Self::Slice {
192        // SAFETY: Passing up invariants
193        unsafe { self.input.next_slice_unchecked(offset) }
194    }
195    #[inline(always)]
196    fn peek_slice(&self, offset: usize) -> Self::Slice {
197        self.input.peek_slice(offset)
198    }
199    #[inline(always)]
200    unsafe fn peek_slice_unchecked(&self, offset: usize) -> Self::Slice {
201        // SAFETY: Passing up invariants
202        unsafe { self.input.peek_slice_unchecked(offset) }
203    }
204
205    #[inline(always)]
206    fn checkpoint(&self) -> Self::Checkpoint {
207        Checkpoint::<_, Self>::new(self.input.checkpoint())
208    }
209    #[inline(always)]
210    fn reset(&mut self, checkpoint: &Self::Checkpoint) {
211        self.input.reset(&checkpoint.inner);
212    }
213
214    fn trace(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
215        self.input.trace(f)
216    }
217}
218
219impl<I> Location for Partial<I>
220where
221    I: Location,
222{
223    #[inline(always)]
224    fn previous_token_end(&self) -> usize {
225        self.input.previous_token_end()
226    }
227    #[inline(always)]
228    fn current_token_start(&self) -> usize {
229        self.input.current_token_start()
230    }
231}
232
233#[cfg(feature = "unstable-recover")]
234#[cfg(feature = "std")]
235impl<I, E> Recover<E> for Partial<I>
236where
237    I: Recover<E>,
238    I: Stream,
239{
240    #[inline(always)]
241    fn record_err(
242        &mut self,
243        _token_start: &Self::Checkpoint,
244        _err_start: &Self::Checkpoint,
245        err: E,
246    ) -> Result<(), E> {
247        Err(err)
248    }
249
250    /// Report whether the [`Stream`] can save off errors for recovery
251    #[inline(always)]
252    fn is_recovery_supported() -> bool {
253        false
254    }
255}
256
257impl<I> StreamIsPartial for Partial<I>
258where
259    I: StreamIsPartial,
260{
261    type PartialState = bool;
262
263    #[inline]
264    fn complete(&mut self) -> Self::PartialState {
265        core::mem::replace(&mut self.partial, false)
266    }
267
268    #[inline]
269    fn restore_partial(&mut self, state: Self::PartialState) {
270        self.partial = state;
271    }
272
273    #[inline(always)]
274    fn is_partial_supported() -> bool {
275        true
276    }
277
278    #[inline(always)]
279    fn is_partial(&self) -> bool {
280        self.partial
281    }
282}
283
284impl<I> Offset for Partial<I>
285where
286    I: Stream,
287{
288    #[inline(always)]
289    fn offset_from(&self, start: &Self) -> usize {
290        self.offset_from(&start.checkpoint())
291    }
292}
293
294impl<I> Offset<<Partial<I> as Stream>::Checkpoint> for Partial<I>
295where
296    I: Stream,
297{
298    #[inline(always)]
299    fn offset_from(&self, other: &<Partial<I> as Stream>::Checkpoint) -> usize {
300        self.checkpoint().offset_from(other)
301    }
302}
303
304impl<I> AsBytes for Partial<I>
305where
306    I: AsBytes,
307{
308    #[inline(always)]
309    fn as_bytes(&self) -> &[u8] {
310        self.input.as_bytes()
311    }
312}
313
314impl<I> AsBStr for Partial<I>
315where
316    I: AsBStr,
317{
318    #[inline(always)]
319    fn as_bstr(&self) -> &[u8] {
320        self.input.as_bstr()
321    }
322}
323
324impl<I, T> Compare<T> for Partial<I>
325where
326    I: Compare<T>,
327{
328    #[inline(always)]
329    fn compare(&self, t: T) -> CompareResult {
330        self.input.compare(t)
331    }
332}
333
334impl<I, T> FindSlice<T> for Partial<I>
335where
336    I: FindSlice<T>,
337{
338    #[inline(always)]
339    fn find_slice(&self, substr: T) -> Option<core::ops::Range<usize>> {
340        self.input.find_slice(substr)
341    }
342}
343
344impl<I> UpdateSlice for Partial<I>
345where
346    I: UpdateSlice,
347{
348    #[inline(always)]
349    fn update_slice(self, inner: Self::Slice) -> Self {
350        Partial {
351            input: I::update_slice(self.input, inner),
352            partial: self.partial,
353        }
354    }
355}