Skip to main content

core/iter/traits/
accum.rs

1use crate::iter;
2use crate::num::{Saturating, 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_const_unstable(feature = "const_iter", issue = "92476")]
14#[diagnostic::on_unimplemented(
15    message = "a value of type `{Self}` cannot be made by summing an iterator over elements of type `{A}`",
16    label = "value of type `{Self}` cannot be made by summing a `std::iter::Iterator<Item={A}>`"
17)]
18pub const trait Sum<A = Self>: Sized {
19    /// Takes an iterator and generates `Self` from the elements by "summing up"
20    /// the items.
21    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
22    fn sum<I: Iterator<Item = A>>(iter: I) -> Self;
23}
24
25/// Trait to represent types that can be created by multiplying elements of an
26/// iterator.
27///
28/// This trait is used to implement [`Iterator::product()`]. Types which implement
29/// this trait can be generated by using the [`product()`] method on an iterator.
30/// Like [`FromIterator`], this trait should rarely be called directly.
31///
32/// [`product()`]: Iterator::product
33/// [`FromIterator`]: iter::FromIterator
34#[stable(feature = "iter_arith_traits", since = "1.12.0")]
35#[rustc_const_unstable(feature = "const_iter", issue = "92476")]
36#[diagnostic::on_unimplemented(
37    message = "a value of type `{Self}` cannot be made by multiplying all elements of type `{A}` from an iterator",
38    label = "value of type `{Self}` cannot be made by multiplying all elements from a `std::iter::Iterator<Item={A}>`"
39)]
40pub const trait Product<A = Self>: Sized {
41    /// Takes an iterator and generates `Self` from the elements by multiplying
42    /// the items.
43    #[stable(feature = "iter_arith_traits", since = "1.12.0")]
44    fn product<I: Iterator<Item = A>>(iter: I) -> Self;
45}
46
47macro_rules! integer_sum_product {
48    (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($(
49        #[$attr]
50        impl Sum for $a {
51            #[ferrocene::prevalidated]
52            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
53                iter.fold(
54                    $zero,
55                    #[rustc_inherit_overflow_checks]
56                    |a, b| a + b,
57                )
58            }
59        }
60
61        #[$attr]
62        impl Product for $a {
63            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
64                iter.fold(
65                    $one,
66                    #[rustc_inherit_overflow_checks]
67                    |a, b| a * b,
68                )
69            }
70        }
71
72        #[$attr]
73        impl<'a> Sum<&'a $a> for $a {
74            #[ferrocene::prevalidated]
75            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
76                iter.fold(
77                    $zero,
78                    #[rustc_inherit_overflow_checks]
79                    |a, b| a + b,
80                )
81            }
82        }
83
84        #[$attr]
85        impl<'a> Product<&'a $a> for $a {
86            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
87                iter.fold(
88                    $one,
89                    #[rustc_inherit_overflow_checks]
90                    |a, b| a * b,
91                )
92            }
93        }
94    )*);
95    ($($a:ty)*) => (
96        integer_sum_product!(@impls 0, 1,
97                #[stable(feature = "iter_arith_traits", since = "1.12.0")],
98                $($a)*);
99        integer_sum_product!(@impls Wrapping(0), Wrapping(1),
100                #[stable(feature = "wrapping_iter_arith", since = "1.14.0")],
101                $(Wrapping<$a>)*);
102    );
103}
104
105macro_rules! saturating_integer_sum_product {
106    (@impls $zero:expr, $one:expr, $doc:expr, #[$attr:meta], $($a:ty)*) => ($(
107        #[$attr]
108        #[doc = $doc]
109        impl Sum for $a {
110            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
111                iter.fold(
112                    $zero,
113                    |a, b| a + b,
114                )
115            }
116        }
117
118        #[$attr]
119        #[doc = $doc]
120        impl Product for $a {
121            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
122                iter.fold(
123                    $one,
124                    |a, b| a * b,
125                )
126            }
127        }
128
129        #[$attr]
130        #[doc = $doc]
131        impl<'a> Sum<&'a $a> for $a {
132            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
133                iter.fold(
134                    $zero,
135                    |a, b| a + b,
136                )
137            }
138        }
139
140        #[$attr]
141        #[doc = $doc]
142        impl<'a> Product<&'a $a> for $a {
143            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
144                iter.fold(
145                    $one,
146                    |a, b| a * b,
147                )
148            }
149        }
150    )*);
151    ($($a:ty)*) => (
152        saturating_integer_sum_product!(@impls Saturating(0), Saturating(1),
153                "The short-circuiting behavior of this implementation is unspecified. If you care about \
154                short-circuiting, use [`Iterator::fold`] directly.",
155                #[stable(feature = "saturating_iter_arith", since = "1.91.0")],
156                $(Saturating<$a>)*);
157    );
158}
159
160macro_rules! float_sum_product {
161    ($($a:ident)*) => ($(
162        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
163        impl Sum for $a {
164            #[ferrocene::prevalidated]
165            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
166                iter.fold(
167                    -0.0,
168                    #[rustc_inherit_overflow_checks]
169                    |a, b| a + b,
170                )
171            }
172        }
173
174        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
175        impl Product for $a {
176            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
177                iter.fold(
178                    1.0,
179                    #[rustc_inherit_overflow_checks]
180                    |a, b| a * b,
181                )
182            }
183        }
184
185        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
186        impl<'a> Sum<&'a $a> for $a {
187            #[ferrocene::prevalidated]
188            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
189                iter.fold(
190                    -0.0,
191                    #[rustc_inherit_overflow_checks]
192                    |a, b| a + b,
193                )
194            }
195        }
196
197        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
198        impl<'a> Product<&'a $a> for $a {
199            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
200                iter.fold(
201                    1.0,
202                    #[rustc_inherit_overflow_checks]
203                    |a, b| a * b,
204                )
205            }
206        }
207    )*)
208}
209
210integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
211saturating_integer_sum_product! { u8 u16 u32 u64 u128 usize }
212float_sum_product! { f16 f32 f64 f128 }
213
214#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
215impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
216where
217    T: Sum<U>,
218{
219    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
220    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
221    /// occur, the sum of all elements is returned.
222    ///
223    /// # Examples
224    ///
225    /// This sums up every integer in a vector, rejecting the sum if a negative
226    /// element is encountered:
227    ///
228    /// ```
229    /// let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) };
230    /// let v = vec![1, 2];
231    /// let res: Result<i32, _> = v.iter().map(f).sum();
232    /// assert_eq!(res, Ok(3));
233    /// let v = vec![1, -2];
234    /// let res: Result<i32, _> = v.iter().map(f).sum();
235    /// assert_eq!(res, Err("Negative element found"));
236    /// ```
237    fn sum<I>(iter: I) -> Result<T, E>
238    where
239        I: Iterator<Item = Result<U, E>>,
240    {
241        iter::try_process(iter, |i| i.sum())
242    }
243}
244
245#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
246impl<T, U, E> Product<Result<U, E>> for Result<T, E>
247where
248    T: Product<U>,
249{
250    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
251    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
252    /// occur, the product of all elements is returned.
253    ///
254    /// # Examples
255    ///
256    /// This multiplies each number in a vector of strings,
257    /// if a string could not be parsed the operation returns `Err`:
258    ///
259    /// ```
260    /// let nums = vec!["5", "10", "1", "2"];
261    /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();
262    /// assert_eq!(total, Ok(100));
263    /// let nums = vec!["5", "10", "one", "2"];
264    /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();
265    /// assert!(total.is_err());
266    /// ```
267    fn product<I>(iter: I) -> Result<T, E>
268    where
269        I: Iterator<Item = Result<U, E>>,
270    {
271        iter::try_process(iter, |i| i.product())
272    }
273}
274
275#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
276impl<T, U> Sum<Option<U>> for Option<T>
277where
278    T: Sum<U>,
279{
280    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
281    /// elements are taken, and the [`None`] is returned. Should no [`None`]
282    /// occur, the sum of all elements is returned.
283    ///
284    /// # Examples
285    ///
286    /// This sums up the position of the character 'a' in a vector of strings,
287    /// if a word did not have the character 'a' the operation returns `None`:
288    ///
289    /// ```
290    /// let words = vec!["have", "a", "great", "day"];
291    /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
292    /// assert_eq!(total, Some(5));
293    /// let words = vec!["have", "a", "good", "day"];
294    /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
295    /// assert_eq!(total, None);
296    /// ```
297    fn sum<I>(iter: I) -> Option<T>
298    where
299        I: Iterator<Item = Option<U>>,
300    {
301        iter::try_process(iter, |i| i.sum())
302    }
303}
304
305#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
306impl<T, U> Product<Option<U>> for Option<T>
307where
308    T: Product<U>,
309{
310    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
311    /// elements are taken, and the [`None`] is returned. Should no [`None`]
312    /// occur, the product of all elements is returned.
313    ///
314    /// # Examples
315    ///
316    /// This multiplies each number in a vector of strings,
317    /// if a string could not be parsed the operation returns `None`:
318    ///
319    /// ```
320    /// let nums = vec!["5", "10", "1", "2"];
321    /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product();
322    /// assert_eq!(total, Some(100));
323    /// let nums = vec!["5", "10", "one", "2"];
324    /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product();
325    /// assert_eq!(total, None);
326    /// ```
327    fn product<I>(iter: I) -> Option<T>
328    where
329        I: Iterator<Item = Option<U>>,
330    {
331        iter::try_process(iter, |i| i.product())
332    }
333}