lexical_util/
noskip.rs

1//! An iterator over a slice.
2//!
3//! This iterator has both the length of the original slice, as
4//! well as the current position of the iterator in the buffer.
5
6#![cfg(all(feature = "parse", not(feature = "format")))]
7
8use core::{mem, ptr};
9
10use crate::digit::char_is_digit_const;
11use crate::format::NumberFormat;
12use crate::iterator::{DigitsIter, Iter};
13
14// AS DIGITS
15// ---------
16
17/// Trait to simplify creation of a `Bytes` object.
18pub trait AsBytes<'a> {
19    /// Create `Bytes` from object.
20    fn bytes<const __: u128>(&'a self) -> Bytes<'a, __>;
21}
22
23impl<'a> AsBytes<'a> for [u8] {
24    #[inline(always)]
25    fn bytes<const __: u128>(&'a self) -> Bytes<'a, __> {
26        Bytes::new(self)
27    }
28}
29
30// DIGITS
31// ------
32
33/// Slice iterator that stores the original length of the slice.
34#[derive(Clone)]
35pub struct Bytes<'a, const __: u128> {
36    /// The raw slice for the iterator.
37    slc: &'a [u8],
38    /// Current index of the iterator in the slice.
39    index: usize,
40}
41
42impl<'a, const __: u128> Bytes<'a, __> {
43    /// Create new byte object.
44    #[inline(always)]
45    pub const fn new(slc: &'a [u8]) -> Self {
46        Self {
47            slc,
48            index: 0,
49        }
50    }
51
52    /// Initialize the slice from raw parts.
53    ///
54    /// # Safety
55    ///
56    /// This is safe if and only if the index is <= `slc.len()`.
57    /// For this reason, since it's easy to get wrong, we only
58    /// expose it to `DigitsIterator` and nothing else.
59    #[inline(always)]
60    #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid"
61    const unsafe fn from_parts(slc: &'a [u8], index: usize) -> Self {
62        debug_assert!(index <= slc.len());
63        debug_assert!(Self::IS_CONTIGUOUS);
64        Self {
65            slc,
66            index,
67        }
68    }
69
70    /// Get iterator over integer digits.
71    #[inline(always)]
72    pub fn integer_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> {
73        DigitsIterator {
74            byte: self,
75        }
76    }
77
78    /// Get iterator over fraction digits.
79    #[inline(always)]
80    pub fn fraction_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> {
81        DigitsIterator {
82            byte: self,
83        }
84    }
85
86    /// Get iterator over exponent digits.
87    #[inline(always)]
88    pub fn exponent_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> {
89        DigitsIterator {
90            byte: self,
91        }
92    }
93
94    /// Get iterator over special floating point values.
95    #[inline(always)]
96    pub fn special_iter<'b>(&'b mut self) -> DigitsIterator<'a, 'b, __> {
97        DigitsIterator {
98            byte: self,
99        }
100    }
101}
102
103unsafe impl<'a, const __: u128> Iter<'a> for Bytes<'a, __> {
104    const IS_CONTIGUOUS: bool = true;
105
106    #[inline(always)]
107    fn get_buffer(&self) -> &'a [u8] {
108        self.slc
109    }
110
111    /// Get the current index of the iterator in the slice.
112    #[inline(always)]
113    fn cursor(&self) -> usize {
114        self.index
115    }
116
117    /// Set the current index of the iterator in the slice.
118    ///
119    /// # Safety
120    ///
121    /// Safe if `index <= self.buffer_length()`.
122    #[inline(always)]
123    unsafe fn set_cursor(&mut self, index: usize) {
124        debug_assert!(index <= self.buffer_length());
125        self.index = index;
126    }
127
128    /// Get the current number of digits returned by the iterator.
129    ///
130    /// For contiguous iterators, this can include the sign character, decimal
131    /// point, and the exponent sign (that is, it is always the cursor). For
132    /// non-contiguous iterators, this must always be the only the number of
133    /// digits returned.
134    #[inline(always)]
135    fn current_count(&self) -> usize {
136        self.index
137    }
138
139    #[inline(always)]
140    #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid"
141    unsafe fn step_by_unchecked(&mut self, count: usize) {
142        assert!(Self::IS_CONTIGUOUS);
143        debug_assert!(self.as_slice().len() >= count);
144        self.index += count;
145    }
146
147    #[inline(always)]
148    #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid"
149    unsafe fn peek_many_unchecked<V>(&self) -> V {
150        debug_assert!(Self::IS_CONTIGUOUS);
151        debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
152
153        // SAFETY: safe as long as the slice has at least count elements.
154        unsafe { ptr::read_unaligned::<V>(self.as_ptr() as *const _) }
155    }
156}
157
158// DIGITS ITERATOR
159// ---------------
160
161/// Slice iterator that stores the original length of the slice.
162pub struct DigitsIterator<'a: 'b, 'b, const __: u128> {
163    /// The internal byte object for the no-skip iterator.
164    byte: &'b mut Bytes<'a, __>,
165}
166
167impl<'a: 'b, 'b, const __: u128> DigitsIterator<'a, 'b, __> {
168    /// Create a new digits iterator from the bytes underlying item.
169    #[inline(always)]
170    pub fn new(byte: &'b mut Bytes<'a, __>) -> Self {
171        Self {
172            byte,
173        }
174    }
175
176    /// Take the first N digits from the iterator.
177    ///
178    /// This only takes the digits if we have a contiguous iterator.
179    /// It takes the digits, validating the bounds, and then advanced
180    /// the iterators state.
181    #[cfg_attr(not(feature = "compact"), inline(always))]
182    #[allow(clippy::assertions_on_constants)] // reason="ensuring safety invariants are valid"
183    pub fn take_n(&mut self, n: usize) -> Option<Bytes<'a, __>> {
184        debug_assert!(Self::IS_CONTIGUOUS);
185        let end = self.byte.slc.len().min(n + self.cursor());
186        // NOTE: The compiler should be able to optimize this out.
187        let slc: &[u8] = &self.byte.slc[..end];
188
189        // SAFETY: Safe since we just ensured the underlying slice has that count
190        // elements, so both the underlying slice for this and this **MUST**
191        // have at least count elements. We do static checking on the bounds for this.
192        unsafe {
193            let byte: Bytes<'_, __> = Bytes::from_parts(slc, self.cursor());
194            unsafe { self.set_cursor(end) };
195            Some(byte)
196        }
197    }
198}
199
200unsafe impl<'a: 'b, 'b, const __: u128> Iter<'a> for DigitsIterator<'a, 'b, __> {
201    const IS_CONTIGUOUS: bool = Bytes::<'a, __>::IS_CONTIGUOUS;
202
203    #[inline(always)]
204    fn get_buffer(&self) -> &'a [u8] {
205        self.byte.get_buffer()
206    }
207
208    #[inline(always)]
209    fn cursor(&self) -> usize {
210        self.byte.cursor()
211    }
212
213    #[inline(always)]
214    unsafe fn set_cursor(&mut self, index: usize) {
215        debug_assert!(index <= self.buffer_length());
216        // SAFETY: safe if `index <= self.buffer_length()`.
217        unsafe { self.byte.set_cursor(index) };
218    }
219
220    #[inline(always)]
221    fn current_count(&self) -> usize {
222        self.byte.current_count()
223    }
224
225    #[inline(always)]
226    unsafe fn step_by_unchecked(&mut self, count: usize) {
227        debug_assert!(self.as_slice().len() >= count);
228        // SAFETY: safe as long as `slc.len() >= count`.
229        unsafe { self.byte.step_by_unchecked(count) }
230    }
231
232    #[inline(always)]
233    unsafe fn peek_many_unchecked<V>(&self) -> V {
234        debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
235        // SAFETY: safe as long as the slice has at least count elements.
236        unsafe { self.byte.peek_many_unchecked() }
237    }
238}
239
240impl<'a: 'b, 'b, const FORMAT: u128> DigitsIter<'a> for DigitsIterator<'a, 'b, FORMAT> {
241    #[inline(always)]
242    fn is_consumed(&mut self) -> bool {
243        self.is_buffer_empty()
244    }
245
246    // Always a no-op
247    #[inline(always)]
248    fn increment_count(&mut self) {
249    }
250
251    #[inline(always)]
252    fn peek(&mut self) -> Option<<Self as Iterator>::Item> {
253        self.byte.slc.get(self.byte.index)
254    }
255
256    /// Determine if the character is a digit.
257    #[inline(always)]
258    fn is_digit(&self, value: u8) -> bool {
259        let format = NumberFormat::<{ FORMAT }> {};
260        char_is_digit_const(value, format.mantissa_radix())
261    }
262}
263
264impl<'a: 'b, 'b, const __: u128> Iterator for DigitsIterator<'a, 'b, __> {
265    type Item = &'a u8;
266
267    #[inline(always)]
268    fn next(&mut self) -> Option<Self::Item> {
269        let value = self.byte.slc.get(self.byte.index)?;
270        self.byte.index += 1;
271        Some(value)
272    }
273}
274
275impl<'a: 'b, 'b, const __: u128> ExactSizeIterator for DigitsIterator<'a, 'b, __> {
276    #[inline(always)]
277    fn len(&self) -> usize {
278        self.buffer_length() - self.cursor()
279    }
280}