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