diff --git a/src/ascii/mod.rs b/src/ascii/mod.rs index 824baee6..827b683c 100644 --- a/src/ascii/mod.rs +++ b/src/ascii/mod.rs @@ -9,6 +9,9 @@ use crate::lib::std::ops::{Add, Shl}; use crate::combinator::alt; use crate::combinator::cut_err; +use crate::combinator::dispatch; +use crate::combinator::empty; +use crate::combinator::fail; use crate::combinator::opt; use crate::combinator::trace; use crate::error::ParserError; @@ -16,6 +19,7 @@ use crate::error::{ErrMode, ErrorKind, Needed}; use crate::stream::FindSlice; use crate::stream::{AsBStr, AsChar, ParseSlice, Stream, StreamIsPartial}; use crate::stream::{Compare, CompareResult}; +use crate::token::any; use crate::token::one_of; use crate::token::take_until; use crate::token::take_while; @@ -906,149 +910,63 @@ pub fn dec_uint>(input: &mut I) -> PResult where I: StreamIsPartial, I: Stream, + ::Slice: AsBStr, ::Token: AsChar + Clone, O: Uint, { trace("dec_uint", move |input: &mut I| { - if input.eof_offset() == 0 { - if ::is_partial_supported() && input.is_partial() { - return Err(ErrMode::Incomplete(Needed::new(1))); - } else { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } - } - - let mut value = O::default(); - for (offset, c) in input.iter_offsets() { - match c.as_char().to_digit(10) { - Some(d) => match value.checked_mul(10, sealed::SealedMarker).and_then(|v| { - let d = d as u8; - v.checked_add(d, sealed::SealedMarker) - }) { - None => return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)), - Some(v) => value = v, - }, - None => { - if offset == 0 { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } else { - let _ = input.next_slice(offset); - return Ok(value); - } - } - } - } - - if ::is_partial_supported() && input.is_partial() { - Err(ErrMode::Incomplete(Needed::new(1))) - } else { - let _ = input.finish(); - Ok(value) - } + (one_of('1'..='9'), digit0) + .recognize() + .verify_map(|s: ::Slice| { + let s = s.as_bstr(); + // SAFETY: Only 7-bit ASCII characters are parsed + let s = unsafe { crate::lib::std::str::from_utf8_unchecked(s) }; + O::try_from_dec_uint(s) + }) + .parse_next(input) }) .parse_next(input) } /// Metadata for parsing unsigned integers, see [`dec_uint`] -pub trait Uint: Default { - #[doc(hidden)] - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option; +pub trait Uint: Sized { #[doc(hidden)] - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option; + fn try_from_dec_uint(slice: &str) -> Option; } impl Uint for u8 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) + fn try_from_dec_uint(slice: &str) -> Option { + slice.parse().ok() } } impl Uint for u16 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) + fn try_from_dec_uint(slice: &str) -> Option { + slice.parse().ok() } } impl Uint for u32 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) + fn try_from_dec_uint(slice: &str) -> Option { + slice.parse().ok() } } impl Uint for u64 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) + fn try_from_dec_uint(slice: &str) -> Option { + slice.parse().ok() } } impl Uint for u128 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) + fn try_from_dec_uint(slice: &str) -> Option { + slice.parse().ok() } } -/// Deprecated since v0.5.17 -impl Uint for i8 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -/// Deprecated since v0.5.17 -impl Uint for i16 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -/// Deprecated since v0.5.17 -impl Uint for i32 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -/// Deprecated since v0.5.17 -impl Uint for i64 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) - } -} - -/// Deprecated since v0.5.17 -impl Uint for i128 { - fn checked_mul(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_mul(by as Self) - } - fn checked_add(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_add(by as Self) +impl Uint for usize { + fn try_from_dec_uint(slice: &str) -> Option { + slice.parse().ok() } } @@ -1066,94 +984,68 @@ pub fn dec_int>(input: &mut I) -> PResult where I: StreamIsPartial, I: Stream, + ::Slice: AsBStr, ::Token: AsChar + Clone, O: Int, { trace("dec_int", move |input: &mut I| { - fn sign(token: impl AsChar) -> bool { - let token = token.as_char(); - token == '+' || token == '-' - } - let sign = opt(crate::token::one_of(sign).map(AsChar::as_char)) - .map(|c| c != Some('-')) - .parse_next(input)?; - - if input.eof_offset() == 0 { - if ::is_partial_supported() && input.is_partial() { - return Err(ErrMode::Incomplete(Needed::new(1))); - } else { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } - } - - let mut value = O::default(); - for (offset, c) in input.iter_offsets() { - match c.as_char().to_digit(10) { - Some(d) => match value.checked_mul(10, sealed::SealedMarker).and_then(|v| { - let d = d as u8; - if sign { - v.checked_add(d, sealed::SealedMarker) - } else { - v.checked_sub(d, sealed::SealedMarker) - } - }) { - None => return Err(ErrMode::from_error_kind(input, ErrorKind::Verify)), - Some(v) => value = v, - }, - None => { - if offset == 0 { - return Err(ErrMode::from_error_kind(input, ErrorKind::Slice)); - } else { - let _ = input.next_slice(offset); - return Ok(value); - } - } - } - } - - if ::is_partial_supported() && input.is_partial() { - Err(ErrMode::Incomplete(Needed::new(1))) - } else { - let _ = input.finish(); - Ok(value) - } + let sign = opt(dispatch! {any.map(AsChar::as_char); + '+' => empty.value(true), + '-' => empty.value(false), + _ => fail, + }); + (sign, one_of('1'..='9'), digit0) + .recognize() + .verify_map(|s: ::Slice| { + let s = s.as_bstr(); + // SAFETY: Only 7-bit ASCII characters are parsed + let s = unsafe { crate::lib::std::str::from_utf8_unchecked(s) }; + O::try_from_dec_int(s) + }) + .parse_next(input) }) .parse_next(input) } /// Metadata for parsing signed integers, see [`dec_int`] -pub trait Int: Uint { +pub trait Int: Sized { #[doc(hidden)] - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option; + fn try_from_dec_int(slice: &str) -> Option; } impl Int for i8 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) + fn try_from_dec_int(slice: &str) -> Option { + slice.parse().ok() } } impl Int for i16 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) + fn try_from_dec_int(slice: &str) -> Option { + slice.parse().ok() } } impl Int for i32 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) + fn try_from_dec_int(slice: &str) -> Option { + slice.parse().ok() } } impl Int for i64 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) + fn try_from_dec_int(slice: &str) -> Option { + slice.parse().ok() } } impl Int for i128 { - fn checked_sub(self, by: u8, _: sealed::SealedMarker) -> Option { - self.checked_sub(by as Self) + fn try_from_dec_int(slice: &str) -> Option { + slice.parse().ok() + } +} + +impl Int for isize { + fn try_from_dec_int(slice: &str) -> Option { + slice.parse().ok() } } diff --git a/src/ascii/tests.rs b/src/ascii/tests.rs index e68988aa..9ba4df24 100644 --- a/src/ascii/tests.rs +++ b/src/ascii/tests.rs @@ -4,7 +4,6 @@ use crate::prelude::*; mod complete { use super::*; use crate::combinator::alt; - use crate::combinator::opt; use crate::error::ErrMode; use crate::error::ErrorKind; use crate::error::InputError; @@ -427,54 +426,6 @@ mod complete { ); } - fn digit_to_i16(input: &str) -> IResult<&str, i16> { - let i = input; - let (i, opt_sign) = opt(alt(('+', '-'))).parse_peek(i)?; - let sign = match opt_sign { - Some('+') | None => true, - Some('-') => false, - _ => unreachable!(), - }; - - let (i, s) = digit1::<_, InputError<_>>.parse_peek(i)?; - match s.parse_slice() { - Some(n) => { - if sign { - Ok((i, n)) - } else { - Ok((i, -n)) - } - } - None => Err(ErrMode::from_error_kind(&i, ErrorKind::Verify)), - } - } - - fn digit_to_u32(i: &str) -> IResult<&str, u32> { - let (i, s) = digit1.parse_peek(i)?; - match s.parse_slice() { - Some(n) => Ok((i, n)), - None => Err(ErrMode::from_error_kind(&i, ErrorKind::Verify)), - } - } - - proptest! { - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn ints(s in "\\PC*") { - let res1 = digit_to_i16(&s); - let res2 = dec_int.parse_peek(s.as_str()); - assert_eq!(res1, res2); - } - - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn uints(s in "\\PC*") { - let res1 = digit_to_u32(&s); - let res2 = dec_uint.parse_peek(s.as_str()); - assert_eq!(res1, res2); - } - } - #[test] fn hex_uint_tests() { fn hex_u32(input: &[u8]) -> IResult<&[u8], u32> { @@ -900,14 +851,11 @@ mod complete { mod partial { use super::*; - use crate::combinator::opt; use crate::error::ErrorKind; use crate::error::InputError; use crate::error::{ErrMode, Needed}; - use crate::stream::ParseSlice; use crate::IResult; use crate::Partial; - use proptest::prelude::*; macro_rules! assert_parse( ($left: expr, $right: expr) => { @@ -1454,54 +1402,6 @@ mod partial { ); } - fn digit_to_i16(input: Partial<&str>) -> IResult, i16> { - let i = input; - let (i, opt_sign) = opt(one_of(['+', '-'])).parse_peek(i)?; - let sign = match opt_sign { - Some('+') | None => true, - Some('-') => false, - _ => unreachable!(), - }; - - let (i, s) = digit1::<_, InputError<_>>.parse_peek(i)?; - match s.parse_slice() { - Some(n) => { - if sign { - Ok((i, n)) - } else { - Ok((i, -n)) - } - } - None => Err(ErrMode::from_error_kind(&i, ErrorKind::Verify)), - } - } - - fn digit_to_u32(i: Partial<&str>) -> IResult, u32> { - let (i, s) = digit1.parse_peek(i)?; - match s.parse_slice() { - Some(n) => Ok((i, n)), - None => Err(ErrMode::from_error_kind(&i, ErrorKind::Verify)), - } - } - - proptest! { - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn ints(s in "\\PC*") { - let res1 = digit_to_i16(Partial::new(&s)); - let res2 = dec_int.parse_peek(Partial::new(s.as_str())); - assert_eq!(res1, res2); - } - - #[test] - #[cfg_attr(miri, ignore)] // See https://github.com/AltSysrq/proptest/issues/253 - fn uints(s in "\\PC*") { - let res1 = digit_to_u32(Partial::new(&s)); - let res2 = dec_uint.parse_peek(Partial::new(s.as_str())); - assert_eq!(res1, res2); - } - } - #[test] fn hex_uint_tests() { fn hex_u32(input: Partial<&[u8]>) -> IResult, u32> { diff --git a/src/combinator/multi.rs b/src/combinator/multi.rs index 3e95c94a..bdaa717b 100644 --- a/src/combinator/multi.rs +++ b/src/combinator/multi.rs @@ -1004,8 +1004,8 @@ where /// } /// /// assert_eq!(parser("9-3-5"), Ok(("", 1))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice)))); -/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Token)))); +/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Verify)))); /// ``` pub fn separated_foldl1( mut parser: P, @@ -1072,8 +1072,8 @@ where /// /// assert_eq!(parser("2^3^2"), Ok(("", 512))); /// assert_eq!(parser("2"), Ok(("", 2))); -/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Slice)))); -/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Slice)))); +/// assert_eq!(parser(""), Err(ErrMode::Backtrack(InputError::new("", ErrorKind::Token)))); +/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(InputError::new("def|abc", ErrorKind::Verify)))); /// ``` #[cfg(feature = "alloc")] pub fn separated_foldr1(