1#[cfg(creusot)]
4use creusot_std::prelude::ensures;
5
6#[must_use]
11#[cfg_attr(
12 creusot,
13 ensures(match result {
14 Some(next) => current@ < maximum@ && next@ == current@ + 1 && next@ <= maximum@,
15 None => current@ >= maximum@,
16 })
17)]
18pub const fn exact_epoch_successor(current: i64, maximum: i64) -> Option<i64> {
19 if current < maximum {
20 Some(current + 1)
21 } else {
22 None
23 }
24}
25
26#[cfg(test)]
27mod tests {
28 use super::exact_epoch_successor;
29
30 #[yare::parameterized(
31 negative = { -1, i64::from(i32::MAX), Some(0) },
32 zero = { 0, i64::from(i32::MAX), Some(1) },
33 ordinary = { 41, i64::from(i32::MAX), Some(42) },
34 maximum = { i64::from(i32::MAX) - 1, i64::from(i32::MAX), Some(i64::from(i32::MAX)) },
35 i64_max = { i64::MAX - 1, i64::MAX, Some(i64::MAX) },
36 )]
37 fn returns_the_exact_successor(current: i64, maximum: i64, expected: Option<i64>) {
38 assert2::assert!(exact_epoch_successor(current, maximum) == expected);
39 }
40
41 #[test]
42 fn rejects_the_maximum_and_values_above_it() {
43 assert2::assert!(exact_epoch_successor(i64::from(i32::MAX), i64::from(i32::MAX)).is_none());
44 assert2::assert!(exact_epoch_successor(i64::MAX, i64::MAX).is_none());
45 assert2::assert!(exact_epoch_successor(7, 6).is_none());
46 }
47}