use core::str;
use std::ops::RangeBounds;
use winnow::ascii::{digit1, Int, Uint};
use winnow::combinator::{alt, trace};
use winnow::error::ParserError;
use winnow::stream::{AsBStr, AsChar, Compare, Stream, StreamIsPartial};
use winnow::token::{literal, take_while};
use winnow::Parser;
pub fn digit_1<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("digit_1", move |input: &mut Input| {
take_exact_digits(input, 1)
})
.parse_next(input)
}
pub fn digit_2<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("digit_2", move |input: &mut Input| {
take_exact_digits(input, 2)
})
.parse_next(input)
}
pub fn digit_3<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("digit_3", move |input: &mut Input| {
take_exact_digits(input, 3)
})
.parse_next(input)
}
pub fn digit_4<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("digit_4", move |input: &mut Input| {
take_exact_digits(input, 4)
})
.parse_next(input)
}
pub fn digit_6<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("digit_6", move |input: &mut Input| {
take_exact_digits(input, 2)
})
.parse_next(input)
}
pub(crate) fn take_exact_digits<Input, Error>(
input: &mut Input,
places: usize,
) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
let n = take_while(places, AsChar::is_dec_digit).parse_next(input)?;
let n = String::from_utf8_lossy(n.as_bstr());
let n = u32::try_from_dec_uint(n.as_ref()).unwrap();
Ok(n)
}
pub fn take_digits<'i, Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream + Compare<&'i str>,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("take_digits", move |input: &mut Input| {
let out = take_while(1.., AsChar::is_dec_digit).parse_next(input)?;
let out = String::from_utf8_lossy(out.as_bstr());
let out = u32::try_from_dec_uint(out.as_ref()).unwrap();
Ok(out)
})
.parse_next(input)
}
pub fn take_digits_in_range<Input, Error>(
input: &mut Input,
places: usize,
range: impl RangeBounds<u32>,
) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
let out = take_while(places, AsChar::is_dec_digit).parse_next(input)?;
let out = String::from_utf8_lossy(out.as_bstr());
let out = u32::try_from_dec_uint(out.as_ref()).unwrap();
if range.contains(&out) {
Ok(out)
} else {
Err(ParserError::from_input(input))
}
}
pub fn sign<'a, Input, Error>(input: &mut Input) -> Result<i32, Error>
where
Input: StreamIsPartial + Stream + Compare<&'a str>,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("sign", move |input: &mut Input| {
let i = alt((literal("-"), literal("+")))
.map(|s: <Input as Stream>::Slice| match s.as_bstr() {
b"-" => "-1",
_ => "1",
})
.parse_next(input)?;
Ok(i32::try_from_dec_int(i).unwrap())
})
.parse_next(input)
}
pub fn date_month<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("date_month", move |input: &mut Input| {
take_digits_in_range(input, 2, 1..=12)
})
.parse_next(input)
}
pub fn date_day<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("date_day", move |input: &mut Input| {
take_digits_in_range(input, 2, 1..=31)
})
.parse_next(input)
}
pub fn time_hour<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("time_hour", move |input: &mut Input| {
take_digits_in_range(input, 2, 0..=23)
})
.parse_next(input)
}
pub fn time_minute<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("time_minute", move |input: &mut Input| {
take_digits_in_range(input, 2, 0..=59)
})
.parse_next(input)
}
pub fn time_second<Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar + Clone,
Error: ParserError<Input>,
{
trace("time_second", move |input: &mut Input| {
take_digits_in_range(input, 2, 0..=60)
})
.parse_next(input)
}
pub fn fraction_millisecond<'i, Input, Error>(input: &mut Input) -> Result<u32, Error>
where
Input: StreamIsPartial + Stream,
<Input as Stream>::Slice: AsBStr,
<Input as Stream>::Token: AsChar,
Error: ParserError<Input>,
{
trace("fraction_millisecond", move |input: &mut Input| {
let d = digit1(input)?;
let mut digits = d.as_bstr();
let mut l = digits.len();
if l > 3 {
digits = digits.get(0..3).unwrap();
}
let mut result = 0;
if l > 0 {
let digits = str::from_utf8(digits).unwrap(); result = digits.parse().unwrap();
}
while l < 3 {
result *= 10;
l += 1;
}
Ok(result)
})
.parse_next(input)
}