diff --git a/lexical-parse-float/src/slow.rs b/lexical-parse-float/src/slow.rs index 26a0d903..3cba04b4 100644 --- a/lexical-parse-float/src/slow.rs +++ b/lexical-parse-float/src/slow.rs @@ -335,7 +335,7 @@ macro_rules! round_up_nonzero { // First try reading 8-digits at a time. if iter.is_contiguous() { - while let Some(value) = iter.read::() { + while let Some(value) = iter.read_u64() { // SAFETY: safe since we have at least 8 bytes in the buffer. unsafe { iter.step_by_unchecked(8) }; if value != 0x3030_3030_3030_3030 { diff --git a/lexical-parse-integer/src/algorithm.rs b/lexical-parse-integer/src/algorithm.rs index 3caedc61..43c21051 100644 --- a/lexical-parse-integer/src/algorithm.rs +++ b/lexical-parse-integer/src/algorithm.rs @@ -217,7 +217,7 @@ where debug_assert!(Iter::IS_CONTIGUOUS); // Read our digits, validate the input, and check from there. - let bytes = u32::from_le(iter.read::()?); + let bytes = u32::from_le(iter.read_u32()?); if is_4digits::(bytes) { // SAFETY: safe since we have at least 4 bytes in the buffer. unsafe { iter.step_by_unchecked(4) }; @@ -289,7 +289,7 @@ where debug_assert!(Iter::IS_CONTIGUOUS); // Read our digits, validate the input, and check from there. - let bytes = u64::from_le(iter.read::()?); + let bytes = u64::from_le(iter.read_u64()?); if is_8digits::(bytes) { // SAFETY: safe since we have at least 8 bytes in the buffer. unsafe { iter.step_by_unchecked(8) }; diff --git a/lexical-util/src/iterator.rs b/lexical-util/src/iterator.rs index bb5f86d7..77e004e3 100644 --- a/lexical-util/src/iterator.rs +++ b/lexical-util/src/iterator.rs @@ -120,9 +120,14 @@ pub trait BytesIter<'a>: Iterator { /// many bytes as the size of V. unsafe fn read_unchecked(&self) -> V; - /// Try to read a value of a different type from the iterator. + /// Try to read a the next four bytes as a u32. /// This advances the internal state of the iterator. - fn read(&self) -> Option; + fn read_u32(&self) -> Option; + + + /// Try to read the next eight bytes as a u64 + /// This advances the internal state of the iterator. + fn read_u64(&self) -> Option; /// Advance the internal slice by `N` elements. /// diff --git a/lexical-util/src/noskip.rs b/lexical-util/src/noskip.rs index 22c511be..292fff8a 100644 --- a/lexical-util/src/noskip.rs +++ b/lexical-util/src/noskip.rs @@ -105,7 +105,7 @@ impl<'a, const __: u128> Bytes<'a, __> { /// # Safety /// /// Safe as long as the number of the buffer is contains as least as - /// many bytes as the size of V. + /// many bytes as the size of V, and V is valid for all bit patterns. #[inline] #[allow(clippy::assertions_on_constants)] pub unsafe fn read_unchecked(&self) -> V { @@ -117,13 +117,26 @@ impl<'a, const __: u128> Bytes<'a, __> { unsafe { ptr::read_unaligned::(slc.as_ptr() as *const _) } } - /// Try to read a value of a different type from the iterator. + /// Try to read a the next four bytes as a u32. /// This advances the internal state of the iterator. #[inline] - pub fn read(&self) -> Option { - if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { + pub fn read_u32(&self) -> Option { + if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { // SAFETY: safe since we've guaranteed the buffer is greater than - // the number of elements read. + // the number of elements read. u32 is valid for all bit patterns + unsafe { Some(self.read_unchecked()) } + } else { + None + } + } + + /// Try to read the next eight bytes as a u64 + /// This advances the internal state of the iterator. + #[inline] + pub fn read_u64(&self) -> Option { + if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { + // SAFETY: safe since we've guaranteed the buffer is greater than + // the number of elements read. u64 is valid for all bit patterns unsafe { Some(self.read_unchecked()) } } else { None @@ -288,8 +301,13 @@ impl<'a: 'b, 'b, const __: u128> BytesIter<'a> for BytesIterator<'a, 'b, __> { } #[inline] - fn read(&self) -> Option { - self.byte.read() + fn read_u32(&self) -> Option { + self.byte.read_u32() + } + + #[inline] + fn read_u64(&self) -> Option { + self.byte.read_u64() } #[inline] diff --git a/lexical-util/src/skip.rs b/lexical-util/src/skip.rs index 4daaaa99..540e39a0 100644 --- a/lexical-util/src/skip.rs +++ b/lexical-util/src/skip.rs @@ -428,7 +428,7 @@ impl<'a, const FORMAT: u128> Bytes<'a, FORMAT> { /// # Safety /// /// Safe as long as the number of the buffer is contains as least as - /// many bytes as the size of V. + /// many bytes as the size of V, and V is valid for all bit patterns. #[inline] pub unsafe fn read_unchecked(&self) -> V { debug_assert!(Self::IS_CONTIGUOUS); @@ -439,19 +439,30 @@ impl<'a, const FORMAT: u128> Bytes<'a, FORMAT> { unsafe { ptr::read_unaligned::(slc.as_ptr() as *const _) } } - /// Try to read a value of a different type from the iterator. + /// Try to read a the next four bytes as a u32. /// This advances the internal state of the iterator. #[inline] - pub fn read(&self) -> Option { - if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { + unsafe fn read_u32(&self) -> Option { + if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { // SAFETY: safe since we've guaranteed the buffer is greater than - // the number of elements read. + // the number of elements read. u32 is valid for all bit patterns + unsafe { Some(self.read_unchecked()) } + } else { + None + } + } + /// Try to read a the next four bytes as a u32. + /// This advances the internal state of the iterator. + #[inline] + unsafe fn read_u64(&self) -> Option { + if Self::IS_CONTIGUOUS && self.as_slice().len() >= mem::size_of::() { + // SAFETY: safe since we've guaranteed the buffer is greater than + // the number of elements read. u64 is valid for all bit patterns unsafe { Some(self.read_unchecked()) } } else { None } } - /// Check if the next element is a given value. #[inline] pub fn first_is(&mut self, value: u8) -> bool {