1use std::cmp::Ordering::{Equal, Greater, Less};
10use std::str::Utf8Error;
11use std::time::Duration as StdDuration;
12
13use crate::config::{Config, DEFAULT_CONFIG, Delimiter, NumbersLike};
14use crate::error::ParseError;
15use crate::time::{Duration, Multiplier, TimeUnit, TimeUnitsLike};
16use crate::util::POW10;
17
18pub const ATTOS_PER_SEC: u64 = 1_000_000_000_000_000_000;
19pub const ATTOS_PER_SEC_U128: u128 = ATTOS_PER_SEC as u128;
20pub const ATTOS_PER_NANO: u64 = 1_000_000_000;
21pub const ATTOS_PER_NANO_U128: u128 = ATTOS_PER_NANO as u128;
22pub const NANOS_PER_SEC: u64 = 1_000_000_000;
23pub const NANOS_PER_SEC_U128: u128 = NANOS_PER_SEC as u128;
24pub const ATTOS_MAX: u64 = 999_999_999_999_999_999;
25pub const SECONDS_MAX: u64 = u64::MAX;
26pub const SECONDS_AND_ATTOS_MAX: (u64, u64) = (SECONDS_MAX, ATTOS_MAX);
27
28#[derive(Debug, PartialEq, Eq)]
88pub struct Parser<'a> {
89 pub config: Config<'a>,
94}
95
96impl<'a> Parser<'a> {
97 pub const fn new() -> Self {
99 Self {
100 config: DEFAULT_CONFIG,
101 }
102 }
103
104 pub const fn with_config(config: Config<'a>) -> Self {
106 Self { config }
107 }
108
109 #[inline]
110 pub fn parse_multiple(
111 &self,
112 source: &str,
113 time_units: &dyn TimeUnitsLike,
114 keywords: Option<&dyn TimeUnitsLike>,
115 numerals: Option<&dyn NumbersLike>,
116 ) -> Result<Duration, ParseError> {
117 let mut duration = Duration::ZERO;
118
119 let mut parser = &mut ReprParserMultiple::new(source);
120 loop {
121 let (mut duration_repr, maybe_parser) =
122 parser.parse(&self.config, time_units, keywords, numerals)?;
123 let parsed_duration = duration_repr.parse()?;
124 duration = if !self.config.allow_negative && parsed_duration.is_negative() {
125 return Err(ParseError::NegativeNumber);
126 } else if parsed_duration.is_zero() {
127 duration
128 } else if duration.is_zero() {
129 parsed_duration
130 } else {
131 duration.saturating_add(parsed_duration)
132 };
133 match maybe_parser {
134 Some(p) => parser = p,
135 None => break Ok(duration),
136 }
137 }
138 }
139
140 #[inline]
141 pub fn parse_single(
142 &self,
143 source: &str,
144 time_units: &dyn TimeUnitsLike,
145 keywords: Option<&dyn TimeUnitsLike>,
146 numerals: Option<&dyn NumbersLike>,
147 ) -> Result<Duration, ParseError> {
148 ReprParserSingle::new(source)
149 .parse(&self.config, time_units, keywords, numerals)
150 .and_then(|mut duration_repr| {
151 duration_repr.parse().and_then(|duration| {
152 if !self.config.allow_negative && duration.is_negative() {
153 Err(ParseError::NegativeNumber)
154 } else {
155 Ok(duration)
156 }
157 })
158 })
159 }
160
161 #[inline]
222 pub fn parse(
223 &self,
224 source: &str,
225 time_units: &dyn TimeUnitsLike,
226 keywords: Option<&dyn TimeUnitsLike>,
227 numerals: Option<&dyn NumbersLike>,
228 ) -> Result<Duration, ParseError> {
229 if self.config.allow_multiple {
230 self.parse_multiple(source, time_units, keywords, numerals)
231 } else {
232 self.parse_single(source, time_units, keywords, numerals)
233 }
234 }
235}
236
237impl Default for Parser<'_> {
238 fn default() -> Self {
239 Self::new()
240 }
241}
242
243pub trait Parse8Digits {
244 unsafe fn parse_8_digits(digits: &[u8]) -> u64 {
247 unsafe {
250 debug_assert!(
252 digits.len() >= 8,
253 "Call this method only if digits has length >= 8"
254 ); #[allow(clippy::cast_ptr_alignment)]
259 let ptr = digits.as_ptr().cast::<u64>();
260 let mut num = u64::from_le(ptr.read_unaligned());
261 num = ((num & 0x0F0F_0F0F_0F0F_0F0F).wrapping_mul(2561)) >> 8i32;
262 num = ((num & 0x00FF_00FF_00FF_00FF).wrapping_mul(6_553_601)) >> 16i32;
263 num = ((num & 0x0000_FFFF_0000_FFFF).wrapping_mul(42_949_672_960_001)) >> 32i32;
264 num
265 }
266 }
267}
268
269#[derive(Debug, PartialEq, Eq, Default, Copy, Clone)]
270pub struct Whole(pub usize, pub usize);
271
272impl Parse8Digits for Whole {}
273
274impl Whole {
275 pub fn parse_slice(mut seconds: u64, digits: &[u8]) -> Option<u64> {
276 if digits.len() >= 8 {
277 let mut iter = digits.chunks_exact(8);
278 for digits in iter.by_ref() {
279 match seconds
280 .checked_mul(100_000_000)
281 .and_then(|s| s.checked_add(unsafe { Self::parse_8_digits(digits) }))
283 {
284 Some(s) => seconds = s,
285 None => {
286 return None;
287 }
288 }
289 }
290 for num in iter.remainder() {
291 match seconds
292 .checked_mul(10)
293 .and_then(|s| s.checked_add(u64::from(*num - b'0')))
294 {
295 Some(s) => seconds = s,
296 None => {
297 return None;
298 }
299 }
300 }
301 } else {
302 for num in digits {
303 match seconds
304 .checked_mul(10)
305 .and_then(|s| s.checked_add(u64::from(*num - b'0')))
306 {
307 Some(s) => seconds = s,
308 None => {
309 return None;
310 }
311 }
312 }
313 }
314 Some(seconds)
315 }
316
317 pub fn parse(digits: &[u8], append: Option<&[u8]>, zeros: Option<usize>) -> Option<u64> {
318 if digits.is_empty() && append.is_none_or(<[u8]>::is_empty) {
319 return Some(0);
320 }
321
322 Self::parse_slice(0, digits).and_then(|s| {
323 append
324 .map_or(Some(s), |append| Self::parse_slice(s, append))
325 .and_then(|seconds| {
326 if seconds == 0 {
327 Some(0)
328 } else {
329 match zeros {
330 Some(num_zeros) if num_zeros > 0 => POW10
331 .get(num_zeros)
332 .and_then(|pow| seconds.checked_mul(*pow)),
333 Some(_) | None => Some(seconds),
334 }
335 }
336 })
337 })
338 }
339
340 #[inline]
341 pub const fn len(&self) -> usize {
342 self.1 - self.0
343 }
344
345 #[inline]
346 pub const fn is_empty(&self) -> bool {
347 self.1 == self.0
348 }
349}
350
351#[derive(Debug, PartialEq, Eq, Default, Copy, Clone)]
352pub struct Fract(pub usize, pub usize);
353
354impl Parse8Digits for Fract {}
355
356impl Fract {
357 pub fn parse_slice(mut attos: u64, max_to_parse: usize, digits: &[u8]) -> (u64, usize) {
358 let num_parsable = digits.len().min(max_to_parse);
359 if num_parsable >= 8 {
360 let mut iter = digits[..num_parsable].chunks_exact(8);
361 for digits in iter.by_ref() {
362 attos = attos * 100_000_000 + unsafe { Self::parse_8_digits(digits) };
364 }
365 for num in iter.remainder() {
366 attos = attos * 10 + u64::from(*num - b'0');
367 }
368 } else {
369 for num in &digits[..num_parsable] {
370 attos = attos * 10 + u64::from(*num - b'0');
371 }
372 }
373 (attos, max_to_parse - num_parsable)
374 }
375
376 pub fn parse(digits: &[u8], prepend: Option<&[u8]>, zeros: Option<usize>) -> u64 {
377 if digits.is_empty() && prepend.is_none_or(<[u8]>::is_empty) {
378 return 0;
379 }
380
381 let max_to_parse = match zeros {
382 Some(z) if z > 18 => return 0,
383 Some(z) => 18 - z,
384 None => 18,
385 };
386
387 match prepend {
388 Some(prepend) if !prepend.is_empty() => {
389 let (attos, remainder) = Self::parse_slice(0, max_to_parse, prepend);
390 if remainder == 0 {
391 attos
392 } else if digits.is_empty() {
393 attos * POW10[remainder]
394 } else {
395 let (attos, remainder) = Self::parse_slice(attos, remainder, digits);
396 if remainder > 0 {
397 attos * POW10[remainder]
398 } else {
399 attos
400 }
401 }
402 }
403 Some(_) | None => {
404 let (attos, remainder) = Self::parse_slice(0, max_to_parse, digits);
405 if remainder > 0 {
406 attos * POW10[remainder]
407 } else {
408 attos
409 }
410 }
411 }
412 }
413
414 #[inline]
415 pub const fn len(&self) -> usize {
416 self.1 - self.0
417 }
418
419 #[inline]
420 pub const fn is_empty(&self) -> bool {
421 self.1 == self.0
422 }
423}
424
425#[derive(Debug, Default)]
426pub struct DurationRepr<'a> {
427 pub default_unit: TimeUnit,
428 pub unit: Option<TimeUnit>,
429 pub is_negative: Option<bool>,
430 pub is_infinite: bool,
431 pub whole: Option<Whole>,
432 pub fract: Option<Fract>,
433 pub input: &'a [u8],
434 pub exponent: i16,
435 pub multiplier: Multiplier,
436 pub numeral: Option<Multiplier>,
437}
438
439impl DurationRepr<'_> {
440 #[allow(clippy::too_many_lines)]
441 pub fn parse(&mut self) -> Result<Duration, ParseError> {
442 if self.is_infinite {
443 return Ok(Duration::from_std(
444 self.is_negative.unwrap_or_default(),
445 StdDuration::MAX,
446 ));
447 }
448
449 if self.whole.is_none() && self.fract.is_none() {
450 return if let Some(numeral) = self.numeral {
451 let time_unit = self.unit.expect("Numeral without time unit");
452 let Multiplier(coefficient, exponent) =
453 numeral * time_unit.multiplier() * self.multiplier;
454
455 Ok(self.parse_duration_with_fixed_number(coefficient, exponent))
456 } else if self.unit.is_some() {
459 let time_unit = self.unit.unwrap_or(self.default_unit);
460 let Multiplier(coefficient, exponent) = time_unit.multiplier() * self.multiplier;
461
462 Ok(self.parse_duration_with_fixed_number(coefficient, exponent))
463 } else {
465 unreachable!() };
467 }
468
469 let time_unit = self.unit.unwrap_or(self.default_unit);
470 let Multiplier(coefficient, exponent) = time_unit.multiplier() * self.multiplier;
472 if coefficient == 0 {
473 return Ok(Duration::ZERO);
474 }
475 let exponent = i32::from(exponent) + i32::from(self.exponent);
476
477 let exponent_abs: usize = exponent.unsigned_abs().try_into().unwrap();
480 let duration_is_negative = self.is_negative.unwrap_or_default() ^ coefficient.is_negative();
481
482 let digits = self.input;
486 let (seconds, attos) = match (exponent.cmp(&0i32), &self.whole, &self.fract) {
487 (Less, Some(whole), fract) if whole.len() > exponent_abs => {
488 match Whole::parse(&digits[whole.0..whole.1 - exponent_abs], None, None) {
489 Some(seconds) => {
490 let attos = Fract::parse(
491 fract.map_or_else(|| [].as_ref(), |fract| &digits[fract.0..fract.1]),
492 Some(&digits[whole.1 - exponent_abs..whole.1]),
493 None,
494 );
495 (seconds, attos)
496 }
497 None if duration_is_negative => return Ok(Duration::MIN),
498 None => return Ok(Duration::MAX),
499 }
500 }
501 (Less, whole, fract) => {
502 let attos = match fract {
503 Some(fract) if fract.is_empty() => Fract::parse(
504 whole.map_or_else(|| [].as_ref(), |whole| &digits[whole.0..whole.1]),
505 None,
506 Some(exponent_abs - whole.map_or(0, |w| w.len())),
507 ),
508 Some(fract) => Fract::parse(
509 &digits[fract.0..fract.1],
510 whole.and_then(|whole| {
511 (!whole.is_empty()).then(|| &digits[whole.0..whole.1])
512 }),
513 Some(exponent_abs - whole.map_or(0, |w| w.len())),
514 ),
515 None => Fract::parse(
516 whole.map_or_else(|| [].as_ref(), |whole| &digits[whole.0..whole.1]),
517 None,
518 Some(exponent_abs - whole.map_or(0, |w| w.len())),
519 ),
520 };
521 (0, attos)
522 }
523 (Equal, whole, fract) => {
524 match whole.map_or(Some(0), |whole| {
525 Whole::parse(&digits[whole.0..whole.1], None, None)
526 }) {
527 Some(seconds) => {
528 let attos = fract.map_or(0, |fract| {
529 Fract::parse(&digits[fract.0..fract.1], None, None)
530 });
531 (seconds, attos)
532 }
533 None if duration_is_negative => return Ok(Duration::MIN),
534 None => return Ok(Duration::MAX),
535 }
536 }
537 (Greater, whole, Some(fract)) if fract.len() > exponent_abs => {
538 match Whole::parse(
539 whole.map_or_else(|| [].as_ref(), |whole| &digits[whole.0..whole.1]),
540 Some(&digits[fract.0..fract.0 + exponent_abs]),
541 None,
542 ) {
543 Some(seconds) => {
544 let attos =
545 Fract::parse(&digits[fract.0 + exponent_abs..fract.1], None, None);
546 (seconds, attos)
547 }
548 None if duration_is_negative => return Ok(Duration::MIN),
549 None => return Ok(Duration::MAX),
550 }
551 }
552 (Greater, whole, fract) => {
553 match Whole::parse(
554 whole.map_or_else(|| [].as_ref(), |whole| &digits[whole.0..whole.1]),
555 fract.map(|fract| &digits[fract.0..fract.1]),
556 Some(exponent_abs - fract.map_or(0, |fract| fract.len())),
557 ) {
558 Some(seconds) => (seconds, 0),
559 None if duration_is_negative => return Ok(Duration::MIN),
560 None => return Ok(Duration::MAX),
561 }
562 }
563 };
564
565 Ok(Self::calculate_duration(
566 duration_is_negative,
567 seconds,
568 attos,
569 coefficient,
570 ))
571 }
572
573 #[inline]
574 pub fn parse_duration_with_fixed_number(&self, coefficient: i64, exponent: i16) -> Duration {
575 if coefficient == 0 {
576 return Duration::ZERO;
577 }
578 let duration_is_negative = coefficient.is_negative() ^ self.is_negative.unwrap_or_default();
579 let (seconds, attos) = match exponent.cmp(&0i16) {
580 Less if exponent < -18 => return Duration::ZERO,
581 Less => (0, POW10[usize::try_from(18 + exponent).unwrap()]),
582 Equal => {
583 return Duration::from_std(
584 duration_is_negative,
585 StdDuration::new(coefficient.unsigned_abs(), 0),
586 );
587 }
588 Greater if exponent > 19 => {
589 return if coefficient.is_negative() {
590 Duration::MIN
591 } else {
592 Duration::MAX
593 };
594 }
595 Greater => (POW10[usize::try_from(exponent).unwrap()], 0),
596 };
597
598 Self::calculate_duration(duration_is_negative, seconds, attos, coefficient)
599 }
600
601 #[inline]
602 pub fn calculate_duration(
603 is_negative: bool,
604 seconds: u64,
605 attos: u64,
606 coefficient: i64,
607 ) -> Duration {
608 if (seconds == 0 && attos == 0) || coefficient == 0 {
609 Duration::ZERO
610 } else if attos == 0 {
611 let unsigned_coefficient = coefficient.unsigned_abs();
612 match seconds.checked_mul(unsigned_coefficient) {
613 Some(s) => Duration::from_std(is_negative, StdDuration::new(s, 0)),
614 None if is_negative => Duration::MIN,
615 None => Duration::MAX,
616 }
617 } else if coefficient == 1 || coefficient == -1 {
618 Duration::from_std(
619 is_negative,
620 StdDuration::new(seconds, (attos / ATTOS_PER_NANO).try_into().unwrap()),
621 )
622 } else {
623 let unsigned_coefficient = coefficient.unsigned_abs();
624 if let Some(attos) = unsigned_coefficient.checked_mul(attos) {
625 match seconds
626 .checked_mul(unsigned_coefficient)
627 .and_then(|s| s.checked_add(attos / ATTOS_PER_SEC))
628 {
629 Some(s) => Duration::from_std(
630 is_negative,
631 StdDuration::new(s, ((attos / ATTOS_PER_NANO) % NANOS_PER_SEC) as u32),
632 ),
633 None if is_negative => Duration::MIN,
634 None => Duration::MAX,
635 }
636 } else {
637 let time = seconds.checked_mul(unsigned_coefficient).and_then(|s| {
638 let attos = u128::from(attos) * u128::from(unsigned_coefficient);
639 s.checked_add((attos / ATTOS_PER_SEC_U128).try_into().unwrap())
640 .map(|s| (s, attos))
641 });
642 match time {
643 Some((s, attos)) => Duration::from_std(
644 is_negative,
645 StdDuration::new(
646 s,
647 ((attos / ATTOS_PER_NANO_U128) % NANOS_PER_SEC_U128) as u32,
648 ),
649 ),
650 None if is_negative => Duration::MIN,
651 None => Duration::MAX,
652 }
653 }
654 }
655 }
656}
657
658pub struct BytesRange(usize, usize);
659
660pub struct Bytes<'a> {
661 pub current_pos: usize, pub current_byte: Option<&'a u8>,
663 pub buffer: Option<(usize, &'a [u8], Option<&'a u8>)>,
664 pub input: &'a [u8],
665}
666
667impl<'a> Bytes<'a> {
668 #[inline]
669 pub const fn new(input: &'a [u8]) -> Self {
670 Self {
671 current_pos: 0,
672 current_byte: input.first(),
673 input,
674 buffer: None,
675 }
676 }
677
678 #[inline]
679 pub fn advance(&mut self) {
680 self.current_pos += 1;
681 self.current_byte = self.input.get(self.current_pos);
682 }
683
684 #[inline]
685 pub unsafe fn advance_by(&mut self, num: usize) {
686 self.current_pos += num;
687 self.current_byte = self.input.get(self.current_pos);
688 }
689
690 pub fn advance_to<F>(&mut self, delimiter: F) -> &'a [u8]
691 where
692 F: Fn(u8) -> bool,
693 {
694 let start = self.current_pos;
695 while let Some(byte) = self.current_byte {
696 if delimiter(*byte) {
697 break;
698 }
699 self.advance();
700 }
701 &self.input[start..self.current_pos]
702 }
703
704 pub fn buffered_advance_to<F>(&mut self, delimiter: F) -> &'a [u8]
705 where
706 F: Fn(u8) -> bool,
707 {
708 match self.buffer {
709 Some((pos, buffer, Some(next))) if pos == self.current_pos && delimiter(*next) => {
710 unsafe { self.advance_by(buffer.len()) };
713 buffer
714 }
715 Some((pos, buffer, None)) if pos == self.current_pos => {
716 unsafe { self.advance_by(buffer.len()) };
719 buffer
720 }
721 None | Some(_) => {
722 let start = self.current_pos;
723 while let Some(byte) = self.current_byte {
724 if delimiter(*byte) {
725 break;
726 }
727 self.advance();
728 }
729 let buffer = &self.input[start..self.current_pos];
730 self.buffer = Some((start, buffer, self.current_byte));
731 buffer
732 }
733 }
734 }
735
736 #[inline]
737 pub fn peek(&self, num: usize) -> Option<&[u8]> {
738 self.input.get(self.current_pos..self.current_pos + num)
739 }
740
741 #[inline]
742 pub fn get_remainder(&self) -> &[u8] {
743 &self.input[self.current_pos..]
744 }
745
746 #[inline]
747 pub unsafe fn get_remainder_str_unchecked(&self) -> &str {
748 unsafe { std::str::from_utf8_unchecked(self.get_remainder()) }
751 }
752
753 #[inline]
754 pub fn get_remainder_str(&self) -> Result<&str, ParseError> {
755 std::str::from_utf8(self.get_remainder())
756 .map_err(|err| ParseError::InvalidInput(err.to_string()))
757 }
758
759 #[inline]
760 pub fn get_current_str(&self, start: usize) -> Result<&str, Utf8Error> {
761 std::str::from_utf8(&self.input[start..self.current_pos])
762 }
763
764 #[inline]
765 pub fn finish(&mut self) {
766 self.current_pos = self.input.len();
767 self.current_byte = None;
768 }
769
770 #[inline]
771 pub fn reset(&mut self, position: usize) {
772 self.current_pos = position;
773 self.current_byte = self.input.get(position);
774 }
775
776 #[inline]
777 pub fn parse_digit(&mut self) -> Option<u8> {
778 self.current_byte.and_then(|byte| {
779 let digit = byte.wrapping_sub(b'0');
780 (digit < 10).then(|| {
781 self.advance();
782 *byte
783 })
784 })
785 }
786
787 pub fn parse_digits_strip_zeros(&mut self) -> BytesRange {
788 const ASCII_EIGHT_ZEROS: u64 = 0x3030_3030_3030_3030;
789
790 debug_assert!(self.current_byte.is_some_and(u8::is_ascii_digit)); let mut start = self.current_pos;
793 let mut strip_leading_zeros = true;
794 while let Some(eight) = self.parse_8_digits() {
795 if strip_leading_zeros {
796 if eight == ASCII_EIGHT_ZEROS {
797 start += 8;
798 } else {
799 strip_leading_zeros = false;
800
801 let leading_zeros = (eight - ASCII_EIGHT_ZEROS).trailing_zeros() / 8;
803 start += leading_zeros as usize;
804 }
805 }
806 }
807
808 while let Some(byte) = self.current_byte {
809 let digit = byte.wrapping_sub(b'0');
810 if digit < 10 {
811 if strip_leading_zeros {
812 if digit == 0 {
813 start += 1;
814 } else {
815 strip_leading_zeros = false;
816 }
817 }
818 self.advance();
819 } else {
820 break;
821 }
822 }
823
824 BytesRange(start, self.current_pos)
825 }
826
827 pub fn parse_digits(&mut self) -> BytesRange {
828 debug_assert!(self.current_byte.is_some_and(u8::is_ascii_digit)); let start = self.current_pos;
831 while self.parse_8_digits().is_some() {}
832 while self.parse_digit().is_some() {}
833
834 BytesRange(start, self.current_pos)
835 }
836
837 pub fn parse_8_digits(&mut self) -> Option<u64> {
840 self.input
841 .get(self.current_pos..(self.current_pos + 8))
842 .and_then(|digits| {
843 #[allow(clippy::cast_ptr_alignment)]
846 let ptr = digits.as_ptr().cast::<u64>();
847 let num = u64::from_le(unsafe { ptr.read_unaligned() });
849 ((num & (num.wrapping_add(0x0606_0606_0606_0606)) & 0xf0f0_f0f0_f0f0_f0f0)
850 == 0x3030_3030_3030_3030)
851 .then(|| {
852 unsafe { self.advance_by(8) }
854 num
855 })
856 })
857 }
858
859 #[inline]
860 pub fn next_is_ignore_ascii_case(&self, word: &[u8]) -> bool {
861 self.peek(word.len())
862 .is_some_and(|bytes| bytes.eq_ignore_ascii_case(word))
863 }
864
865 #[inline]
866 pub const fn is_end_of_input(&self) -> bool {
867 self.current_byte.is_none()
868 }
869
870 #[inline]
871 pub fn check_end_of_input(&self) -> Result<(), ParseError> {
872 self.current_byte.map_or(Ok(()), |_| {
873 self.get_remainder_str().and_then(|remainder| {
874 Err(ParseError::Syntax(
875 self.current_pos,
876 format!("Expected end of input but found: '{remainder}'"),
877 ))
878 })
879 })
880 }
881
882 pub fn try_consume_delimiter(&mut self, delimiter: Delimiter) -> Result<(), ParseError> {
883 debug_assert!(delimiter(*self.current_byte.unwrap())); if self.current_pos == 0 {
885 return Err(ParseError::Syntax(
886 0,
887 "Input may not start with a delimiter".to_owned(),
888 ));
889 }
890
891 let start = self.current_pos;
892 self.advance();
893 while let Some(byte) = self.current_byte {
894 if delimiter(*byte) {
895 self.advance();
896 } else {
897 break;
898 }
899 }
900
901 match self.current_byte {
902 Some(_) => Ok(()),
903 None => Err(ParseError::Syntax(
904 start,
905 "Input may not end with a delimiter".to_owned(),
906 )),
907 }
908 }
909}
910
911pub trait ReprParserTemplate<'a> {
912 type Output;
913
914 fn bytes(&mut self) -> &mut Bytes<'a>;
915
916 fn make_output(&'a mut self, duration_repr: DurationRepr<'a>) -> Self::Output;
917
918 fn parse_infinity_remainder(
919 &'a mut self,
920 duration_repr: DurationRepr<'a>,
921 config: &'a Config,
922 ) -> Result<Self::Output, ParseError>;
923
924 fn parse_keyword(
925 &mut self,
926 keywords: Option<&dyn TimeUnitsLike>,
927 config: &'a Config,
928 ) -> Result<Option<(TimeUnit, Multiplier)>, ParseError>;
929
930 fn parse_time_unit(
931 &mut self,
932 config: &'a Config,
933 time_units: &dyn TimeUnitsLike,
934 ) -> Result<Option<(TimeUnit, Multiplier)>, ParseError>;
935
936 fn parse_number_time_unit(
937 &mut self,
938 duration_repr: &mut DurationRepr<'a>,
939 config: &'a Config,
940 time_units: &dyn TimeUnitsLike,
941 ) -> Result<bool, ParseError>;
942
943 fn finalize(
944 &'a mut self,
945 duration_repr: DurationRepr<'a>,
946 config: &'a Config,
947 ) -> Result<Self::Output, ParseError>;
948
949 #[inline]
950 fn parse_whole(&mut self) -> Whole {
951 let BytesRange(start, end) = self.bytes().parse_digits_strip_zeros();
952 Whole(start, end)
953 }
954
955 #[inline]
956 fn parse_numeral(
957 &'_ mut self,
958 numerals: Option<&'a dyn NumbersLike>,
959 config: &'a Config,
960 ) -> Result<Option<(&'a str, Multiplier)>, ParseError> {
961 if let Some(numerals) = numerals {
962 let bytes = self.bytes();
963 let start = bytes.current_pos;
964 let buffer = bytes.buffered_advance_to(config.inner_delimiter);
965
966 if buffer.is_empty() {
967 return Ok(None); }
970 let string = unsafe { std::str::from_utf8_unchecked(buffer) };
973 return match numerals.get(string) {
974 None => {
975 bytes.reset(start);
976 Ok(None)
977 }
978 some_option => match bytes.current_byte {
979 Some(byte) if (config.inner_delimiter)(*byte) => {
980 bytes.try_consume_delimiter(config.inner_delimiter)?;
981 Ok(some_option.map(|m| (string, m)))
982 }
983 None | Some(_) => {
984 bytes.reset(start);
985 Ok(None)
986 }
987 },
988 };
989 }
990 Ok(None)
991 }
992
993 fn parse(
994 &'a mut self,
995 config: &'a Config,
996 time_units: &dyn TimeUnitsLike,
997 keywords: Option<&dyn TimeUnitsLike>,
998 numerals: Option<&'a dyn NumbersLike>,
999 ) -> Result<Self::Output, ParseError> {
1000 if self.bytes().current_byte.is_none() {
1001 return Err(ParseError::Empty);
1002 }
1003
1004 let mut duration_repr = DurationRepr {
1005 default_unit: config.default_unit,
1006 input: self.bytes().input,
1007 ..Default::default()
1008 };
1009
1010 self.parse_number_sign(&mut duration_repr, config)?;
1011
1012 match self.bytes().current_byte.copied() {
1014 Some(byte) if byte.is_ascii_digit() => {
1015 duration_repr.whole = Some(self.parse_whole());
1016 }
1017 Some(b'.') => {}
1018 Some(_)
1019 if !config.disable_infinity && self.bytes().next_is_ignore_ascii_case(b"inf") =>
1020 {
1021 unsafe { self.bytes().advance_by(3) }
1023 return self.parse_infinity_remainder(duration_repr, config);
1024 }
1025 Some(_) => {
1026 if let Some((unit, multi)) = self.parse_keyword(keywords, config)? {
1027 duration_repr.unit = Some(unit);
1028 duration_repr.multiplier = multi;
1029 return self.finalize(duration_repr, config);
1030 }
1031 if config.number_is_optional {
1032 let start = self.bytes().current_pos;
1033 match self.parse_time_unit(config, time_units)? {
1034 Some((time_unit, multiplier)) => {
1035 duration_repr.unit = Some(time_unit);
1036 duration_repr.multiplier = multiplier;
1037 return self.finalize(duration_repr, config);
1038 }
1039 None => {
1040 self.bytes().reset(start);
1041 }
1042 }
1043 }
1044 if let Some((id, numeral)) = self.parse_numeral(numerals, config)? {
1045 match self.parse_time_unit(config, time_units)? {
1046 Some((time_unit, multiplier)) => {
1047 duration_repr.numeral = Some(numeral);
1048 duration_repr.unit = Some(time_unit);
1049 duration_repr.multiplier = multiplier;
1050 return self.finalize(duration_repr, config);
1051 }
1052 None if time_units.is_empty() => {
1053 return Err(ParseError::TimeUnit(
1054 self.bytes().current_pos,
1055 format!("Found numeral '{id}' without time units being defined"),
1056 ));
1057 }
1058 None => {
1059 return Err(ParseError::TimeUnit(
1060 self.bytes().current_pos,
1061 format!("Found numeral '{id}' without a time unit"),
1062 ));
1063 }
1064 }
1065 }
1066 return self
1067 .bytes()
1068 .get_remainder_str()
1069 .and_then(|remainder| Err(ParseError::InvalidInput(remainder.to_owned())));
1070 }
1071 None => {
1075 return Err(ParseError::Syntax(
1076 self.bytes().current_pos,
1077 "Unexpected end of input".to_owned(),
1078 ));
1079 } }
1081
1082 if !self.parse_number_fraction(&mut duration_repr, config.disable_fraction)? {
1083 return Ok(self.make_output(duration_repr));
1084 }
1085
1086 if !self.parse_number_exponent(&mut duration_repr, config.disable_exponent)? {
1087 return Ok(self.make_output(duration_repr));
1088 }
1089
1090 if !self.parse_number_delimiter(
1091 config
1092 .allow_time_unit_delimiter
1093 .then_some(config.inner_delimiter),
1094 )? {
1095 return Ok(self.make_output(duration_repr));
1096 }
1097
1098 if !self.parse_number_time_unit(&mut duration_repr, config, time_units)? {
1099 return Ok(self.make_output(duration_repr)); }
1103
1104 self.finalize(duration_repr, config)
1105 }
1106
1107 fn parse_sign_is_negative(&mut self) -> Result<Option<bool>, ParseError> {
1109 let bytes = self.bytes();
1110 match bytes.current_byte {
1111 Some(byte) if *byte == b'+' => {
1112 bytes.advance();
1113 Ok(Some(false))
1114 }
1115 Some(byte) if *byte == b'-' => {
1116 bytes.advance();
1117 Ok(Some(true))
1118 }
1119 Some(_) => Ok(None),
1120 None => Err(ParseError::Syntax(
1121 bytes.current_pos,
1122 "Unexpected end of input".to_owned(),
1123 )),
1124 }
1125 }
1126
1127 fn parse_number_sign(
1128 &mut self,
1129 duration_repr: &mut DurationRepr,
1130 config: &Config,
1131 ) -> Result<(), ParseError> {
1132 if let Some(is_negative) = self.parse_sign_is_negative()? {
1133 duration_repr.is_negative = Some(is_negative);
1134
1135 let bytes = self.bytes();
1136 match bytes.current_byte {
1137 Some(byte) if config.allow_sign_delimiter && (config.inner_delimiter)(*byte) => {
1138 return bytes.try_consume_delimiter(config.inner_delimiter);
1139 }
1140 Some(_) => {}
1141 None => {
1142 return Err(ParseError::Syntax(
1143 bytes.current_pos,
1144 "Unexpected end of input. Sign without a number".to_owned(),
1145 ));
1146 }
1147 }
1148 }
1149 Ok(())
1150 }
1151
1152 #[inline]
1153 fn parse_fract(&mut self) -> Fract {
1154 let BytesRange(start, end) = self.bytes().parse_digits();
1155 Fract(start, end)
1156 }
1157
1158 fn parse_number_fraction(
1159 &mut self,
1160 duration_repr: &mut DurationRepr<'a>,
1161 disable_fraction: bool,
1162 ) -> Result<bool, ParseError> {
1163 let bytes = self.bytes();
1164 match bytes.current_byte {
1165 Some(byte) if *byte == b'.' && !disable_fraction => {
1166 bytes.advance();
1167 let fract = match bytes.current_byte {
1168 Some(byte) if byte.is_ascii_digit() => Some(self.parse_fract()),
1169 Some(_) | None if duration_repr.whole.is_none() => {
1170 return Err(ParseError::Syntax(
1173 bytes.current_pos - 1,
1174 "Either the whole number part or the fraction must be present"
1175 .to_owned(),
1176 ));
1177 }
1178 Some(_) => Some(Fract(self.bytes().current_pos, self.bytes().current_pos)),
1179 None => {
1180 duration_repr.fract =
1181 Some(Fract(self.bytes().current_pos, self.bytes().current_pos));
1182 return Ok(false);
1183 }
1184 };
1185 duration_repr.fract = fract;
1186 Ok(true)
1187 }
1188 Some(byte) if *byte == b'.' => Err(ParseError::Syntax(
1189 bytes.current_pos,
1190 "No fraction allowed".to_owned(),
1191 )),
1192 Some(_) => Ok(true),
1193 None => Ok(false),
1194 }
1195 }
1196
1197 fn parse_exponent(&mut self) -> Result<i16, ParseError> {
1198 let is_negative = self.parse_sign_is_negative()?.unwrap_or_default();
1199 let bytes = self.bytes();
1200
1201 let mut exponent = 0i16;
1202 let start = bytes.current_pos;
1203 while let Some(byte) = bytes.current_byte {
1204 let digit = byte.wrapping_sub(b'0');
1205 if digit < 10 {
1206 exponent = if is_negative {
1207 match exponent
1208 .checked_mul(10)
1209 .and_then(|e| e.checked_sub(i16::from(digit)))
1210 {
1211 Some(exponent) => exponent,
1212 None => return Err(ParseError::NegativeExponentOverflow),
1213 }
1214 } else {
1215 match exponent
1216 .checked_mul(10)
1217 .and_then(|e| e.checked_add(i16::from(digit)))
1218 {
1219 Some(exponent) => exponent,
1220 None => return Err(ParseError::PositiveExponentOverflow),
1221 }
1222 };
1223 bytes.advance();
1224 } else {
1225 break;
1226 }
1227 }
1228
1229 if bytes.current_pos - start > 0 {
1230 Ok(exponent)
1231 } else if bytes.is_end_of_input() {
1232 Err(ParseError::Syntax(
1233 bytes.current_pos,
1234 "Expected exponent but reached end of input".to_owned(),
1235 ))
1236 } else {
1237 Err(ParseError::Syntax(
1238 bytes.current_pos,
1239 "The exponent must have at least one digit".to_owned(),
1240 ))
1241 }
1242 }
1243
1244 fn parse_number_exponent(
1245 &mut self,
1246 duration_repr: &mut DurationRepr<'a>,
1247 disable_exponent: bool,
1248 ) -> Result<bool, ParseError> {
1249 let bytes = self.bytes();
1250 match bytes.current_byte {
1251 Some(byte) if byte.eq_ignore_ascii_case(&b'e') && !disable_exponent => {
1252 bytes.advance();
1253 duration_repr.exponent = self.parse_exponent()?;
1254 Ok(true)
1255 }
1256 Some(byte) if byte.eq_ignore_ascii_case(&b'e') => Err(ParseError::Syntax(
1257 bytes.current_pos,
1258 "No exponent allowed".to_owned(),
1259 )),
1260 Some(_) => Ok(true),
1261 None => Ok(false),
1262 }
1263 }
1264
1265 fn parse_number_delimiter(&mut self, delimiter: Option<Delimiter>) -> Result<bool, ParseError> {
1266 let bytes = self.bytes();
1267
1268 match (bytes.current_byte, delimiter) {
1271 (Some(byte), Some(delimiter)) if delimiter(*byte) => {
1272 bytes.try_consume_delimiter(delimiter)?;
1273 Ok(true)
1274 }
1275 (Some(_), _) => Ok(true),
1276 (None, _) => Ok(false),
1277 }
1278 }
1279}
1280
1281pub struct ReprParserSingle<'a> {
1282 pub bytes: Bytes<'a>,
1283}
1284
1285impl<'a> ReprParserSingle<'a> {
1286 pub const fn new(input: &'a str) -> Self {
1287 Self {
1288 bytes: Bytes::new(input.as_bytes()),
1289 }
1290 }
1291}
1292
1293impl<'a> ReprParserTemplate<'a> for ReprParserSingle<'a> {
1294 type Output = DurationRepr<'a>;
1295
1296 #[inline]
1297 fn bytes(&mut self) -> &mut Bytes<'a> {
1298 &mut self.bytes
1299 }
1300
1301 #[inline]
1302 fn make_output(&'a mut self, duration_repr: DurationRepr<'a>) -> Self::Output {
1303 duration_repr
1304 }
1305
1306 #[inline]
1307 fn parse_infinity_remainder(
1308 &'a mut self,
1309 mut duration_repr: DurationRepr<'a>,
1310 _: &Config,
1311 ) -> Result<DurationRepr<'a>, ParseError> {
1312 if self.bytes.is_end_of_input() {
1313 duration_repr.is_infinite = true;
1314 return Ok(duration_repr);
1315 }
1316
1317 let expected = b"inity";
1318 for byte in expected {
1319 match self.bytes.current_byte {
1320 Some(current) if current.eq_ignore_ascii_case(byte) => self.bytes.advance(),
1321 Some(current) => {
1323 return Err(ParseError::Syntax(
1324 self.bytes.current_pos,
1325 format!(
1326 "Error parsing infinity: Invalid character '{}'",
1327 *current as char
1328 ),
1329 ));
1330 }
1331 None => {
1332 return Err(ParseError::Syntax(
1333 self.bytes.current_pos,
1334 "Error parsing infinity: Premature end of input".to_owned(),
1335 ));
1336 }
1337 }
1338 }
1339
1340 duration_repr.is_infinite = true;
1341 self.bytes.check_end_of_input().map(|()| duration_repr)
1342 }
1343
1344 #[inline]
1345 fn parse_keyword(
1346 &mut self,
1347 keywords: Option<&dyn TimeUnitsLike>,
1348 _: &Config,
1349 ) -> Result<Option<(TimeUnit, Multiplier)>, ParseError> {
1350 if let Some(keywords) = keywords {
1351 let keyword = unsafe { self.bytes.get_remainder_str_unchecked() };
1353 match keywords.get(keyword) {
1354 None => Ok(None),
1355 some_time_unit => {
1356 self.bytes.finish();
1357 Ok(some_time_unit)
1358 }
1359 }
1360 } else {
1361 Ok(None)
1362 }
1363 }
1364
1365 fn parse_time_unit(
1366 &mut self,
1367 config: &Config,
1368 time_units: &dyn TimeUnitsLike,
1369 ) -> Result<Option<(TimeUnit, Multiplier)>, ParseError> {
1370 debug_assert!(
1372 self.bytes.current_byte.is_some(),
1373 "Don't call this function without being sure there's at least 1 byte remaining"
1374 ); if config.allow_ago {
1377 let start = self.bytes.current_pos;
1378 let string = unsafe {
1381 std::str::from_utf8_unchecked(self.bytes.advance_to(config.inner_delimiter))
1382 };
1383
1384 let (time_unit, mut multiplier) = if string.is_empty() {
1385 return Ok(None); } else {
1388 match time_units.get(string) {
1389 None => {
1390 self.bytes.reset(start);
1391 return Ok(None);
1392 }
1393 Some(unit) => unit,
1394 }
1395 };
1396
1397 if self.bytes.current_byte.is_some() {
1400 self.bytes.try_consume_delimiter(config.inner_delimiter)?;
1401 if self.bytes.next_is_ignore_ascii_case(b"ago") {
1402 unsafe { self.bytes.advance_by(3) };
1404 multiplier = multiplier.saturating_neg();
1407 } else {
1408 self.bytes.reset(start);
1409 return Ok(None);
1410 }
1411 }
1412
1413 Ok(Some((time_unit, multiplier)))
1414 } else {
1415 let string = unsafe { self.bytes.get_remainder_str_unchecked() };
1418 let result = match time_units.get(string) {
1419 None => return Ok(None),
1420 some_time_unit => Ok(some_time_unit),
1421 };
1422 self.bytes.finish();
1423 result
1424 }
1425 }
1426
1427 #[inline]
1428 fn parse_number_time_unit(
1429 &mut self,
1430 duration_repr: &mut DurationRepr<'a>,
1431 config: &'a Config,
1432 time_units: &dyn TimeUnitsLike,
1433 ) -> Result<bool, ParseError> {
1434 match self.bytes.current_byte {
1435 Some(_) if !time_units.is_empty() => {
1436 if let Some((unit, multi)) = self.parse_time_unit(config, time_units)? {
1437 duration_repr.unit = Some(unit);
1438 duration_repr.multiplier = multi;
1439 Ok(true)
1440 } else {
1441 self.bytes.get_remainder_str().and_then(|remainder| {
1442 Err(ParseError::TimeUnit(
1443 self.bytes.current_pos,
1444 format!("Invalid time unit: '{remainder}'"),
1445 ))
1446 })
1447 }
1448 }
1449 Some(_) => {
1450 Err(ParseError::TimeUnit(
1451 self.bytes.current_pos,
1452 format!("No time units allowed but found: '{}'", unsafe {
1454 self.bytes.get_remainder_str_unchecked()
1455 }),
1456 ))
1457 }
1458 None => Ok(false), }
1462 }
1463
1464 #[inline]
1465 fn finalize(
1466 &'a mut self,
1467 duration_repr: DurationRepr<'a>,
1468 _: &Config,
1469 ) -> Result<Self::Output, ParseError> {
1470 self.bytes.check_end_of_input().map(|()| duration_repr)
1471 }
1472}
1473
1474pub struct ReprParserMultiple<'a> {
1475 pub bytes: Bytes<'a>,
1476}
1477
1478impl<'a> ReprParserMultiple<'a> {
1479 pub fn new(input: &'a str) -> Self {
1480 Self {
1481 bytes: Bytes::new(input.as_bytes()),
1482 }
1483 }
1484
1485 #[inline]
1486 pub fn is_next_duration(byte: u8) -> bool {
1487 byte.is_ascii_digit() || byte == b'+' || byte == b'-'
1488 }
1489
1490 pub fn try_consume_connection(
1491 &mut self,
1492 delimiter: Delimiter,
1493 conjunctions: &'a [&'a str],
1494 ) -> Result<(), ParseError> {
1495 debug_assert!(delimiter(*self.bytes.current_byte.unwrap()));
1496
1497 self.bytes.try_consume_delimiter(delimiter)?;
1498 let start = self.bytes.current_pos;
1499 for word in conjunctions {
1501 if self.bytes.next_is_ignore_ascii_case(word.as_bytes()) {
1502 unsafe { self.bytes.advance_by(word.len()) };
1504 match self.bytes.current_byte {
1505 Some(byte) if delimiter(*byte) => {
1506 self.bytes.try_consume_delimiter(delimiter)?;
1507 }
1508 Some(byte) if Self::is_next_duration(*byte) => {}
1509 Some(byte) => {
1510 return Err(ParseError::Syntax(
1511 self.bytes.current_pos,
1512 format!(
1513 "A conjunction must be separated by a delimiter, sign or digit \
1514 but found: '{}'",
1515 *byte as char
1516 ),
1517 ));
1518 }
1519 None => {
1520 return Err(ParseError::Syntax(
1521 start,
1522 format!("Input may not end with a conjunction but found: '{word}'"),
1523 ));
1524 }
1525 }
1526 break;
1527 }
1528 }
1529 Ok(())
1530 }
1531}
1532
1533impl<'a> ReprParserTemplate<'a> for ReprParserMultiple<'a> {
1534 type Output = (DurationRepr<'a>, Option<&'a mut ReprParserMultiple<'a>>);
1535
1536 #[inline]
1537 fn bytes(&mut self) -> &mut Bytes<'a> {
1538 &mut self.bytes
1539 }
1540
1541 #[inline]
1542 fn make_output(&'a mut self, duration_repr: DurationRepr<'a>) -> Self::Output {
1543 (duration_repr, self.bytes().current_byte.map(|_| self))
1544 }
1545
1546 #[inline]
1547 fn parse_infinity_remainder(
1548 &'a mut self,
1549 mut duration_repr: DurationRepr<'a>,
1550 config: &'a Config,
1551 ) -> Result<(DurationRepr<'a>, Option<&'a mut ReprParserMultiple<'a>>), ParseError> {
1552 match self.bytes.current_byte {
1553 Some(byte) if (config.outer_delimiter)(*byte) => {
1554 duration_repr.is_infinite = true;
1555 return self
1556 .try_consume_connection(
1557 config.outer_delimiter,
1558 config.conjunctions.unwrap_or_default(),
1559 )
1560 .map(|()| (duration_repr, Some(self)));
1561 }
1562 Some(_) => {}
1563 None => {
1564 duration_repr.is_infinite = true;
1565 return Ok((duration_repr, None));
1566 }
1567 }
1568
1569 let expected = "inity";
1570 let start = self.bytes.current_pos;
1571 for byte in expected.as_bytes() {
1572 match self.bytes.current_byte {
1573 Some(current) if current.eq_ignore_ascii_case(byte) => self.bytes.advance(),
1574 Some(current) => {
1576 return Err(ParseError::Syntax(
1577 self.bytes.current_pos,
1578 format!(
1579 "Error parsing infinity: Invalid character '{}'",
1580 *current as char
1581 ),
1582 ));
1583 }
1584 None => {
1585 return Err(ParseError::Syntax(
1586 start - 3,
1589 format!(
1590 "Error parsing infinity: 'inf{}' is an invalid identifier for infinity",
1591 self.bytes.get_current_str(start).unwrap() ),
1593 ));
1594 }
1595 }
1596 }
1597
1598 duration_repr.is_infinite = true;
1599 match self.bytes.current_byte {
1600 Some(byte) if (config.outer_delimiter)(*byte) => {
1601 self.try_consume_connection(
1602 config.outer_delimiter,
1603 config.conjunctions.unwrap_or_default(),
1604 )?;
1605 Ok((duration_repr, Some(self)))
1606 }
1607 Some(byte) => Err(ParseError::Syntax(
1608 self.bytes.current_pos,
1609 format!(
1610 "Error parsing infinity: Expected a delimiter but found '{}'",
1611 *byte as char
1612 ),
1613 )),
1614 None => Ok((duration_repr, None)),
1615 }
1616 }
1617
1618 #[inline]
1619 fn parse_keyword(
1620 &mut self,
1621 keywords: Option<&dyn TimeUnitsLike>,
1622 config: &'a Config,
1623 ) -> Result<Option<(TimeUnit, Multiplier)>, ParseError> {
1624 if let Some(keywords) = keywords {
1625 let start = self.bytes.current_pos;
1626 let buffer = self.bytes.buffered_advance_to(|byte: u8| {
1627 (config.outer_delimiter)(byte) || Self::is_next_duration(byte)
1628 });
1629
1630 if buffer.is_empty() {
1631 return Ok(None); }
1634
1635 let string = unsafe { std::str::from_utf8_unchecked(buffer) };
1638
1639 match keywords.get(string) {
1640 None => {
1641 self.bytes.reset(start);
1642 Ok(None)
1643 }
1644 some_time_unit => {
1645 if let Some(byte) = self.bytes.current_byte {
1646 if (config.outer_delimiter)(*byte) {
1647 self.try_consume_connection(
1648 config.outer_delimiter,
1649 config.conjunctions.unwrap_or_default(),
1650 )?;
1651 }
1652 }
1653 Ok(some_time_unit)
1654 }
1655 }
1656 } else {
1657 Ok(None)
1658 }
1659 }
1660
1661 #[inline]
1662 fn parse_time_unit(
1663 &mut self,
1664 config: &'a Config,
1665 time_units: &dyn TimeUnitsLike,
1666 ) -> Result<Option<(TimeUnit, Multiplier)>, ParseError> {
1667 debug_assert!(
1669 self.bytes.current_byte.is_some(),
1670 "Don't call this function without being sure there's at least 1 byte remaining"
1671 ); let start = self.bytes.current_pos;
1674 let buffer = if config.allow_ago {
1675 self.bytes.buffered_advance_to(|byte: u8| {
1676 (config.inner_delimiter)(byte)
1677 || (config.outer_delimiter)(byte)
1678 || Self::is_next_duration(byte)
1679 })
1680 } else {
1681 self.bytes.buffered_advance_to(|byte: u8| {
1682 (config.outer_delimiter)(byte) || Self::is_next_duration(byte)
1683 })
1684 };
1685 if buffer.is_empty() {
1686 return Ok(None);
1687 }
1688
1689 let string = unsafe { std::str::from_utf8_unchecked(buffer) };
1692
1693 let Some((time_unit, mut multiplier)) = time_units.get(string) else {
1694 self.bytes.reset(start);
1695 return Ok(None);
1696 };
1697
1698 match self.bytes.current_byte {
1699 Some(byte) if config.allow_ago && (config.inner_delimiter)(*byte) => {
1700 let start = self.bytes.current_pos;
1701 self.bytes.try_consume_delimiter(config.inner_delimiter)?;
1702 if self.bytes.next_is_ignore_ascii_case(b"ago") {
1703 unsafe { self.bytes.advance_by(3) };
1705 match self.bytes.current_byte {
1706 Some(byte)
1707 if (config.outer_delimiter)(*byte) || Self::is_next_duration(*byte) =>
1708 {
1709 multiplier = multiplier.saturating_neg();
1710 }
1711 Some(_) => {
1712 self.bytes.reset(start);
1713 }
1714 None => {
1715 multiplier = multiplier.saturating_neg();
1716 }
1717 }
1718 } else {
1719 self.bytes.reset(start);
1720 }
1721 }
1722 _ => {}
1723 }
1724
1725 match self.bytes.current_byte {
1726 Some(byte) if (config.outer_delimiter)(*byte) => {
1727 self.try_consume_connection(
1728 config.outer_delimiter,
1729 config.conjunctions.unwrap_or_default(),
1730 )?;
1731 }
1732 Some(_) | None => {}
1733 }
1734
1735 Ok(Some((time_unit, multiplier)))
1736 }
1737
1738 #[inline]
1739 fn parse_number_time_unit(
1740 &mut self,
1741 duration_repr: &mut DurationRepr<'a>,
1742 config: &'a Config,
1743 time_units: &dyn TimeUnitsLike,
1744 ) -> Result<bool, ParseError> {
1745 match self.bytes().current_byte {
1746 Some(_) if !time_units.is_empty() => {
1747 if let Some((unit, multi)) = self.parse_time_unit(config, time_units)? {
1748 duration_repr.unit = Some(unit);
1749 duration_repr.multiplier = multi;
1750 }
1751 }
1752 Some(_) => {}
1753 None => return Ok(false), }
1757 Ok(true)
1758 }
1759
1760 #[inline]
1761 fn finalize(
1762 &'a mut self,
1763 duration_repr: DurationRepr<'a>,
1764 config: &'a Config,
1765 ) -> Result<Self::Output, ParseError> {
1766 match self.bytes().current_byte {
1767 Some(byte) if (config.outer_delimiter)(*byte) => self
1768 .try_consume_connection(
1769 config.outer_delimiter,
1770 config.conjunctions.unwrap_or_default(),
1771 )
1772 .map(|()| (duration_repr, Some(self))),
1773 Some(_) => Ok((duration_repr, Some(self))),
1774 None => Ok((duration_repr, None)),
1775 }
1776 }
1777}
1778
1779#[cfg(test)]
1780mod tests {
1781 use rstest::rstest;
1782 use rstest_reuse::{apply, template};
1783
1784 use super::*;
1785
1786 struct TimeUnitsFixture;
1787
1788 impl TimeUnitsLike for TimeUnitsFixture {
1790 fn is_empty(&self) -> bool {
1791 true
1792 }
1793
1794 fn get(&self, _: &str) -> Option<(TimeUnit, Multiplier)> {
1795 None
1796 }
1797 } #[rstest]
1800 #[case::zeros("00000000", Some(0x3030_3030_3030_3030))]
1801 #[case::one("00000001", Some(0x3130_3030_3030_3030))]
1802 #[case::ten_millions("10000000", Some(0x3030_3030_3030_3031))]
1803 #[case::nines("99999999", Some(0x3939_3939_3939_3939))]
1804 fn test_duration_repr_parser_parse_8_digits(
1805 #[case] input: &str,
1806 #[case] expected: Option<u64>,
1807 ) {
1808 let mut parser = ReprParserSingle::new(input);
1809 assert_eq!(parser.bytes.parse_8_digits(), expected);
1810 }
1811
1812 #[rstest]
1813 #[case::empty("", None)]
1814 #[case::one_non_digit_char("a0000000", None)]
1815 #[case::less_than_8_digits("9999999", None)]
1816 fn test_duration_repr_parser_parse_8_digits_when_not_8_digits(
1817 #[case] input: &str,
1818 #[case] expected: Option<u64>,
1819 ) {
1820 let mut parser = ReprParserSingle::new(input);
1821 assert_eq!(parser.bytes.parse_8_digits(), expected);
1822 assert_eq!(parser.bytes.get_remainder(), input.as_bytes());
1823 assert_eq!(parser.bytes.current_byte, input.as_bytes().first());
1824 assert_eq!(parser.bytes.current_pos, 0);
1825 }
1826
1827 #[test]
1828 fn test_duration_repr_parser_parse_8_digits_when_more_than_8() {
1829 let mut parser = ReprParserSingle::new("00000000a");
1830 assert_eq!(parser.bytes.parse_8_digits(), Some(0x3030_3030_3030_3030));
1831 assert_eq!(parser.bytes.get_remainder(), b"a");
1832 assert_eq!(parser.bytes.current_byte, Some(&b'a'));
1833 assert_eq!(parser.bytes.current_pos, 8);
1834 }
1835
1836 #[template]
1837 #[rstest]
1838 #[case::zero("0", Whole(1, 1))]
1839 #[case::one("1", Whole(0, 1))]
1840 #[case::nine("9", Whole(0, 1))]
1841 #[case::ten("10", Whole(0, 2))]
1842 #[case::eight_leading_zeros("00000000", Whole(8, 8))]
1843 #[case::fifteen_leading_zeros("000000000000000", Whole(15, 15))]
1844 #[case::ten_with_leading_zeros_when_eight_digits("00000010", Whole(6, 8))]
1845 #[case::ten_with_leading_zeros_when_nine_digits("000000010", Whole(7, 9))]
1846 #[case::mixed_number("12345", Whole(0, 5))]
1847 #[case::max_8_digits("99999999", Whole(0, 8))]
1848 #[case::max_8_digits_minus_one("99999998", Whole(0, 8))]
1849 #[case::min_nine_digits("100000000", Whole(0, 9))]
1850 #[case::min_nine_digits_plus_one("100000001", Whole(0, 9))]
1851 #[case::eight_zero_digits_start("0000000011111111", Whole(8, 16))]
1852 #[case::eight_zero_digits_end("1111111100000000", Whole(0, 16))]
1853 #[case::eight_zero_digits_middle("11111111000000001", Whole(0, 17))]
1854 #[case::max_16_digits("9999999999999999", Whole(0, 16))]
1855 fn test_duration_repr_parser_parse_whole(#[case] input: &str, #[case] expected: Whole) {}
1856
1857 #[apply(test_duration_repr_parser_parse_whole)]
1858 fn test_duration_repr_parser_parse_whole_single(input: &str, expected: Whole) {
1859 let mut parser = ReprParserSingle::new(input);
1860 assert_eq!(parser.parse_whole(), expected);
1861 }
1862
1863 #[apply(test_duration_repr_parser_parse_whole)]
1864 fn test_duration_repr_parser_parse_whole_multiple(input: &str, expected: Whole) {
1865 let mut parser = ReprParserMultiple::new(input); assert_eq!(parser.parse_whole(), expected);
1867 }
1868
1869 #[test]
1871 fn test_duration_repr_parser_parse_whole_when_more_than_max_exponent() {
1872 let config = Config::new();
1873 let input = &"1".repeat(i16::MAX as usize + 100);
1874 let mut parser = ReprParserSingle::new(input);
1875 let duration_repr = parser
1876 .parse(&config, &TimeUnitsFixture, None, None)
1877 .unwrap();
1878 assert_eq!(duration_repr.whole, Some(Whole(0, i16::MAX as usize + 100)));
1879 assert_eq!(duration_repr.fract, None);
1880 }
1881
1882 #[test]
1884 fn test_duration_repr_parser_parse_fract_when_more_than_max_exponent() {
1885 let input = format!(".{}", "1".repeat(i16::MAX as usize + 100));
1886 let config = Config::new();
1887
1888 let mut parser = ReprParserSingle::new(&input);
1889 let duration_repr = parser
1890 .parse(&config, &TimeUnitsFixture, None, None)
1891 .unwrap();
1892 assert_eq!(duration_repr.whole, None);
1893 assert_eq!(duration_repr.fract, Some(Fract(1, i16::MAX as usize + 101)));
1894
1895 let mut config = Config::new();
1896 config.allow_multiple = true;
1897 let mut parser = ReprParserMultiple::new(&input);
1898 let (duration_repr, maybe_parser) = parser
1899 .parse(&config, &TimeUnitsFixture, None, None)
1900 .unwrap();
1901 assert!(maybe_parser.is_none());
1902 assert_eq!(duration_repr.whole, None);
1903 assert_eq!(duration_repr.fract, Some(Fract(1, i16::MAX as usize + 101)));
1904 }
1905
1906 #[template]
1907 #[rstest]
1908 #[case::zero("0", Fract(0, 1))]
1909 #[case::one("1", Fract(0, 1))]
1910 #[case::nine("9", Fract(0, 1))]
1911 #[case::ten("10", Fract(0, 2))]
1912 #[case::leading_zero("01", Fract(0, 2))]
1913 #[case::leading_zeros("001", Fract(0, 3))]
1914 #[case::eight_leading_zeros("000000001", Fract(0, 9))]
1915 #[case::mixed_number("12345", Fract(0, 5))]
1916 #[case::max_8_digits("99999999", Fract(0, 8))]
1917 #[case::max_8_digits_minus_one("99999998", Fract(0, 8))]
1918 #[case::nine_digits("123456789", Fract(0, 9))]
1919 fn test_duration_repr_parser_parse_fract(#[case] input: &str, #[case] expected: Fract) {}
1920
1921 #[apply(test_duration_repr_parser_parse_fract)]
1922 fn test_duration_repr_parser_parse_fract_single(input: &str, expected: Fract) {
1923 let mut parser = ReprParserSingle::new(input);
1924 assert_eq!(parser.parse_fract(), expected);
1925 }
1926
1927 #[apply(test_duration_repr_parser_parse_fract)]
1928 fn test_duration_repr_parser_parse_fract_multiple(input: &str, expected: Fract) {
1929 let mut parser = ReprParserMultiple::new(input); assert_eq!(parser.parse_fract(), expected);
1931 }
1932
1933 #[test]
1934 fn test_fract_is_empty() {
1935 assert!(Fract(0, 0).is_empty());
1936 assert!(Fract(9, 9).is_empty());
1937 }
1938
1939 #[test]
1940 fn test_whole_is_empty() {
1941 assert!(Whole(0, 0).is_empty());
1942 assert!(Whole(9, 9).is_empty());
1943 }
1944
1945 #[rstest]
1946 #[case::one_digit(b"1", None, None, 100_000_000_000_000_000)]
1947 #[case::one_digit_one_zero(b"1", None, Some(1), 10_000_000_000_000_000)]
1948 #[case::two_digits(b"12", None, None, 120_000_000_000_000_000)]
1949 #[case::two_digits_one_zero(b"12", None, Some(1), 12_000_000_000_000_000)]
1950 #[case::one_digit_prepend(b"2", Some(b"1".as_ref()), None, 120_000_000_000_000_000)]
1951 #[case::empty_digits_prepend_one(b"", Some(b"1".as_ref()), None, 100_000_000_000_000_000)]
1952 #[case::more_than_18_digits_when_zeros(b"234", Some(b"1".as_ref()), Some(16), 12)]
1953 fn test_fract(
1954 #[case] digits: &[u8],
1955 #[case] prepend: Option<&[u8]>,
1956 #[case] zeros: Option<usize>,
1957 #[case] expected: u64,
1958 ) {
1959 assert_eq!(Fract::parse(digits, prepend, zeros), expected);
1960 }
1961
1962 #[test]
1963 fn test_try_consume_delimiter_when_input_starts_with_delimiter_then_error() {
1964 let mut bytes = Bytes::new(b" some");
1965 assert_eq!(
1966 bytes.try_consume_delimiter(|byte| byte == b' '),
1967 Err(ParseError::Syntax(
1968 0,
1969 "Input may not start with a delimiter".to_owned()
1970 ))
1971 );
1972 }
1973}