lexical_util/
iterator.rs

1//! Specialized iterator traits.
2//!
3//! The traits are for iterables containing bytes, and provide optimizations
4//! which then can be used for contiguous or non-contiguous iterables,
5//! including containers or iterators of any kind.
6
7#![cfg(any(feature = "parse-floats", feature = "parse-integers"))]
8
9use core::mem;
10
11// Re-export our digit iterators.
12#[cfg(not(feature = "format"))]
13pub use crate::noskip::{AsBytes, Bytes};
14#[cfg(feature = "format")]
15pub use crate::skip::{AsBytes, Bytes};
16
17/// A trait for working with iterables of bytes.
18///
19/// These iterators can either be contiguous or not contiguous and provide
20/// methods for reading data and accessing underlying data. The readers
21/// can either be contiguous or non-contiguous, although performance and
22/// some API methods may not be available for both.
23///
24/// # Safety
25///
26/// Safe if [`set_cursor`] is set to an index <= [`buffer_length`], so no
27/// out-of-bounds reads can occur. Also, [`get_buffer`] must return a slice of
28/// initialized bytes. The caller must also ensure that any calls that increment
29/// the cursor, such as [`step_by_unchecked`], [`step_unchecked`], and
30/// [`peek_many_unchecked`] never exceed [`buffer_length`] as well.
31///
32/// [`set_cursor`]: `Iter::set_cursor`
33/// [`buffer_length`]: `Iter::buffer_length`
34/// [`get_buffer`]: `Iter::get_buffer`
35/// [`step_by_unchecked`]: `Iter::step_by_unchecked`
36/// [`step_unchecked`]: `Iter::step_unchecked`
37/// [`peek_many_unchecked`]: `Iter::peek_many_unchecked`
38pub unsafe trait Iter<'a> {
39    /// Determine if the buffer is contiguous in memory.
40    const IS_CONTIGUOUS: bool;
41
42    // CURSORS
43    // -------
44
45    /// Get a ptr to the current start of the buffer.
46    #[inline(always)]
47    fn as_ptr(&self) -> *const u8 {
48        self.as_slice().as_ptr()
49    }
50
51    /// Get a slice to the current start of the buffer.
52    #[inline(always)]
53    fn as_slice(&self) -> &'a [u8] {
54        debug_assert!(self.cursor() <= self.buffer_length());
55        // SAFETY: safe since index must be in range.
56        unsafe { self.get_buffer().get_unchecked(self.cursor()..) }
57    }
58
59    /// Get a slice to the full underlying contiguous buffer,
60    fn get_buffer(&self) -> &'a [u8];
61
62    /// Get the total number of elements in the underlying buffer.
63    #[inline(always)]
64    fn buffer_length(&self) -> usize {
65        self.get_buffer().len()
66    }
67
68    /// Get if no bytes are available in the buffer.
69    ///
70    /// This operators on the underlying buffer: that is,
71    /// it returns if [`as_slice`] would return an empty slice.
72    ///
73    /// [`as_slice`]: Iter::as_slice
74    #[inline(always)]
75    fn is_buffer_empty(&self) -> bool {
76        self.cursor() >= self.get_buffer().len()
77    }
78
79    /// Get the current index of the iterator in the slice.
80    fn cursor(&self) -> usize;
81
82    /// Set the current index of the iterator in the slice.
83    ///
84    /// This is **NOT** the current position of the iterator,
85    /// since iterators may skip digits: this is the cursor
86    /// in the underlying buffer. For example, if `slc[2]` is
87    /// skipped, `set_cursor(3)` would be the 3rd element in
88    /// the iterator, not the 4th.
89    ///
90    /// # Safety
91    ///
92    /// Safe if `index <= self.buffer_length()`. Although this
93    /// won't affect safety, the caller also should be careful it
94    /// does not set the cursor within skipped characters
95    /// since this could affect correctness: an iterator that
96    /// only accepts non-consecutive digit separators would
97    /// pass if the cursor was set between the two.
98    unsafe fn set_cursor(&mut self, index: usize);
99
100    /// Get the current number of digits returned by the iterator.
101    ///
102    /// For contiguous iterators, this can include the sign character, decimal
103    /// point, and the exponent sign (that is, it is always the cursor). For
104    /// non-contiguous iterators, this must always be the only the number of
105    /// digits returned.
106    ///
107    /// This is never used for indexing but will be used for API detection.
108    fn current_count(&self) -> usize;
109
110    // PROPERTIES
111
112    /// Determine if the buffer is contiguous.
113    #[inline(always)]
114    fn is_contiguous(&self) -> bool {
115        Self::IS_CONTIGUOUS
116    }
117
118    /// Get the next value available without consuming it.
119    ///
120    /// This does **NOT** skip digits, and directly fetches the item
121    /// from the underlying buffer.
122    #[inline(always)]
123    fn first(&self) -> Option<&'a u8> {
124        self.get_buffer().get(self.cursor())
125    }
126
127    /// Check if the next element is a given value.
128    #[inline(always)]
129    fn first_is_cased(&self, value: u8) -> bool {
130        Some(&value) == self.first()
131    }
132
133    /// Check if the next element is a given value without case sensitivity.
134    #[inline(always)]
135    fn first_is_uncased(&self, value: u8) -> bool {
136        if let Some(&c) = self.first() {
137            c.eq_ignore_ascii_case(&value)
138        } else {
139            false
140        }
141    }
142
143    /// Check if the next item in buffer is a given value with optional case
144    /// sensitivity.
145    #[inline(always)]
146    fn first_is(&self, value: u8, is_cased: bool) -> bool {
147        if is_cased {
148            self.first_is_cased(value)
149        } else {
150            self.first_is_uncased(value)
151        }
152    }
153
154    // STEP BY
155    // -------
156
157    /// Advance the internal slice by `N` elements.
158    ///
159    /// This does not advance the iterator by `N` elements for
160    /// non-contiguous iterators: this just advances the internal,
161    /// underlying buffer. This is useful for multi-digit optimizations
162    /// for contiguous iterators.
163    ///
164    /// This does not increment the count of items: returns: this only
165    /// increments the index, not the total digits returned. You must use
166    /// this carefully: if stepping over a digit, you must then call
167    /// [`increment_count`] afterwards or else the internal count will
168    /// be incorrect.
169    ///
170    /// [`increment_count`]: DigitsIter::increment_count
171    ///
172    /// # Panics
173    ///
174    /// This will panic if the buffer advances for non-contiguous
175    /// iterators if the current byte is a digit separator, or if the
176    /// count is more than 1.
177    ///
178    /// # Safety
179    ///
180    /// As long as the iterator is at least `N` elements, this
181    /// is safe.
182    unsafe fn step_by_unchecked(&mut self, count: usize);
183
184    /// Advance the internal slice by 1 element.
185    ///
186    ///
187    /// This does not increment the count of items: returns: this only
188    /// increments the index, not the total digits returned. You must
189    /// use this carefully: if stepping over a digit, you must then call
190    /// [`increment_count`] afterwards or else the internal count will
191    /// be incorrect.
192    ///
193    /// [`increment_count`]: DigitsIter::increment_count
194    ///
195    /// # Panics
196    ///
197    /// This will panic if the buffer advances for non-contiguous
198    /// iterators if the current byte is a digit separator.
199    ///
200    /// # Safety
201    ///
202    /// Safe as long as the iterator is not empty.
203    #[inline(always)]
204    unsafe fn step_unchecked(&mut self) {
205        debug_assert!(!self.as_slice().is_empty());
206        // SAFETY: safe if `self.index < self.buffer_length()`.
207        unsafe { self.step_by_unchecked(1) };
208    }
209
210    // READ
211    // ----
212
213    /// Read a value of a difference type from the iterator.
214    ///
215    /// This does **not** advance the internal state of the iterator.
216    /// This can only be implemented for contiguous iterators: non-
217    /// contiguous iterators **MUST** panic.
218    ///
219    /// # Panics
220    ///
221    /// If the iterator is a non-contiguous iterator.
222    ///
223    /// # Safety
224    ///
225    /// Safe as long as the number of the buffer is contains as least as
226    /// many bytes as the size of V. This must be unimplemented for
227    /// non-contiguous iterators.
228    #[inline(always)]
229    unsafe fn peek_many_unchecked<V>(&self) -> V {
230        unimplemented!();
231    }
232
233    /// Try to read a the next four bytes as a u32.
234    ///
235    /// This does not advance the internal state of the iterator.
236    #[inline(always)]
237    fn peek_u32(&self) -> Option<u32> {
238        if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::<u32>() {
239            // SAFETY: safe since we've guaranteed the buffer is greater than
240            // the number of elements read. u32 is valid for all bit patterns
241            unsafe { Some(self.peek_many_unchecked()) }
242        } else {
243            None
244        }
245    }
246
247    /// Try to read the next eight bytes as a u64.
248    ///
249    /// This does not advance the internal state of the iterator.
250    #[inline(always)]
251    fn peek_u64(&self) -> Option<u64> {
252        if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::<u64>() {
253            // SAFETY: safe since we've guaranteed the buffer is greater than
254            // the number of elements read. u64 is valid for all bit patterns
255            unsafe { Some(self.peek_many_unchecked()) }
256        } else {
257            None
258        }
259    }
260}
261
262/// Iterator over a contiguous block of bytes.
263///
264/// This allows us to convert to-and-from-slices, raw pointers, and
265/// peek/query the data from either end cheaply.
266///
267/// A default implementation is provided for slice iterators.
268/// This trait **should never** return `null` from `as_ptr`, or be
269/// implemented for non-contiguous data.
270pub trait DigitsIter<'a>: Iterator<Item = &'a u8> + Iter<'a> {
271    /// Get if the iterator cannot return any more elements.
272    ///
273    /// This may advance the internal iterator state, but not
274    /// modify the next returned value.
275    ///
276    /// If this is an iterator, this is based on the number of items
277    /// left to be returned. We do not necessarly know the length of
278    /// the buffer. If this is a non-contiguous iterator, this **MUST**
279    /// advance the state until it knows a value can be returned.
280    ///
281    /// Any incorrect implementations of this affect all safety invariants
282    /// for the rest of the trait. For contiguous iterators, this can be
283    /// as simple as checking if `self.cursor >= self.slc.len()`, but for
284    /// non-contiguous iterators you **MUST** advance to the next element
285    /// to be returned, then check to see if a value exists. The safest
286    /// implementation is always to check if `self.peek().is_none()` and
287    /// ensure [`peek`] is always safe.
288    ///
289    /// If you would like to see if the cursor is at the end of the buffer,
290    /// see [`is_buffer_empty`] instead.
291    ///
292    /// [`is_buffer_empty`]: Iter::is_buffer_empty
293    /// [`peek`]: DigitsIter::peek
294    #[inline(always)]
295    #[allow(clippy::wrong_self_convention)] // reason="required for peeking next item"
296    fn is_consumed(&mut self) -> bool {
297        self.peek().is_none()
298    }
299
300    /// Increment the number of digits that have been returned by the iterator.
301    ///
302    /// For contiguous iterators, this is a no-op. For non-contiguous iterators,
303    /// this increments the count by 1.
304    fn increment_count(&mut self);
305
306    /// Peek the next value of the iterator, without consuming it.
307    ///
308    /// Note that this can modify the internal state, by skipping digits
309    /// for iterators that find the first non-zero value, etc. We optimize
310    /// this for the case where we have contiguous iterators, since
311    /// non-contiguous iterators already have a major performance penalty.
312    fn peek(&mut self) -> Option<Self::Item>;
313
314    /// Peek the next value of the iterator, and step only if it exists.
315    #[inline(always)]
316    fn try_read(&mut self) -> Option<Self::Item> {
317        if let Some(value) = self.peek() {
318            // SAFETY: the slice cannot be empty because we peeked a value.
319            unsafe { self.step_unchecked() };
320            Some(value)
321        } else {
322            None
323        }
324    }
325
326    /// Check if the next element is a given value.
327    #[inline(always)]
328    fn peek_is_cased(&mut self, value: u8) -> bool {
329        Some(&value) == self.peek()
330    }
331
332    /// Check if the next element is a given value without case sensitivity.
333    #[inline(always)]
334    fn peek_is_uncased(&mut self, value: u8) -> bool {
335        if let Some(&c) = self.peek() {
336            c.eq_ignore_ascii_case(&value)
337        } else {
338            false
339        }
340    }
341
342    /// Check if the next element is a given value with optional case
343    /// sensitivity.
344    #[inline(always)]
345    fn peek_is(&mut self, value: u8, is_cased: bool) -> bool {
346        if is_cased {
347            self.peek_is_cased(value)
348        } else {
349            self.peek_is_uncased(value)
350        }
351    }
352
353    /// Peek the next value and consume it if the read value matches the
354    /// expected one.
355    #[inline(always)]
356    fn read_if<Pred: FnOnce(u8) -> bool>(&mut self, pred: Pred) -> Option<u8> {
357        // NOTE: This was implemented to remove usage of unsafe throughout to code
358        // base, however, performance was really not up to scratch. I'm not sure
359        // the cause of this.
360        if let Some(&peeked) = self.peek() {
361            if pred(peeked) {
362                // SAFETY: the slice cannot be empty because we peeked a value.
363                unsafe { self.step_unchecked() };
364                Some(peeked)
365            } else {
366                None
367            }
368        } else {
369            None
370        }
371    }
372
373    /// Read a value if the value matches the provided one.
374    #[inline(always)]
375    fn read_if_value_cased(&mut self, value: u8) -> Option<u8> {
376        if self.peek() == Some(&value) {
377            // SAFETY: the slice cannot be empty because we peeked a value.
378            unsafe { self.step_unchecked() };
379            Some(value)
380        } else {
381            None
382        }
383    }
384
385    /// Read a value if the value matches the provided one without case
386    /// sensitivity.
387    #[inline(always)]
388    fn read_if_value_uncased(&mut self, value: u8) -> Option<u8> {
389        self.read_if(|x| x.eq_ignore_ascii_case(&value))
390    }
391
392    /// Read a value if the value matches the provided one.
393    #[inline(always)]
394    fn read_if_value(&mut self, value: u8, is_cased: bool) -> Option<u8> {
395        if is_cased {
396            self.read_if_value_cased(value)
397        } else {
398            self.read_if_value_uncased(value)
399        }
400    }
401
402    /// Skip zeros from the start of the iterator
403    #[inline(always)]
404    fn skip_zeros(&mut self) -> usize {
405        let start = self.current_count();
406        while self.read_if_value_cased(b'0').is_some() {
407            self.increment_count();
408        }
409        self.current_count() - start
410    }
411
412    /// Determine if the character is a digit.
413    fn is_digit(&self, value: u8) -> bool;
414}