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