lexical_util/
skip.rs

1//! An iterator that skips values equal to a provided value.
2//!
3//! Iterators over a contiguous slice, returning all values
4//! except for those matching the provided skip value.
5//!
6//! # Complexity
7//!
8//! Although superficially quite simple, the level of complexity
9//! introduced by digit separators can be quite complex, due
10//! the number of permutations during parsing.
11//!
12//! We can consume any combinations of of \[0,3\] items from the following set:
13//!     - \[l\]eading digit separators, where digit separators occur before digits.
14//!     - \[i\]nternal digit separators, where digit separators occur between digits.
15//!     - \[t\]railing digit separators, where digit separators occur after digits.
16//!
17//! In addition to those combinations, we can also have:
18//!     - \[c\]onsecutive digit separators, which allows two digit separators to be adjacent.
19//!
20//! # Shorthand
21//!
22//! We will use the term consumer to denote a function that consumes digits,
23//! splitting an input buffer at an index, where the leading section contains
24//! valid input digits, and the trailing section contains invalid characters.
25//! Due to the number of combinations for consumers, we use the following
26//! shorthand to denote consumers:
27//!     - `no`, does not use a digit separator.
28//!     - `l`, consumes leading digit separators.
29//!     - `i`, consumes internal digit separators.
30//!     - `t`, consumes trailing digit separators.
31//!     - `c`, consumes consecutive digit separators.
32//!
33//! The `next`/`iter` algorithms are therefore named `next_x`, where `x`
34//! represents the shorthand name of the consumer, in sorted order.
35//!  For example, `next_ilt` means that consumer can skip internal,
36//! leading, and trailing digit separators, but not consecutive ones.
37
38#![cfg(all(feature = "format", feature = "parse"))]
39
40use crate::digit::char_is_digit_const;
41use crate::format::NumberFormat;
42use crate::format_flags as flags;
43use crate::iterator::BytesIter;
44use core::{mem, ptr};
45
46// PEEK
47// ----
48
49/// Determine if the digit separator is internal.
50///
51/// Preconditions: Assumes `slc[index]` is a digit separator.
52/// The compiler optimizes this pretty well: it's almost as efficient as
53/// optimized assembly without bounds checking.
54macro_rules! is_i {
55    ($self:ident) => {
56        !is_l!($self) && !is_t!($self)
57    };
58}
59
60/// Determine if the digit separator is leading.
61///
62/// Preconditions: Assumes `slc[index]` is a digit separator.
63/// The compiler optimizes this pretty well: it's almost as efficient as
64/// optimized assembly without bounds checking.
65macro_rules! is_l {
66    ($self:ident) => {{
67        // Consume any digit separators before the current one.
68        let mut index = $self.byte.index;
69        while index > 0
70            && $self.byte.slc.get(index - 1).map_or(false, |&x| $self.is_digit_separator(x))
71        {
72            index -= 1;
73        }
74
75        // True if there are no items before the digit separator, or character
76        // before the digit separators is not a digit.
77        index == 0 || !$self.byte.slc.get(index - 1).map_or(false, |&x| $self.is_digit(x))
78    }};
79}
80
81/// Determine if the digit separator is trailing.
82///
83/// Preconditions: Assumes `slc[index]` is a digit separator.
84/// The compiler optimizes this pretty well: it's almost as efficient as
85/// optimized assembly without bounds checking.
86macro_rules! is_t {
87    ($self:ident) => {{
88        // Consume any digit separators after the current one.
89        let mut index = $self.byte.index;
90        while index < $self.byte.slc.len()
91            && $self.byte.slc.get(index + 1).map_or(false, |&x| $self.is_digit_separator(x))
92        {
93            index += 1;
94        }
95
96        index == $self.byte.slc.len()
97            || !$self.byte.slc.get(index + 1).map_or(false, |&x| $self.is_digit(x))
98    }};
99}
100
101/// Determine if the digit separator is leading or internal.
102///
103/// Preconditions: Assumes `slc[index]` is a digit separator.
104macro_rules! is_il {
105    ($self:ident) => {
106        is_l!($self) || !is_t!($self)
107    };
108}
109
110/// Determine if the digit separator is internal or trailing.
111///
112/// Preconditions: Assumes `slc[index]` is a digit separator.
113macro_rules! is_it {
114    ($self:ident) => {
115        is_t!($self) || !is_l!($self)
116    };
117}
118
119/// Determine if the digit separator is leading or trailing.
120///
121/// Preconditions: Assumes `slc[index]` is a digit separator.
122macro_rules! is_lt {
123    ($self:ident) => {
124        is_l!($self) || is_t!($self)
125    };
126}
127
128/// Determine if the digit separator is internal, leading, or trailing.
129macro_rules! is_ilt {
130    ($self:ident) => {
131        true
132    };
133}
134
135/// Consumes 1 or more digit separators.
136/// Peeks the next token that's not a digit separator.
137macro_rules! peek_1 {
138    ($self:ident, $is_skip:ident) => {{
139        // This will consume consecutive digit separators.
140        let value = $self.byte.slc.get($self.byte.index)?;
141        let is_digit_separator = $self.is_digit_separator(*value);
142        if is_digit_separator && $is_skip!($self) {
143            // Have a skippable digit separator: keep incrementing until we find
144            // a non-digit separator character. Don't need any complex checks
145            // here, since we've already done them above.
146            let mut index = $self.byte.index + 1;
147            while index < $self.length()
148                && $self.byte.slc.get(index).map_or(false, |&x| $self.is_digit_separator(x))
149            {
150                index += 1;
151            }
152            $self.byte.index = index;
153            $self.byte.slc.get($self.byte.index)
154        } else {
155            // Have 1 of 2 conditions:
156            //  1. A non-digit separator character.
157            //  2. A digit separator that is not valid in the context.
158            Some(value)
159        }
160    }};
161}
162
163/// Consumes 1 or more digit separators.
164/// Peeks the next token that's not a digit separator.
165macro_rules! peek_n {
166    ($self:ident, $is_skip:ident) => {{
167        // This will consume consecutive digit separators.
168        let value = $self.byte.slc.get($self.byte.index)?;
169        let is_digit_separator = $self.is_digit_separator(*value);
170        if is_digit_separator && $is_skip!($self) {
171            // Have a skippable digit separator: keep incrementing until we find
172            // a non-digit separator character. Don't need any complex checks
173            // here, since we've already done them above.
174            let mut index = $self.byte.index + 1;
175            while index < $self.byte.slc.len()
176                && $self.byte.slc.get(index).map_or(false, |&x| $self.is_digit_separator(x))
177            {
178                index += 1;
179            }
180            $self.byte.index = index;
181            $self.byte.slc.get($self.byte.index)
182        } else {
183            // Have 1 of 2 conditions:
184            //  1. A non-digit separator character.
185            //  2. A digit separator that is not valid in the context.
186            Some(value)
187        }
188    }};
189}
190
191/// Consumes no digit separators and peeks the next value.
192macro_rules! peek_noskip {
193    ($self:ident) => {
194        $self.byte.slc.get($self.byte.index)
195    };
196}
197
198/// Consumes at most 1 leading digit separator and peeks the next value.
199macro_rules! peek_l {
200    ($self:ident) => {
201        peek_1!($self, is_l)
202    };
203}
204
205/// Consumes at most 1 internal digit separator and peeks the next value.
206macro_rules! peek_i {
207    ($self:ident) => {
208        peek_1!($self, is_i)
209    };
210}
211
212/// Consumes at most 1 trailing digit separator and peeks the next value.
213macro_rules! peek_t {
214    ($self:ident) => {
215        peek_1!($self, is_t)
216    };
217}
218
219/// Consumes at most 1 internal/leading digit separator and peeks the next value.
220macro_rules! peek_il {
221    ($self:ident) => {
222        peek_1!($self, is_il)
223    };
224}
225
226/// Consumes at most 1 internal/trailing digit separator and peeks the next value.
227macro_rules! peek_it {
228    ($self:ident) => {
229        peek_1!($self, is_it)
230    };
231}
232
233/// Consumes at most 1 leading/trailing digit separator and peeks the next value.
234macro_rules! peek_lt {
235    ($self:ident) => {
236        peek_1!($self, is_lt)
237    };
238}
239
240/// Consumes at most 1 digit separator and peeks the next value.
241macro_rules! peek_ilt {
242    ($self:ident) => {
243        peek_1!($self, is_ilt)
244    };
245}
246
247/// Consumes 1 or more leading digit separators and peeks the next value.
248macro_rules! peek_lc {
249    ($self:ident) => {
250        peek_n!($self, is_l)
251    };
252}
253
254/// Consumes 1 or more internal digit separators and peeks the next value.
255macro_rules! peek_ic {
256    ($self:ident) => {
257        peek_n!($self, is_i)
258    };
259}
260
261/// Consumes 1 or more trailing digit separators and peeks the next value.
262macro_rules! peek_tc {
263    ($self:ident) => {
264        peek_n!($self, is_t)
265    };
266}
267
268/// Consumes 1 or more internal/leading digit separators and peeks the next value.
269macro_rules! peek_ilc {
270    ($self:ident) => {
271        peek_n!($self, is_il)
272    };
273}
274
275/// Consumes 1 or more internal/trailing digit separators and peeks the next value.
276macro_rules! peek_itc {
277    ($self:ident) => {
278        peek_n!($self, is_it)
279    };
280}
281
282/// Consumes 1 or more leading/trailing digit separators and peeks the next value.
283macro_rules! peek_ltc {
284    ($self:ident) => {
285        peek_n!($self, is_lt)
286    };
287}
288
289/// Consumes 1 or more digit separators and peeks the next value.
290macro_rules! peek_iltc {
291    ($self:ident) => {{
292        loop {
293            let value = $self.byte.slc.get($self.byte.index)?;
294            if !$self.is_digit_separator(*value) {
295                return Some(value);
296            }
297            $self.byte.index += 1;
298        }
299    }};
300}
301
302// AS DIGITS
303// ---------
304
305/// Trait to simplify creation of a `Bytes` object.
306pub trait AsBytes<'a> {
307    /// Create `Bytes` from object.
308    fn bytes<const FORMAT: u128>(&'a self) -> Bytes<'a, FORMAT>;
309}
310
311impl<'a> AsBytes<'a> for [u8] {
312    #[inline]
313    fn bytes<const FORMAT: u128>(&'a self) -> Bytes<'a, FORMAT> {
314        Bytes::new(self)
315    }
316}
317
318// DIGITS
319// ------
320
321/// Slice iterator that skips characters matching a given value.
322///
323/// This wraps an iterator over a contiguous block of memory,
324/// and only returns values that are not equal to skip.
325///
326/// The format allows us to dictate the actual behavior of
327/// the iterator: in what contexts does it skip digit separators.
328///
329/// `FORMAT` is required to tell us what the digit separator is, and where
330/// the digit separators are allowed, as well tell us the radix.
331/// The radix is required to allow us to differentiate digit from
332/// non-digit characters (see [DigitSeparators](/docs/DigitSeparators.md)
333/// for a detailed explanation on why).
334#[derive(Clone)]
335pub struct Bytes<'a, const FORMAT: u128> {
336    /// The raw slice for the iterator.
337    slc: &'a [u8],
338    /// Current index of the iterator in the slice.
339    index: usize,
340    /// The current count of values returned by the iterator.
341    /// This is only used if the iterator is not contiguous.
342    count: usize,
343}
344
345impl<'a, const FORMAT: u128> Bytes<'a, FORMAT> {
346    /// If each yielded value is adjacent in memory.
347    pub const IS_CONTIGUOUS: bool = NumberFormat::<{ FORMAT }>::DIGIT_SEPARATOR == 0;
348
349    /// Create new byte object.
350    #[inline]
351    pub fn new(slc: &'a [u8]) -> Self {
352        Self {
353            slc,
354            index: 0,
355            count: 0,
356        }
357    }
358
359    /// Get a ptr to the current start of the iterator.
360    #[inline]
361    pub fn as_ptr(&self) -> *const u8 {
362        self.as_slice().as_ptr()
363    }
364
365    /// Get a slice to the current start of the iterator.
366    #[inline]
367    pub fn as_slice(&self) -> &'a [u8] {
368        // SAFETY: safe since index must be in range
369        unsafe { self.slc.get_unchecked(self.index..) }
370    }
371
372    /// Get the total number of elements in the underlying slice.
373    #[inline]
374    pub fn length(&self) -> usize {
375        self.slc.len()
376    }
377
378    /// Get the current index of the iterator in the slice.
379    #[inline]
380    pub fn cursor(&self) -> usize {
381        self.index
382    }
383
384    /// Set the current index of the iterator in the slice.
385    ///
386    /// # Safety
387    ///
388    /// Safe if `index <= self.length()`.
389    #[inline]
390    pub unsafe fn set_cursor(&mut self, index: usize) {
391        debug_assert!(index <= self.length());
392        self.index = index
393    }
394
395    /// Get the current number of values returned by the iterator.
396    #[inline]
397    pub fn current_count(&self) -> usize {
398        // If the buffer is contiguous, then we don't need to track the
399        // number of values: the current index is enough.
400        if Self::IS_CONTIGUOUS {
401            self.index
402        } else {
403            self.count
404        }
405    }
406
407    /// Get if the buffer underlying the iterator is empty.
408    ///
409    /// This might not be the same thing as `is_consumed`: `is_consumed`
410    /// checks if any more elements may be returned, which may require
411    /// peeking the next value. Consumed merely checks if the
412    /// iterator has an empty slice. It is effectively a cheaper,
413    /// but weaker variant of `is_consumed()`.
414    #[inline]
415    pub fn is_done(&self) -> bool {
416        self.index >= self.slc.len()
417    }
418
419    // Determine if the abstraction is contiguous.
420    #[inline]
421    pub fn is_contiguous(&self) -> bool {
422        Self::IS_CONTIGUOUS
423    }
424
425    /// Read a value of a difference type from the iterator.
426    /// This advances the internal state of the iterator.
427    ///
428    /// # Safety
429    ///
430    /// Safe as long as the number of the buffer is contains as least as
431    /// many bytes as the size of V.
432    #[inline]
433    pub unsafe fn read_unchecked<V>(&self) -> V {
434        debug_assert!(Self::IS_CONTIGUOUS);
435        debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
436
437        let slc = self.as_slice();
438        // SAFETY: safe as long as the slice has at least count elements.
439        unsafe { ptr::read_unaligned::<V>(slc.as_ptr() as *const _) }
440    }
441
442    /// Try to read a value of a different type from the iterator.
443    /// This advances the internal state of the iterator.
444    #[inline]
445    pub fn read<V>(&self) -> Option<V> {
446        if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::<V>() {
447            // SAFETY: safe since we've guaranteed the buffer is greater than
448            // the number of elements read.
449            unsafe { Some(self.read_unchecked()) }
450        } else {
451            None
452        }
453    }
454
455    /// Check if the next element is a given value.
456    #[inline]
457    pub fn first_is(&mut self, value: u8) -> bool {
458        // Don't assert not a digit separator, since this can occur when
459        // a different component does not allow digit separators there.
460        if let Some(&c) = self.slc.get(self.index) {
461            c == value
462        } else {
463            false
464        }
465    }
466
467    /// Check if the next element is a given value without case sensitivity.
468    #[inline]
469    pub fn case_insensitive_first_is(&mut self, value: u8) -> bool {
470        // Don't assert not a digit separator, since this can occur when
471        // a different component does not allow digit separators there.
472        if let Some(&c) = self.slc.get(self.index) {
473            c.to_ascii_lowercase() == value.to_ascii_lowercase()
474        } else {
475            false
476        }
477    }
478
479    /// Get iterator over integer digits.
480    #[inline]
481    pub fn integer_iter<'b>(&'b mut self) -> IntegerBytesIterator<'a, 'b, FORMAT> {
482        IntegerBytesIterator {
483            byte: self,
484        }
485    }
486
487    /// Get iterator over fraction digits.
488    #[inline]
489    pub fn fraction_iter<'b>(&'b mut self) -> FractionBytesIterator<'a, 'b, FORMAT> {
490        FractionBytesIterator {
491            byte: self,
492        }
493    }
494
495    /// Get iterator over exponent digits.
496    #[inline]
497    pub fn exponent_iter<'b>(&'b mut self) -> ExponentBytesIterator<'a, 'b, FORMAT> {
498        ExponentBytesIterator {
499            byte: self,
500        }
501    }
502
503    /// Get iterator over special floating point values.
504    #[inline]
505    pub fn special_iter<'b>(&'b mut self) -> SpecialBytesIterator<'a, 'b, FORMAT> {
506        SpecialBytesIterator {
507            byte: self,
508        }
509    }
510
511    /// Advance the byte by `N` elements.
512    ///
513    /// # Safety
514    ///
515    /// As long as the iterator is at least `N` elements, this
516    /// is safe.
517    #[inline]
518    pub unsafe fn step_by_unchecked(&mut self, count: usize) {
519        if Self::IS_CONTIGUOUS {
520            // Contiguous, can skip most of these checks.
521            debug_assert!(self.as_slice().len() >= count);
522        } else {
523            // Since this isn't contiguous, it only works
524            // if the value is in the range `[0, 1]`.
525            // We also need to make sure the **current** value
526            // isn't a digit separator.
527            let format = NumberFormat::<{ FORMAT }> {};
528            debug_assert!(self.as_slice().len() >= count);
529            debug_assert!(count == 0 || count == 1);
530            debug_assert!(
531                count == 0 || self.slc.get(self.index) != Some(&format.digit_separator())
532            );
533        }
534        self.index += count;
535        if !Self::IS_CONTIGUOUS {
536            // Only increment the count if it's not contiguous, otherwise,
537            // this is an unnecessary performance penalty.
538            self.count += count;
539        }
540    }
541
542    /// Advance the byte by 1 element.
543    ///
544    /// # Safety
545    ///
546    /// Safe as long as the iterator is not empty.
547    #[inline]
548    pub unsafe fn step_unchecked(&mut self) {
549        debug_assert!(!self.as_slice().is_empty());
550        // SAFETY: safe if `self.index < self.length()`.
551        unsafe { self.step_by_unchecked(1) };
552    }
553}
554
555// ITERATOR HELPERS
556// ----------------
557
558/// Create skip iterator definition.
559macro_rules! skip_iterator {
560    ($iterator:ident, $doc:literal) => {
561        #[doc = $doc]
562        pub struct $iterator<'a: 'b, 'b, const FORMAT: u128> {
563            /// The internal byte object for the skip iterator.
564            byte: &'b mut Bytes<'a, FORMAT>,
565        }
566    };
567}
568
569macro_rules! is_digit_separator {
570    ($format:ident) => {
571        /// Determine if the character is a digit separator.
572        pub const fn is_digit_separator(&self, value: u8) -> bool {
573            let format = NumberFormat::<{ $format }> {};
574            let digit_separator = format.digit_separator();
575            if digit_separator == 0 {
576                // Check at compile time if we have an invalid digit separator.
577                // b'\x00', or the NUL character, is this invalid value.
578                false
579            } else {
580                value == digit_separator
581            }
582        }
583    };
584}
585
586/// Create impl block for skip iterator.
587macro_rules! skip_iterator_impl {
588    ($iterator:ident, $radix_cb:ident) => {
589        impl<'a: 'b, 'b, const FORMAT: u128> $iterator<'a, 'b, FORMAT> {
590            is_digit_separator!(FORMAT);
591
592            /// Determine if the character is a digit.
593            pub const fn is_digit(&self, value: u8) -> bool {
594                let format = NumberFormat::<{ FORMAT }> {};
595                char_is_digit_const(value, format.$radix_cb())
596            }
597        }
598    };
599}
600
601/// Create impl Iterator block for skip iterator.
602macro_rules! skip_iterator_iterator_impl {
603    ($iterator:ident) => {
604        impl<'a: 'b, 'b, const FORMAT: u128> Iterator for $iterator<'a, 'b, FORMAT> {
605            type Item = &'a u8;
606
607            #[inline]
608            fn next(&mut self) -> Option<Self::Item> {
609                // Peek will handle everything properly internally.
610                let value = self.peek()?;
611                // Increment the index so we know not to re-fetch it.
612                self.byte.index += 1;
613                if !Self::IS_CONTIGUOUS {
614                    // Only increment the count if it's not contiguous, otherwise,
615                    // this is an unnecessary performance penalty.
616                    self.byte.count += 1;
617                }
618                Some(value)
619            }
620        }
621    };
622}
623
624/// Create base methods for the ByteIter block of a skip iterator.
625macro_rules! skip_iterator_byteiter_base {
626    ($format:ident, $mask:ident) => {
627        // It's contiguous if we don't skip over any values.
628        // IE, the digit separator flags for the iterator over
629        // the digits doesn't skip any values.
630        const IS_CONTIGUOUS: bool = $format & flags::$mask == 0;
631
632        #[inline]
633        fn as_ptr(&self) -> *const u8 {
634            self.byte.as_ptr()
635        }
636
637        #[inline]
638        fn as_slice(&self) -> &'a [u8] {
639            self.byte.as_slice()
640        }
641
642        #[inline]
643        fn length(&self) -> usize {
644            self.byte.length()
645        }
646
647        #[inline]
648        fn cursor(&self) -> usize {
649            self.byte.cursor()
650        }
651
652        #[inline]
653        unsafe fn set_cursor(&mut self, index: usize) {
654            debug_assert!(index <= self.length());
655            // SAFETY: safe if `index <= self.length()`.
656            unsafe { self.byte.set_cursor(index) };
657        }
658
659        #[inline]
660        fn current_count(&self) -> usize {
661            self.byte.current_count()
662        }
663
664        #[inline]
665        fn is_consumed(&mut self) -> bool {
666            self.peek().is_none()
667        }
668
669        #[inline]
670        fn is_done(&self) -> bool {
671            self.byte.is_done()
672        }
673
674        #[inline]
675        fn is_contiguous(&self) -> bool {
676            Self::IS_CONTIGUOUS
677        }
678
679        #[inline]
680        unsafe fn peek_unchecked(&mut self) -> <Self as Iterator>::Item {
681            self.peek().unwrap()
682        }
683
684        #[inline]
685        unsafe fn read_unchecked<V>(&self) -> V {
686            debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
687            // SAFETY: safe as long as the slice has at least count elements.
688            unsafe { self.byte.read_unchecked() }
689        }
690
691        #[inline]
692        fn read<V>(&self) -> Option<V> {
693            self.byte.read()
694        }
695
696        #[inline]
697        unsafe fn step_by_unchecked(&mut self, count: usize) {
698            debug_assert!(self.as_slice().len() >= count);
699            // SAFETY: safe as long as `slc.len() >= count`.
700            unsafe { self.byte.step_by_unchecked(count) }
701        }
702    };
703}
704
705/// Create impl ByteIter block for skip iterator.
706macro_rules! skip_iterator_byteiter_impl {
707    ($iterator:ident, $mask:ident, $i:ident, $l:ident, $t:ident, $c:ident) => {
708        impl<'a: 'b, 'b, const FORMAT: u128> BytesIter<'a> for $iterator<'a, 'b, FORMAT> {
709            skip_iterator_byteiter_base!(FORMAT, $mask);
710
711            /// Peek the next value of the iterator, without consuming it.
712            #[inline]
713            fn peek(&mut self) -> Option<<Self as Iterator>::Item> {
714                let format = NumberFormat::<{ FORMAT }> {};
715                const IL: u128 = flags::$i | flags::$l;
716                const IT: u128 = flags::$i | flags::$t;
717                const LT: u128 = flags::$l | flags::$t;
718                const ILT: u128 = flags::$i | flags::$l | flags::$t;
719                const IC: u128 = flags::$i | flags::$c;
720                const LC: u128 = flags::$l | flags::$c;
721                const TC: u128 = flags::$t | flags::$c;
722                const ILC: u128 = IL | flags::$c;
723                const ITC: u128 = IT | flags::$c;
724                const LTC: u128 = LT | flags::$c;
725                const ILTC: u128 = ILT | flags::$c;
726
727                match format.digit_separator_flags() & flags::$mask {
728                    0 => peek_noskip!(self),
729                    flags::$i => peek_i!(self),
730                    flags::$l => peek_l!(self),
731                    flags::$t => peek_t!(self),
732                    IL => peek_il!(self),
733                    IT => peek_it!(self),
734                    LT => peek_lt!(self),
735                    ILT => peek_ilt!(self),
736                    IC => peek_ic!(self),
737                    LC => peek_lc!(self),
738                    TC => peek_tc!(self),
739                    ILC => peek_ilc!(self),
740                    ITC => peek_itc!(self),
741                    LTC => peek_ltc!(self),
742                    ILTC => peek_iltc!(self),
743                    _ => unreachable!(),
744                }
745            }
746        }
747    };
748}
749
750// INTEGER DIGITS ITERATOR
751// -----------------------
752
753skip_iterator!(IntegerBytesIterator, "Iterator that skips over digit separators in the integer.");
754skip_iterator_impl!(IntegerBytesIterator, mantissa_radix);
755skip_iterator_iterator_impl!(IntegerBytesIterator);
756skip_iterator_byteiter_impl!(
757    IntegerBytesIterator,
758    INTEGER_DIGIT_SEPARATOR_FLAG_MASK,
759    INTEGER_INTERNAL_DIGIT_SEPARATOR,
760    INTEGER_LEADING_DIGIT_SEPARATOR,
761    INTEGER_TRAILING_DIGIT_SEPARATOR,
762    INTEGER_CONSECUTIVE_DIGIT_SEPARATOR
763);
764
765// FRACTION DIGITS ITERATOR
766// ------------------------
767
768skip_iterator!(FractionBytesIterator, "Iterator that skips over digit separators in the fraction.");
769skip_iterator_impl!(FractionBytesIterator, mantissa_radix);
770skip_iterator_iterator_impl!(FractionBytesIterator);
771skip_iterator_byteiter_impl!(
772    FractionBytesIterator,
773    FRACTION_DIGIT_SEPARATOR_FLAG_MASK,
774    FRACTION_INTERNAL_DIGIT_SEPARATOR,
775    FRACTION_LEADING_DIGIT_SEPARATOR,
776    FRACTION_TRAILING_DIGIT_SEPARATOR,
777    FRACTION_CONSECUTIVE_DIGIT_SEPARATOR
778);
779
780// EXPONENT DIGITS ITERATOR
781// ------------------------
782
783skip_iterator!(ExponentBytesIterator, "Iterator that skips over digit separators in the exponent.");
784skip_iterator_impl!(ExponentBytesIterator, exponent_radix);
785skip_iterator_iterator_impl!(ExponentBytesIterator);
786skip_iterator_byteiter_impl!(
787    ExponentBytesIterator,
788    EXPONENT_DIGIT_SEPARATOR_FLAG_MASK,
789    EXPONENT_INTERNAL_DIGIT_SEPARATOR,
790    EXPONENT_LEADING_DIGIT_SEPARATOR,
791    EXPONENT_TRAILING_DIGIT_SEPARATOR,
792    EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR
793);
794
795// SPECIAL DIGITS ITERATOR
796// -----------------------
797
798skip_iterator!(
799    SpecialBytesIterator,
800    "Iterator that skips over digit separators in special floats."
801);
802skip_iterator_iterator_impl!(SpecialBytesIterator);
803
804impl<'a: 'b, 'b, const FORMAT: u128> SpecialBytesIterator<'a, 'b, FORMAT> {
805    is_digit_separator!(FORMAT);
806}
807
808impl<'a: 'b, 'b, const FORMAT: u128> BytesIter<'a> for SpecialBytesIterator<'a, 'b, FORMAT> {
809    skip_iterator_byteiter_base!(FORMAT, SPECIAL_DIGIT_SEPARATOR);
810
811    /// Peek the next value of the iterator, without consuming it.
812    #[inline]
813    fn peek(&mut self) -> Option<<Self as Iterator>::Item> {
814        let format = NumberFormat::<{ FORMAT }> {};
815        if format.special_digit_separator() {
816            peek_iltc!(self)
817        } else {
818            peek_noskip!(self)
819        }
820    }
821}