core/iter/traits/
accum.rs

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