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