#![cfg(all(feature = "format", feature = "parse"))]
use crate::digit::char_is_digit_const;
use crate::format::NumberFormat;
use crate::format_flags as flags;
use crate::iterator::BytesIter;
use core::{mem, ptr};
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.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]
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> {
pub const IS_CONTIGUOUS: bool = NumberFormat::<{ FORMAT }>::DIGIT_SEPARATOR == 0;
#[inline]
pub fn new(slc: &'a [u8]) -> Self {
Self {
slc,
index: 0,
count: 0,
}
}
#[inline]
pub fn as_ptr(&self) -> *const u8 {
self.as_slice().as_ptr()
}
#[inline]
pub fn as_slice(&self) -> &'a [u8] {
unsafe { self.slc.get_unchecked(self.index..) }
}
#[inline]
pub fn length(&self) -> usize {
self.slc.len()
}
#[inline]
pub fn cursor(&self) -> usize {
self.index
}
#[inline]
pub unsafe fn set_cursor(&mut self, index: usize) {
debug_assert!(index <= self.length());
self.index = index
}
#[inline]
pub fn current_count(&self) -> usize {
if Self::IS_CONTIGUOUS {
self.index
} else {
self.count
}
}
#[inline]
pub fn is_done(&self) -> bool {
self.index >= self.slc.len()
}
#[inline]
pub fn is_contiguous(&self) -> bool {
Self::IS_CONTIGUOUS
}
#[inline]
pub unsafe fn read_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 _) }
}
#[inline]
pub fn read<V>(&self) -> Option<V> {
if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::<V>() {
unsafe { Some(self.read_unchecked()) }
} else {
None
}
}
#[inline]
pub fn first_is(&mut self, value: u8) -> bool {
if let Some(&c) = self.slc.get(self.index) {
c == value
} else {
false
}
}
#[inline]
pub fn case_insensitive_first_is(&mut self, value: u8) -> bool {
if let Some(&c) = self.slc.get(self.index) {
c.to_ascii_lowercase() == value.to_ascii_lowercase()
} else {
false
}
}
#[inline]
pub fn integer_iter<'b>(&'b mut self) -> IntegerBytesIterator<'a, 'b, FORMAT> {
IntegerBytesIterator {
byte: self,
}
}
#[inline]
pub fn fraction_iter<'b>(&'b mut self) -> FractionBytesIterator<'a, 'b, FORMAT> {
FractionBytesIterator {
byte: self,
}
}
#[inline]
pub fn exponent_iter<'b>(&'b mut self) -> ExponentBytesIterator<'a, 'b, FORMAT> {
ExponentBytesIterator {
byte: self,
}
}
#[inline]
pub fn special_iter<'b>(&'b mut self) -> SpecialBytesIterator<'a, 'b, FORMAT> {
SpecialBytesIterator {
byte: self,
}
}
#[inline]
pub 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]
pub unsafe fn step_unchecked(&mut self) {
debug_assert!(!self.as_slice().is_empty());
unsafe { self.step_by_unchecked(1) };
}
}
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 const fn is_digit(&self, value: u8) -> bool {
let format = NumberFormat::<{ FORMAT }> {};
char_is_digit_const(value, format.$radix_cb())
}
}
};
}
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]
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_byteiter_base {
($format:ident, $mask:ident) => {
const IS_CONTIGUOUS: bool = $format & flags::$mask == 0;
#[inline]
fn as_ptr(&self) -> *const u8 {
self.byte.as_ptr()
}
#[inline]
fn as_slice(&self) -> &'a [u8] {
self.byte.as_slice()
}
#[inline]
fn length(&self) -> usize {
self.byte.length()
}
#[inline]
fn cursor(&self) -> usize {
self.byte.cursor()
}
#[inline]
unsafe fn set_cursor(&mut self, index: usize) {
debug_assert!(index <= self.length());
unsafe { self.byte.set_cursor(index) };
}
#[inline]
fn current_count(&self) -> usize {
self.byte.current_count()
}
#[inline]
fn is_consumed(&mut self) -> bool {
self.peek().is_none()
}
#[inline]
fn is_done(&self) -> bool {
self.byte.is_done()
}
#[inline]
fn is_contiguous(&self) -> bool {
Self::IS_CONTIGUOUS
}
#[inline]
unsafe fn peek_unchecked(&mut self) -> <Self as Iterator>::Item {
self.peek().unwrap()
}
#[inline]
unsafe fn read_unchecked<V>(&self) -> V {
debug_assert!(self.as_slice().len() >= mem::size_of::<V>());
unsafe { self.byte.read_unchecked() }
}
#[inline]
fn read<V>(&self) -> Option<V> {
self.byte.read()
}
#[inline]
unsafe fn step_by_unchecked(&mut self, count: usize) {
debug_assert!(self.as_slice().len() >= count);
unsafe { self.byte.step_by_unchecked(count) }
}
};
}
macro_rules! skip_iterator_byteiter_impl {
($iterator:ident, $mask:ident, $i:ident, $l:ident, $t:ident, $c:ident) => {
impl<'a: 'b, 'b, const FORMAT: u128> BytesIter<'a> for $iterator<'a, 'b, FORMAT> {
skip_iterator_byteiter_base!(FORMAT, $mask);
#[inline]
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!(),
}
}
}
};
}
skip_iterator!(IntegerBytesIterator, "Iterator that skips over digit separators in the integer.");
skip_iterator_impl!(IntegerBytesIterator, mantissa_radix);
skip_iterator_iterator_impl!(IntegerBytesIterator);
skip_iterator_byteiter_impl!(
IntegerBytesIterator,
INTEGER_DIGIT_SEPARATOR_FLAG_MASK,
INTEGER_INTERNAL_DIGIT_SEPARATOR,
INTEGER_LEADING_DIGIT_SEPARATOR,
INTEGER_TRAILING_DIGIT_SEPARATOR,
INTEGER_CONSECUTIVE_DIGIT_SEPARATOR
);
skip_iterator!(FractionBytesIterator, "Iterator that skips over digit separators in the fraction.");
skip_iterator_impl!(FractionBytesIterator, mantissa_radix);
skip_iterator_iterator_impl!(FractionBytesIterator);
skip_iterator_byteiter_impl!(
FractionBytesIterator,
FRACTION_DIGIT_SEPARATOR_FLAG_MASK,
FRACTION_INTERNAL_DIGIT_SEPARATOR,
FRACTION_LEADING_DIGIT_SEPARATOR,
FRACTION_TRAILING_DIGIT_SEPARATOR,
FRACTION_CONSECUTIVE_DIGIT_SEPARATOR
);
skip_iterator!(ExponentBytesIterator, "Iterator that skips over digit separators in the exponent.");
skip_iterator_impl!(ExponentBytesIterator, exponent_radix);
skip_iterator_iterator_impl!(ExponentBytesIterator);
skip_iterator_byteiter_impl!(
ExponentBytesIterator,
EXPONENT_DIGIT_SEPARATOR_FLAG_MASK,
EXPONENT_INTERNAL_DIGIT_SEPARATOR,
EXPONENT_LEADING_DIGIT_SEPARATOR,
EXPONENT_TRAILING_DIGIT_SEPARATOR,
EXPONENT_CONSECUTIVE_DIGIT_SEPARATOR
);
skip_iterator!(
SpecialBytesIterator,
"Iterator that skips over digit separators in special floats."
);
skip_iterator_iterator_impl!(SpecialBytesIterator);
impl<'a: 'b, 'b, const FORMAT: u128> SpecialBytesIterator<'a, 'b, FORMAT> {
is_digit_separator!(FORMAT);
}
impl<'a: 'b, 'b, const FORMAT: u128> BytesIter<'a> for SpecialBytesIterator<'a, 'b, FORMAT> {
skip_iterator_byteiter_base!(FORMAT, SPECIAL_DIGIT_SEPARATOR);
#[inline]
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)
}
}
}