]> git.lizzy.rs Git - rust.git/blob - library/core/src/iter/traits/accum.rs
Rollup merge of #105419 - YC:issue-41731, r=petrochenkov
[rust.git] / library / core / src / iter / traits / accum.rs
1 use crate::iter;
2 use crate::num::Wrapping;
3
4 /// Trait to represent types that can be created by summing up an iterator.
5 ///
6 /// This trait is used to implement [`Iterator::sum()`]. Types which implement
7 /// this trait can be generated by using the [`sum()`] method on an iterator.
8 /// Like [`FromIterator`], this trait should rarely be called directly.
9 ///
10 /// [`sum()`]: Iterator::sum
11 /// [`FromIterator`]: iter::FromIterator
12 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
13 #[rustc_on_unimplemented(
14     message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`",
15     label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator<Item={A}>`"
16 )]
17 pub trait Sum<A = Self>: Sized {
18     /// Method which takes an iterator and generates `Self` from the elements by
19     /// "summing up" the items.
20     #[stable(feature = "iter_arith_traits", since = "1.12.0")]
21     fn sum<I: Iterator<Item = A>>(iter: I) -> Self;
22 }
23
24 /// Trait to represent types that can be created by multiplying elements of an
25 /// iterator.
26 ///
27 /// This trait is used to implement [`Iterator::product()`]. Types which implement
28 /// this trait can be generated by using the [`product()`] method on an iterator.
29 /// Like [`FromIterator`], this trait should rarely be called directly.
30 ///
31 /// [`product()`]: Iterator::product
32 /// [`FromIterator`]: iter::FromIterator
33 #[stable(feature = "iter_arith_traits", since = "1.12.0")]
34 #[rustc_on_unimplemented(
35     message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator",
36     label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator<Item={A}>`"
37 )]
38 pub trait Product<A = Self>: Sized {
39     /// Method which takes an iterator and generates `Self` from the elements by
40     /// multiplying the items.
41     #[stable(feature = "iter_arith_traits", since = "1.12.0")]
42     fn product<I: Iterator<Item = A>>(iter: I) -> Self;
43 }
44
45 macro_rules! integer_sum_product {
46     (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($(
47         #[$attr]
48         impl Sum for $a {
49             fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
50                 iter.fold(
51                     $zero,
52                     #[rustc_inherit_overflow_checks]
53                     |a, b| a + b,
54                 )
55             }
56         }
57
58         #[$attr]
59         impl Product for $a {
60             fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
61                 iter.fold(
62                     $one,
63                     #[rustc_inherit_overflow_checks]
64                     |a, b| a * b,
65                 )
66             }
67         }
68
69         #[$attr]
70         impl<'a> Sum<&'a $a> for $a {
71             fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
72                 iter.fold(
73                     $zero,
74                     #[rustc_inherit_overflow_checks]
75                     |a, b| a + b,
76                 )
77             }
78         }
79
80         #[$attr]
81         impl<'a> Product<&'a $a> for $a {
82             fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
83                 iter.fold(
84                     $one,
85                     #[rustc_inherit_overflow_checks]
86                     |a, b| a * b,
87                 )
88             }
89         }
90     )*);
91     ($($a:ty)*) => (
92         integer_sum_product!(@impls 0, 1,
93                 #[stable(feature = "iter_arith_traits", since = "1.12.0")],
94                 $($a)*);
95         integer_sum_product!(@impls Wrapping(0), Wrapping(1),
96                 #[stable(feature = "wrapping_iter_arith", since = "1.14.0")],
97                 $(Wrapping<$a>)*);
98     );
99 }
100
101 macro_rules! float_sum_product {
102     ($($a:ident)*) => ($(
103         #[stable(feature = "iter_arith_traits", since = "1.12.0")]
104         impl Sum for $a {
105             fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
106                 iter.fold(
107                     0.0,
108                     #[rustc_inherit_overflow_checks]
109                     |a, b| a + b,
110                 )
111             }
112         }
113
114         #[stable(feature = "iter_arith_traits", since = "1.12.0")]
115         impl Product for $a {
116             fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
117                 iter.fold(
118                     1.0,
119                     #[rustc_inherit_overflow_checks]
120                     |a, b| a * b,
121                 )
122             }
123         }
124
125         #[stable(feature = "iter_arith_traits", since = "1.12.0")]
126         impl<'a> Sum<&'a $a> for $a {
127             fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
128                 iter.fold(
129                     0.0,
130                     #[rustc_inherit_overflow_checks]
131                     |a, b| a + b,
132                 )
133             }
134         }
135
136         #[stable(feature = "iter_arith_traits", since = "1.12.0")]
137         impl<'a> Product<&'a $a> for $a {
138             fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
139                 iter.fold(
140                     1.0,
141                     #[rustc_inherit_overflow_checks]
142                     |a, b| a * b,
143                 )
144             }
145         }
146     )*)
147 }
148
149 integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
150 float_sum_product! { f32 f64 }
151
152 #[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
153 impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
154 where
155     T: Sum<U>,
156 {
157     /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
158     /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
159     /// occur, the sum of all elements is returned.
160     ///
161     /// # Examples
162     ///
163     /// This sums up every integer in a vector, rejecting the sum if a negative
164     /// element is encountered:
165     ///
166     /// ```
167     /// let v = vec![1, 2];
168     /// let res: Result<i32, &'static str> = v.iter().map(|&x: &i32|
169     ///     if x < 0 { Err("Negative element found") }
170     ///     else { Ok(x) }
171     /// ).sum();
172     /// assert_eq!(res, Ok(3));
173     /// ```
174     fn sum<I>(iter: I) -> Result<T, E>
175     where
176         I: Iterator<Item = Result<U, E>>,
177     {
178         iter::try_process(iter, |i| i.sum())
179     }
180 }
181
182 #[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
183 impl<T, U, E> Product<Result<U, E>> for Result<T, E>
184 where
185     T: Product<U>,
186 {
187     /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
188     /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
189     /// occur, the product of all elements is returned.
190     fn product<I>(iter: I) -> Result<T, E>
191     where
192         I: Iterator<Item = Result<U, E>>,
193     {
194         iter::try_process(iter, |i| i.product())
195     }
196 }
197
198 #[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
199 impl<T, U> Sum<Option<U>> for Option<T>
200 where
201     T: Sum<U>,
202 {
203     /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
204     /// elements are taken, and the [`None`] is returned. Should no [`None`]
205     /// occur, the sum of all elements is returned.
206     ///
207     /// # Examples
208     ///
209     /// This sums up the position of the character 'a' in a vector of strings,
210     /// if a word did not have the character 'a' the operation returns `None`:
211     ///
212     /// ```
213     /// let words = vec!["have", "a", "great", "day"];
214     /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
215     /// assert_eq!(total, Some(5));
216     /// ```
217     fn sum<I>(iter: I) -> Option<T>
218     where
219         I: Iterator<Item = Option<U>>,
220     {
221         iter::try_process(iter, |i| i.sum())
222     }
223 }
224
225 #[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
226 impl<T, U> Product<Option<U>> for Option<T>
227 where
228     T: Product<U>,
229 {
230     /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
231     /// elements are taken, and the [`None`] is returned. Should no [`None`]
232     /// occur, the product of all elements is returned.
233     fn product<I>(iter: I) -> Option<T>
234     where
235         I: Iterator<Item = Option<U>>,
236     {
237         iter::try_process(iter, |i| i.product())
238     }
239 }