Commit 144f886e authored by Ian Jackson's avatar Ian Jackson 💬
Browse files

Merge branch 'integers' into 'main'

Better handling of integer overflows

See merge request !466
parents 0d4c53bb 77653608
Loading
Loading
Loading
Loading
+28 −3
Original line number Diff line number Diff line
@@ -127,10 +127,12 @@ impl<E> RetryError<E> {
    where
        T: Into<E>,
    {
        if self.n_errors < usize::MAX {
            self.n_errors += 1;
            let attempt = Attempt::Single(self.n_errors);
            self.errors.push((attempt, err.into()));
        }
    }

    /// Return an iterator over all of the reasons that the attempt
    /// behind this RetryError has failed.
@@ -329,4 +331,27 @@ Tried to parse some integers 3 times, but all attempts failed.
Attempts 1..3: invalid digit found in string"
        );
    }

    #[test]
    fn overflow() {
        use std::num::ParseIntError;
        let mut err: RetryError<ParseIntError> =
            RetryError::in_attempt_to("parse too many integers");
        assert!(err.is_empty());
        let mut errors: Vec<ParseIntError> = vec!["no", "numbers"]
            .iter()
            .filter_map(|s| s.parse::<u16>().err())
            .collect();
        err.n_errors = usize::MAX;
        err.errors.push((
            Attempt::Range(1, err.n_errors),
            errors.pop().expect("parser did not fail"),
        ));
        assert!(err.n_errors == usize::MAX);
        assert!(err.len() == 1);

        err.push(errors.pop().expect("parser did not fail"));
        assert!(err.n_errors == usize::MAX);
        assert!(err.len() == 1);
    }
}
+27 −4
Original line number Diff line number Diff line
@@ -161,8 +161,14 @@ impl RetryTime {
    {
        match self {
            RetryTime::Immediate => AbsRetryTime::Immediate,
            RetryTime::AfterWaiting => AbsRetryTime::At(now + choose_delay()),
            RetryTime::After(d) => AbsRetryTime::At(now + d),
            RetryTime::AfterWaiting => match now.checked_add(choose_delay()) {
                Some(t) => AbsRetryTime::At(t),
                None => AbsRetryTime::Never,
            },
            RetryTime::After(d) => match now.checked_add(d) {
                Some(t) => AbsRetryTime::At(t),
                None => AbsRetryTime::Never,
            },
            RetryTime::At(t) => AbsRetryTime::At(t),
            RetryTime::Never => AbsRetryTime::Never,
        }
@@ -181,11 +187,14 @@ impl RetryTime {
        I: Iterator<Item = RetryTime>,
        F: FnOnce() -> Duration,
    {
        let chosen_delay = once_cell::unsync::Lazy::new(choose_delay);
        let chosen_delay = once_cell::unsync::Lazy::new(|| match now.checked_add(choose_delay()) {
            Some(t) => AbsRetryTime::At(t),
            None => AbsRetryTime::Never,
        });

        items
            .map(|item| match item {
                RetryTime::AfterWaiting => AbsRetryTime::At(now + *chosen_delay),
                RetryTime::AfterWaiting => *chosen_delay,
                other => other.absolute(now, || unreachable!()),
            })
            .min()
@@ -277,4 +286,18 @@ mod test {
            }
        }
    }

    #[test]
    fn earliest_absolute() {
        let sec = Duration::from_secs(1);
        let now = Instant::now();

        let times = vec![RetryTime::AfterWaiting, RetryTime::Never];

        let earliest = RetryTime::earliest_absolute(times.into_iter(), now, || sec);
        assert_eq!(
            earliest.expect("no absolute time"),
            AbsRetryTime::At(now + sec)
        );
    }
}