#![cfg(all(feature = "format", feature = "parse"))]
use core::{mem, ptr};
use crate::digit::char_is_digit_const;
use crate::format::NumberFormat;
use crate::format_flags as flags;
use crate::iterator::{DigitsIter, Iter};
macro_rules! is_i {
($self:ident) => {
!is_l!($self) && !is_t!($self)
};
}
macro_rules! is_l {
($self:ident) => {{
let mut index = $self.byte.index;
while index > 0
&& $self.byte.slc.get(index - 1).map_or(false, |&x| $self.is_digit_separator(x))
{
index -= 1;
}
index == 0 || !$self.byte.slc.get(index - 1).map_or(false, |&x| $self.is_digit(x))
}};
}
macro_rules! is_t {
($self:ident) => {{
let mut index = $self.byte.index;
while index < $self.byte.slc.len()
&& $self.byte.slc.get(index + 1).map_or(false, |&x| $self.is_digit_separator(x))
{
index += 1;
}
index == $self.byte.slc.len()
|| !$self.byte.slc.get(index + 1).map_or(false, |&x| $self.is_digit(x))
}};
}
macro_rules! is_il {
($self:ident) => {
is_l!($self) || !is_t!($self)
};
}
macro_rules! is_it {
($self:ident) => {
is_t!($self) || !is_l!($self)
};
}
macro_rules! is_lt {
($self:ident) => {
is_l!($self) || is_t!($self)
};
}
macro_rules! is_ilt {
($self:ident) => {
true
};
}
macro_rules! peek_1 {
($self:ident, $is_skip:ident) => {{
let value = $self.byte.slc.get($self.byte.index)?;
let is_digit_separator = $self.is_digit_separator(*value);
if is_digit_separator && $is_skip!($self) {
let mut index = $self.byte.index + 1;
while index < $self.buffer_length()
&& $self.byte.slc.get(index).map_or(false, |&x| $self.is_digit_separator(x))
{
index += 1;
}
$self.byte.index = index;
$self.byte.slc.get($self.byte.index)
} else {
Some(value)
}
}};
}
macro_rules! peek_n {
($self:ident, $is_skip:ident) => {{
let value = $self.byte.slc.get($self.byte.index)?;
let is_digit_separator = $self.is_digit_separator(*value);
if is_digit_separator && $is_skip!($self) {
let mut index = $self.byte.index + 1;
while index < $self.byte.slc.len()
&& $self.byte.slc.get(index).map_or(false, |&x| $self.is_digit_separator(x))
{
index += 1;
}
$self.byte.index = index;
$self.byte.slc.get($self.byte.index)
} else {
Some(value)
}
}};
}
macro_rules! peek_noskip {
($self:ident) => {
$self.byte.slc.get($self.byte.index)
};
}
macro_rules! peek_l {
($self:ident) => {
peek_1!($self, is_l)
};
}
macro_rules! peek_i {
($self:ident) => {
peek_1!($self, is_i)
};
}
macro_rules! peek_t {
($self:ident) => {
peek_1!($self, is_t)
};
}
macro_rules! peek_il {
($self:ident) => {
peek_1!($self, is_il)
};
}
macro_rules! peek_it {
($self:ident) => {
peek_1!($self, is_it)
};
}
macro_rules! peek_lt {
($self:ident) => {
peek_1!($self, is_lt)
};
}
macro_rules! peek_ilt {
($self:ident) => {
peek_1!($self, is_ilt)
};
}
macro_rules! peek_lc {
($self:ident) => {
peek_n!($self, is_l)
};
}
macro_rules! peek_ic {
($self:ident) => {
peek_n!($self, is_i)
};
}
macro_rules! peek_tc {
($self:ident) => {
peek_n!($self, is_t)
};
}
macro_rules! peek_ilc {
($self:ident) => {
peek_n!($self, is_il)
};
}
macro_rules! peek_itc {
($self:ident) => {
peek_n!($self, is_it)
};
}
macro_rules! peek_ltc {
($self:ident) => {
peek_n!($self, is_lt)
};
}
macro_rules! peek_iltc {
($self:ident) => {{
loop {
let value = $self.byte.slc.get($self.byte.index)?;
if !$self.is_digit_separator(*value) {
return Some(value);
}
$self.byte.index += 1;
}
}};
}
pub trait AsBytes<'a> {
fn bytes<const FORMAT: u128>(&'a self) -> Bytes<'a, FORMAT>;
}
impl<'a> AsBytes<'a> for [u8] {
#[inline(always)]
fn bytes<const FORMAT: u128>(&'a self) -> Bytes<'a, FORMAT> {
Bytes::new(self)
}
}
#[derive(Clone)]
pub struct Bytes<'a, const FORMAT: u128> {
slc: &'a [u8],
index: usize,
count: usize,
}
impl<'a, const FORMAT: u128> Bytes<'a, FORMAT> {
#[inline(always)]
pub const fn new(slc: &'a [u8]) -> Self {
Self {
slc,
index: 0,
count: 0,
}
}
#[inline(always)]
const unsafe fn from_parts(slc: &'a [u8], index: usize) -> Self {
debug_assert!(index <= slc.len());
debug_assert!(Self::IS_CONTIGUOUS);
Self {
slc,
index,
count: 0,
}
}
#[inline(always)]
pub fn integer_iter<'b>(&'b mut self) -> IntegerDigitsIterator<'a, 'b, FORMAT> {
IntegerDigitsIterator {
byte: self,
}
}
#[inline(always)]
pub fn fraction_iter<'b>(&'b mut self) -> FractionDigitsIterator<'a, 'b, FORMAT> {
FractionDigitsIterator {
byte: self,
}
}
#[inline(always)]
pub fn exponent_iter<'b>(&'b mut self) -> ExponentDigitsIterator<'a, 'b, FORMAT> {
ExponentDigitsIterator {
byte: self,
}
}
#[inline(always)]
pub fn special_iter<'b>(&'b mut self) -> SpecialDigitsIterator<'a, 'b, FORMAT> {
SpecialDigitsIterator {
byte: self,
}
}
}
impl<'a, const FORMAT: u128> Iter<'a> for Bytes<'a, FORMAT> {
const IS_CONTIGUOUS: bool = NumberFormat::<{ FORMAT }>::DIGIT_SEPARATOR == 0;
#[inline(always)]
fn get_buffer(&self) -> &'a [u8] {
self.slc
}
#[inline(always)]
fn cursor(&self) -> usize {
self.index
}
#[inline(always)]
unsafe fn set_cursor(&mut self, index: usize) {
debug_assert!(index <= self.buffer_length());
self.index = index
}
#[inline(always)]
fn current_count(&self) -> usize {
if Self::IS_CONTIGUOUS {
self.index
} else {
self.count
}
}
#[inline(always)]
unsafe fn step_by_unchecked(&mut self, count: usize) {
if Self::IS_CONTIGUOUS {
debug_assert!(self.as_slice().len() >= count);
} else {
let format = NumberFormat::<{ FORMAT }> {};
debug_assert!(self.as_slice().len() >= count);
debug_assert!(count == 0 || count == 1);
debug_assert!(
count == 0 || self.slc.get(self.index) != Some(&format.digit_separator())
);
}
self.index += count;
if !Self::IS_CONTIGUOUS {
self.count += count;
}
}
#[inline(always)]
unsafe fn peek_many_unchecked<V>(&self) -> V {
debug_assert!(Self::IS_CONTIGUOUS);
debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
let slc = self.as_slice();
unsafe { ptr::read_unaligned::<V>(slc.as_ptr() as *const _) }
}
}
macro_rules! skip_iterator {
($iterator:ident, $doc:literal) => {
#[doc = $doc]
pub struct $iterator<'a: 'b, 'b, const FORMAT: u128> {
byte: &'b mut Bytes<'a, FORMAT>,
}
};
}
macro_rules! is_digit_separator {
($format:ident) => {
pub const fn is_digit_separator(&self, value: u8) -> bool {
let format = NumberFormat::<{ $format }> {};
let digit_separator = format.digit_separator();
if digit_separator == 0 {
false
} else {
value == digit_separator
}
}
};
}
macro_rules! skip_iterator_impl {
($iterator:ident, $radix_cb:ident) => {
impl<'a: 'b, 'b, const FORMAT: u128> $iterator<'a, 'b, FORMAT> {
is_digit_separator!(FORMAT);
pub fn new(byte: &'b mut Bytes<'a, FORMAT>) -> Self {
Self {
byte,
}
}
#[cfg_attr(not(feature = "compact"), inline(always))]
#[allow(clippy::assertions_on_constants)]
pub fn take_n(&mut self, n: usize) -> Option<Bytes<'a, FORMAT>> {
if Self::IS_CONTIGUOUS {
let end = self.byte.slc.len().min(n + self.cursor());
let slc: &[u8] = &self.byte.slc[..end];
unsafe {
let byte: Bytes<'_, FORMAT> = Bytes::from_parts(slc, self.cursor());
unsafe { self.set_cursor(end) };
Some(byte)
}
} else {
None
}
}
}
};
}
macro_rules! skip_iterator_iterator_impl {
($iterator:ident) => {
impl<'a: 'b, 'b, const FORMAT: u128> Iterator for $iterator<'a, 'b, FORMAT> {
type Item = &'a u8;
#[inline(always)]
fn next(&mut self) -> Option<Self::Item> {
let value = self.peek()?;
self.byte.index += 1;
if !Self::IS_CONTIGUOUS {
self.byte.count += 1;
}
Some(value)
}
}
};
}
macro_rules! skip_iterator_iter_base {
($format:ident, $mask:ident) => {
const IS_CONTIGUOUS: bool = $format & flags::$mask == 0;
#[inline(always)]
fn get_buffer(&self) -> &'a [u8] {
self.byte.get_buffer()
}
#[inline(always)]
fn cursor(&self) -> usize {
self.byte.cursor()
}
#[inline(always)]
unsafe fn set_cursor(&mut self, index: usize) {
debug_assert!(index <= self.buffer_length());
unsafe { self.byte.set_cursor(index) };
}
#[inline(always)]
fn current_count(&self) -> usize {
self.byte.current_count()
}
#[inline(always)]
unsafe fn step_by_unchecked(&mut self, count: usize) {
debug_assert!(self.as_slice().len() >= count);
unsafe { self.byte.step_by_unchecked(count) }
}
#[inline(always)]
unsafe fn peek_many_unchecked<V>(&self) -> V {
debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
unsafe { self.byte.peek_many_unchecked() }
}
};
}
macro_rules! skip_iterator_digits_iter_base {
() => {
#[inline(always)]
fn is_consumed(&mut self) -> bool {
self.peek().is_none()
}
};
}
macro_rules! skip_iterator_bytesiter_impl {
($iterator:ident, $mask:ident, $i:ident, $l:ident, $t:ident, $c:ident) => {
impl<'a: 'b, 'b, const FORMAT: u128> Iter<'a> for $iterator<'a, 'b, FORMAT> {
skip_iterator_iter_base!(FORMAT, $mask);
}
impl<'a: 'b, 'b, const FORMAT: u128> DigitsIter<'a> for $iterator<'a, 'b, FORMAT> {
skip_iterator_digits_iter_base!();
#[inline(always)]
fn peek(&mut self) -> Option<<Self as Iterator>::Item> {
let format = NumberFormat::<{ FORMAT }> {};
const IL: u128 = flags::$i | flags::$l;
const IT: u128 = flags::$i | flags::$t;
const LT: u128 = flags::$l | flags::$t;
const ILT: u128 = flags::$i | flags::$l | flags::$t;
const IC: u128 = flags::$i | flags::$c;
const LC: u128 = flags::$l | flags::$c;
const TC: u128 = flags::$t | flags::$c;
const ILC: u128 = IL | flags::$c;
const ITC: u128 = IT | flags::$c;
const LTC: u128 = LT | flags::$c;
const ILTC: u128 = ILT | flags::$c;
match format.digit_separator_flags() & flags::$mask {
0 => peek_noskip!(self),
flags::$i => peek_i!(self),
flags::$l => peek_l!(self),
flags::$t => peek_t!(self),
IL => peek_il!(self),
IT => peek_it!(self),
LT => peek_lt!(self),
ILT => peek_ilt!(self),
IC => peek_ic!(self),
LC => peek_lc!(self),
TC => peek_tc!(self),
ILC => peek_ilc!(self),
ITC => peek_itc!(self),
LTC => peek_ltc!(self),
ILTC => peek_iltc!(self),
_ => unreachable!(),
}
}
#[inline(always)]
fn is_digit(&self, value: u8) -> bool {
let format = NumberFormat::<{ FORMAT }> {};
char_is_digit_const(value, format.mantissa_radix())
}
}
};
}
skip_iterator!(IntegerDigitsIterator, "Iterator that skips over digit separators in the integer.");
skip_iterator_impl!(IntegerDigitsIterator, mantissa_radix);
skip_iterator_iterator_impl!(IntegerDigitsIterator);
skip_iterator_bytesiter_impl!(
IntegerDigitsIterator,
INTEGER_DIGIT_SEPARATOR_FLAG_MASK,
INTEGER_INTERNAL_DIGIT_SEPARATOR,
INTEGER_LEADING_DIGIT_SEPARATOR,
INTEGER_TRAILING_DIGIT_SEPARATOR,
INTEGER_CONSECUTIVE_DIGIT_SEPARATOR
);
skip_iterator!(
FractionDigitsIterator,
"Iterator that skips over digit separators in the fraction."
);
skip_iterator_impl!(FractionDigitsIterator, mantissa_radix);
skip_iterator_iterator_impl!(FractionDigitsIterator);
skip_iterator_bytesiter_impl!(
FractionDigitsIterator,
FRACTION_DIGIT_SEPARATOR_FLAG_MASK,
FRACTION_INTERNAL_DIGIT_SEPARATOR,
FRACTION_LEADING_DIGIT_SEPARATOR,
FRACTION_TRAILING_DIGIT_SEPARATOR,
FRACTION_CONSECUTIVE_DIGIT_SEPARATOR
);
skip_iterator!(
ExponentDigitsIterator,
"Iterator that skips over digit separators in the exponent."
);
skip_iterator_impl!(ExponentDigitsIterator, exponent_radix);
skip_iterator_iterator_impl!(ExponentDigitsIterator);
skip_iterator_bytesiter_impl!(
ExponentDigitsIterator,
EXPONENT_DIGIT_SEPARATOR_FLAG_MASK,
EXPONENT_INTERNAL_DIGIT_SEPARATOR,
EXPONENT_LEADING_DIGIT_SEPARATOR,
EXPONENT_TRAILING_DIGIT_SEPARATOR,
EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR
);
skip_iterator!(
SpecialDigitsIterator,
"Iterator that skips over digit separators in special floats."
);
skip_iterator_iterator_impl!(SpecialDigitsIterator);
impl<'a: 'b, 'b, const FORMAT: u128> SpecialDigitsIterator<'a, 'b, FORMAT> {
is_digit_separator!(FORMAT);
}
impl<'a: 'b, 'b, const FORMAT: u128> Iter<'a> for SpecialDigitsIterator<'a, 'b, FORMAT> {
skip_iterator_iter_base!(FORMAT, SPECIAL_DIGIT_SEPARATOR);
}
impl<'a: 'b, 'b, const FORMAT: u128> DigitsIter<'a> for SpecialDigitsIterator<'a, 'b, FORMAT> {
skip_iterator_digits_iter_base!();
#[inline(always)]
fn peek(&mut self) -> Option<<Self as Iterator>::Item> {
let format = NumberFormat::<{ FORMAT }> {};
if format.special_digit_separator() {
peek_iltc!(self)
} else {
peek_noskip!(self)
}
}
#[inline(always)]
fn is_digit(&self, value: u8) -> bool {
let format = NumberFormat::<{ FORMAT }> {};
char_is_digit_const(value, format.mantissa_radix())
}
}