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
48#[cfg(not(feature = "ferrocene_certified"))]
49macro_rules! integer_sum_product {
50    (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($(
51        #[$attr]
52        impl Sum for $a {
53            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
54                iter.fold(
55                    $zero,
56                    #[rustc_inherit_overflow_checks]
57                    |a, b| a + b,
58                )
59            }
60        }
61
62        #[$attr]
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        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
105#[cfg(not(feature = "ferrocene_certified"))]
106macro_rules! saturating_integer_sum_product {
107    (@impls $zero:expr, $one:expr, $doc:expr, #[$attr:meta], $($a:ty)*) => ($(
108        #[$attr]
109        #[doc = $doc]
110        impl Sum for $a {
111            fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
112                iter.fold(
113                    $zero,
114                    |a, b| a + b,
115                )
116            }
117        }
118
119        #[$attr]
120        #[doc = $doc]
121        impl Product for $a {
122            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
123                iter.fold(
124                    $one,
125                    |a, b| a * b,
126                )
127            }
128        }
129
130        #[$attr]
131        #[doc = $doc]
132        impl<'a> Sum<&'a $a> for $a {
133            fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
134                iter.fold(
135                    $zero,
136                    |a, b| a + b,
137                )
138            }
139        }
140
141        #[$attr]
142        #[doc = $doc]
143        impl<'a> Product<&'a $a> for $a {
144            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
145                iter.fold(
146                    $one,
147                    |a, b| a * b,
148                )
149            }
150        }
151    )*);
152    ($($a:ty)*) => (
153        saturating_integer_sum_product!(@impls Saturating(0), Saturating(1),
154                "The short-circuiting behavior of this implementation is unspecified. If you care about \
155                short-circuiting, use [`Iterator::fold`] directly.",
156                #[stable(feature = "saturating_iter_arith", since = "1.91.0")],
157                $(Saturating<$a>)*);
158    );
159}
160
161macro_rules! float_sum_product {
162    ($($a:ident)*) => ($(
163        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
164        impl Sum for $a {
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        #[cfg(not(feature = "ferrocene_certified"))]
176        impl Product for $a {
177            fn product<I: Iterator<Item=Self>>(iter: I) -> Self {
178                iter.fold(
179                    1.0,
180                    #[rustc_inherit_overflow_checks]
181                    |a, b| a * b,
182                )
183            }
184        }
185
186        #[stable(feature = "iter_arith_traits", since = "1.12.0")]
187        impl<'a> Sum<&'a $a> for $a {
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        #[cfg(not(feature = "ferrocene_certified"))]
199        impl<'a> Product<&'a $a> for $a {
200            fn product<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
201                iter.fold(
202                    1.0,
203                    #[rustc_inherit_overflow_checks]
204                    |a, b| a * b,
205                )
206            }
207        }
208    )*)
209}
210
211#[cfg(not(feature = "ferrocene_certified"))]
212integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize }
213#[cfg(not(feature = "ferrocene_certified"))]
214saturating_integer_sum_product! { u8 u16 u32 u64 u128 usize }
215float_sum_product! { f16 f32 f64 f128 }
216
217#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
218#[cfg(not(feature = "ferrocene_certified"))]
219impl<T, U, E> Sum<Result<U, E>> for Result<T, E>
220where
221    T: Sum<U>,
222{
223    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
224    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
225    /// occur, the sum of all elements is returned.
226    ///
227    /// # Examples
228    ///
229    /// This sums up every integer in a vector, rejecting the sum if a negative
230    /// element is encountered:
231    ///
232    /// ```
233    /// let f = |&x: &i32| if x < 0 { Err("Negative element found") } else { Ok(x) };
234    /// let v = vec![1, 2];
235    /// let res: Result<i32, _> = v.iter().map(f).sum();
236    /// assert_eq!(res, Ok(3));
237    /// let v = vec![1, -2];
238    /// let res: Result<i32, _> = v.iter().map(f).sum();
239    /// assert_eq!(res, Err("Negative element found"));
240    /// ```
241    fn sum<I>(iter: I) -> Result<T, E>
242    where
243        I: Iterator<Item = Result<U, E>>,
244    {
245        iter::try_process(iter, |i| i.sum())
246    }
247}
248
249#[stable(feature = "iter_arith_traits_result", since = "1.16.0")]
250#[cfg(not(feature = "ferrocene_certified"))]
251impl<T, U, E> Product<Result<U, E>> for Result<T, E>
252where
253    T: Product<U>,
254{
255    /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further
256    /// elements are taken, and the [`Err`] is returned. Should no [`Err`]
257    /// occur, the product of all elements is returned.
258    ///
259    /// # Examples
260    ///
261    /// This multiplies each number in a vector of strings,
262    /// if a string could not be parsed the operation returns `Err`:
263    ///
264    /// ```
265    /// let nums = vec!["5", "10", "1", "2"];
266    /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();
267    /// assert_eq!(total, Ok(100));
268    /// let nums = vec!["5", "10", "one", "2"];
269    /// let total: Result<usize, _> = nums.iter().map(|w| w.parse::<usize>()).product();
270    /// assert!(total.is_err());
271    /// ```
272    fn product<I>(iter: I) -> Result<T, E>
273    where
274        I: Iterator<Item = Result<U, E>>,
275    {
276        iter::try_process(iter, |i| i.product())
277    }
278}
279
280#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
281#[cfg(not(feature = "ferrocene_certified"))]
282impl<T, U> Sum<Option<U>> for Option<T>
283where
284    T: Sum<U>,
285{
286    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
287    /// elements are taken, and the [`None`] is returned. Should no [`None`]
288    /// occur, the sum of all elements is returned.
289    ///
290    /// # Examples
291    ///
292    /// This sums up the position of the character 'a' in a vector of strings,
293    /// if a word did not have the character 'a' the operation returns `None`:
294    ///
295    /// ```
296    /// let words = vec!["have", "a", "great", "day"];
297    /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
298    /// assert_eq!(total, Some(5));
299    /// let words = vec!["have", "a", "good", "day"];
300    /// let total: Option<usize> = words.iter().map(|w| w.find('a')).sum();
301    /// assert_eq!(total, None);
302    /// ```
303    fn sum<I>(iter: I) -> Option<T>
304    where
305        I: Iterator<Item = Option<U>>,
306    {
307        iter::try_process(iter, |i| i.sum())
308    }
309}
310
311#[stable(feature = "iter_arith_traits_option", since = "1.37.0")]
312#[cfg(not(feature = "ferrocene_certified"))]
313impl<T, U> Product<Option<U>> for Option<T>
314where
315    T: Product<U>,
316{
317    /// Takes each element in the [`Iterator`]: if it is a [`None`], no further
318    /// elements are taken, and the [`None`] is returned. Should no [`None`]
319    /// occur, the product of all elements is returned.
320    ///
321    /// # Examples
322    ///
323    /// This multiplies each number in a vector of strings,
324    /// if a string could not be parsed the operation returns `None`:
325    ///
326    /// ```
327    /// let nums = vec!["5", "10", "1", "2"];
328    /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product();
329    /// assert_eq!(total, Some(100));
330    /// let nums = vec!["5", "10", "one", "2"];
331    /// let total: Option<usize> = nums.iter().map(|w| w.parse::<usize>().ok()).product();
332    /// assert_eq!(total, None);
333    /// ```
334    fn product<I>(iter: I) -> Option<T>
335    where
336        I: Iterator<Item = Option<U>>,
337    {
338        iter::try_process(iter, |i| i.product())
339    }
340}