diff --git a/CHANGELOG b/CHANGELOG index 0dda1435..78b53391 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.0.0] 2024-09-16 + ### Changed - Fixes a correctness regression diff --git a/lexical-util/Cargo.toml b/lexical-util/Cargo.toml index 0c74fe20..ca9e79d8 100644 --- a/lexical-util/Cargo.toml +++ b/lexical-util/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT/Apache-2.0" name = "lexical-util" readme = "README.md" repository = "https://github.com/Alexhuszagh/rust-lexical" -version = "1.0.1" +version = "1.0.2" exclude = [ "assets/*", "docs/*", diff --git a/lexical-util/src/iterator.rs b/lexical-util/src/iterator.rs index c70e9116..f944cce1 100644 --- a/lexical-util/src/iterator.rs +++ b/lexical-util/src/iterator.rs @@ -20,8 +20,23 @@ pub use crate::skip::{AsBytes, Bytes}; /// methods for reading data and accessing underlying data. The readers /// can either be contiguous or non-contiguous, although performance and /// some API methods may not be available for both. +/// +/// # Safety +/// +/// Safe if [set_cursor] is set to an index <= [buffer_length], so no out-of-bounds +/// reads can occur. Also, [get_buffer] must return a slice of initialized bytes. +/// The caller must also ensure that any calls that increment the cursor, such +/// as [step_by_unchecked], [step_unchecked], and [peek_many_unchecked] never +/// exceed [buffer_length] as well. +/// +/// [set_cursor] Iter::set_cursor +/// [buffer_length] Iter::buffer_length +/// [get_buffer]: Iter::get_buffer +/// [step_by_unchecked]: Iter::step_by_unchecked +/// [step_unchecked]: Iter::step_unchecked +/// [peek_many_unchecked]: Iter::peek_many_unchecked #[cfg(feature = "parse")] -pub trait Iter<'a> { +pub unsafe trait Iter<'a> { /// Determine if the buffer is contiguous in memory. const IS_CONTIGUOUS: bool; @@ -233,7 +248,6 @@ pub trait Iter<'a> { /// This trait **should never** return `null` from `as_ptr`, or be /// implemented for non-contiguous data. pub trait DigitsIter<'a>: Iterator + Iter<'a> { - // TODO: Fix the documentation /// Get if the iterator cannot return any more elements. /// /// This may advance the internal iterator state, but not diff --git a/lexical-util/src/noskip.rs b/lexical-util/src/noskip.rs index 2af26191..e71d5e0b 100644 --- a/lexical-util/src/noskip.rs +++ b/lexical-util/src/noskip.rs @@ -100,7 +100,7 @@ impl<'a, const __: u128> Bytes<'a, __> { } } -impl<'a, const __: u128> Iter<'a> for Bytes<'a, __> { +unsafe impl<'a, const __: u128> Iter<'a> for Bytes<'a, __> { const IS_CONTIGUOUS: bool = true; #[inline(always)] @@ -139,7 +139,7 @@ impl<'a, const __: u128> Iter<'a> for Bytes<'a, __> { #[inline(always)] #[allow(clippy::assertions_on_constants)] unsafe fn step_by_unchecked(&mut self, count: usize) { - debug_assert!(Self::IS_CONTIGUOUS); + assert!(Self::IS_CONTIGUOUS); debug_assert!(self.as_slice().len() >= count); self.index += count; } @@ -199,7 +199,7 @@ impl<'a: 'b, 'b, const __: u128> DigitsIterator<'a, 'b, __> { } } -impl<'a: 'b, 'b, const __: u128> Iter<'a> for DigitsIterator<'a, 'b, __> { +unsafe impl<'a: 'b, 'b, const __: u128> Iter<'a> for DigitsIterator<'a, 'b, __> { const IS_CONTIGUOUS: bool = Bytes::<'a, __>::IS_CONTIGUOUS; #[inline(always)] diff --git a/lexical-util/src/skip.rs b/lexical-util/src/skip.rs index 3aa62776..8337e26c 100644 --- a/lexical-util/src/skip.rs +++ b/lexical-util/src/skip.rs @@ -416,7 +416,7 @@ impl<'a, const FORMAT: u128> Bytes<'a, FORMAT> { } } -impl<'a, const FORMAT: u128> Iter<'a> for Bytes<'a, FORMAT> { +unsafe impl<'a, const FORMAT: u128> Iter<'a> for Bytes<'a, FORMAT> { /// If each yielded value is adjacent in memory. const IS_CONTIGUOUS: bool = NumberFormat::<{ FORMAT }>::DIGIT_SEPARATOR == 0; @@ -646,7 +646,7 @@ macro_rules! skip_iterator_digits_iter_base { /// Create impl ByteIter block for skip iterator. 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> { + unsafe impl<'a: 'b, 'b, const FORMAT: u128> Iter<'a> for $iterator<'a, 'b, FORMAT> { skip_iterator_iter_base!(FORMAT, $mask); } @@ -763,7 +763,7 @@ 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> { +unsafe impl<'a: 'b, 'b, const FORMAT: u128> Iter<'a> for SpecialDigitsIterator<'a, 'b, FORMAT> { skip_iterator_iter_base!(FORMAT, SPECIAL_DIGIT_SEPARATOR); }