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