1pub fn arithmetic_series<T: Int>(a: T, n: T, d: T) -> Option<T> {
18 if n == T::zero() {
19 return Some(T::zero());
20 }
21
22 assert!(n.is_positive());
23
24 let last = d.checked_mul(n.decrement())?.checked_add(a)?;
25 a.checked_add(last)?.checked_mul(n)?.checked_div(T::two())
26}
27
28pub trait Int: Copy + Ord {
29 fn is_positive(self) -> bool;
30 fn decrement(self) -> Self;
31 fn checked_add(self, rhs: Self) -> Option<Self>;
32 fn checked_mul(self, rhs: Self) -> Option<Self>;
33 fn checked_div(self, rhs: Self) -> Option<Self>;
34 fn zero() -> Self;
35 fn two() -> Self;
36}
37
38macro_rules! impl_int {
39 ($($t:ty),+) => {
40 $(
41 impl Int for $t {
42 fn is_positive(self) -> bool {
43 self >= 1
44 }
45 fn decrement(self) -> Self {
46 self - 1
47 }
48 fn checked_add(self, rhs: Self) -> Option<Self> {
49 self.checked_add(rhs)
50 }
51 fn checked_mul(self, rhs: Self) -> Option<Self> {
52 self.checked_mul(rhs)
53 }
54 fn checked_div(self, rhs: Self) -> Option<Self> {
55 self.checked_div(rhs)
56 }
57 fn zero() -> Self {
58 0
59 }
60 fn two() -> Self {
61 2
62 }
63 }
64 )+
65 };
66}
67
68impl_int!(i32, i64, i128, u32, u64, u128, usize);
69
70#[cfg(test)]
71mod tests {
72 use crate::arithmetic_series;
73
74 #[test]
75 fn test_sum_of_1_2_3_to_10() {
76 assert_eq!(arithmetic_series(1, 10, 1), Some(55));
77 }
78
79 #[test]
80 fn test_single() {
81 assert_eq!(arithmetic_series(42, 1, 3), Some(42));
82 }
83
84 #[test]
85 fn test_decrease_sequence() {
86 assert_eq!(
87 arithmetic_series(8, 6, -3),
88 Some(8 + 5 + 2 + (-1) + (-4) + (-7))
89 );
90 }
91
92 #[test]
93 fn test_empty() {
94 assert_eq!(arithmetic_series(42, 0, 3), Some(0));
95 }
96
97 #[test]
98 fn test_too_large() {
99 assert_eq!(arithmetic_series(1, std::i64::MAX, 1), None);
100 }
101
102 #[test]
103 #[should_panic]
104 fn test_negative_length() {
105 arithmetic_series(42, -4, 3);
106 }
107}