use crate::ops::{Mul, Add}; use crate::num::Wrapping; use crate::iter; /// Trait to represent types that can be created by summing up an iterator. /// /// This trait is used to implement the [`sum`] method on iterators. Types which /// implement the trait can be generated by the [`sum`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead /// interacted with through [`Iterator::sum`]. /// /// [`sum`]: ../../std/iter/trait.Sum.html#tymethod.sum /// [`FromIterator`]: ../../std/iter/trait.FromIterator.html /// [`Iterator::sum`]: ../../std/iter/trait.Iterator.html#method.sum #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// "summing up" the items. #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn sum>(iter: I) -> Self; } /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// /// This trait is used to implement the [`product`] method on iterators. Types /// which implement the trait can be generated by the [`product`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead /// interacted with through [`Iterator::product`]. /// /// [`product`]: ../../std/iter/trait.Product.html#tymethod.product /// [`FromIterator`]: ../../std/iter/trait.FromIterator.html /// [`Iterator::product`]: ../../std/iter/trait.Iterator.html#method.product #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by /// multiplying the items. #[stable(feature = "iter_arith_traits", since = "1.12.0")] fn product>(iter: I) -> Self; } // N.B., explicitly use Add and Mul here to inherit overflow checks macro_rules! integer_sum_product { (@impls $zero:expr, $one:expr, #[$attr:meta], $($a:ty)*) => ($( #[$attr] impl Sum for $a { fn sum>(iter: I) -> $a { iter.fold($zero, Add::add) } } #[$attr] impl Product for $a { fn product>(iter: I) -> $a { iter.fold($one, Mul::mul) } } #[$attr] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { iter.fold($zero, Add::add) } } #[$attr] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { iter.fold($one, Mul::mul) } } )*); ($($a:ty)*) => ( integer_sum_product!(@impls 0, 1, #[stable(feature = "iter_arith_traits", since = "1.12.0")], $($a)*); integer_sum_product!(@impls Wrapping(0), Wrapping(1), #[stable(feature = "wrapping_iter_arith", since = "1.14.0")], $(Wrapping<$a>)*); ); } macro_rules! float_sum_product { ($($a:ident)*) => ($( #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Sum for $a { fn sum>(iter: I) -> $a { iter.fold(0.0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl Product for $a { fn product>(iter: I) -> $a { iter.fold(1.0, Mul::mul) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Sum<&'a $a> for $a { fn sum>(iter: I) -> $a { iter.fold(0.0, Add::add) } } #[stable(feature = "iter_arith_traits", since = "1.12.0")] impl<'a> Product<&'a $a> for $a { fn product>(iter: I) -> $a { iter.fold(1.0, Mul::mul) } } )*) } integer_sum_product! { i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize } float_sum_product! { f32 f64 } #[stable(feature = "iter_arith_traits_result", since="1.16.0")] impl Sum> for Result where T: Sum, { /// Takes each element in the `Iterator`: if it is an `Err`, no further /// elements are taken, and the `Err` is returned. Should no `Err` occur, /// the sum of all elements is returned. /// /// # Examples /// /// This sums up every integer in a vector, rejecting the sum if a negative /// element is encountered: /// /// ``` /// let v = vec![1, 2]; /// let res: Result = v.iter().map(|&x: &i32| /// if x < 0 { Err("Negative element found") } /// else { Ok(x) } /// ).sum(); /// assert_eq!(res, Ok(3)); /// ``` fn sum(iter: I) -> Result where I: Iterator>, { iter::process_results(iter, |i| i.sum()) } } #[stable(feature = "iter_arith_traits_result", since="1.16.0")] impl Product> for Result where T: Product, { /// Takes each element in the `Iterator`: if it is an `Err`, no further /// elements are taken, and the `Err` is returned. Should no `Err` occur, /// the product of all elements is returned. fn product(iter: I) -> Result where I: Iterator>, { iter::process_results(iter, |i| i.product()) } } #[stable(feature = "iter_arith_traits_option", since = "1.37.0")] impl Sum> for Option where T: Sum, { /// Takes each element in the `Iterator`: if it is a `None`, no further /// elements are taken, and the `None` is returned. Should no `None` occur, /// the sum of all elements is returned. /// /// # Examples /// /// This sums up the position of the character 'a' in a vector of strings, /// if a word did not have the character 'a' the operation returns `None`: /// /// ``` /// let words = vec!["have", "a", "great", "day"]; /// let total: Option = words.iter().map(|w| w.find('a')).sum(); /// assert_eq!(total, Some(5)); /// ``` fn sum(iter: I) -> Option where I: Iterator>, { iter.map(|x| x.ok_or(())).sum::>().ok() } } #[stable(feature = "iter_arith_traits_option", since = "1.37.0")] impl Product> for Option where T: Product, { /// Takes each element in the `Iterator`: if it is a `None`, no further /// elements are taken, and the `None` is returned. Should no `None` occur, /// the product of all elements is returned. fn product(iter: I) -> Option where I: Iterator>, { iter.map(|x| x.ok_or(())).product::>().ok() } }