@@ -102,6 +102,7 @@ pub mod structs {
102
102
#[ cfg( feature = "use_std" ) ]
103
103
pub use combinations:: Combinations ;
104
104
pub use cons_tuples_impl:: ConsTuples ;
105
+ pub use exactly_one_err:: ExactlyOneError ;
105
106
pub use format:: { Format , FormatWith } ;
106
107
#[ cfg( feature = "use_std" ) ]
107
108
pub use groupbylazy:: { IntoChunks , Chunk , Chunks , GroupBy , Group , Groups } ;
@@ -158,6 +159,7 @@ mod concat_impl;
158
159
mod cons_tuples_impl;
159
160
#[ cfg( feature = "use_std" ) ]
160
161
mod combinations;
162
+ mod exactly_one_err;
161
163
mod diff;
162
164
mod format;
163
165
#[ cfg( feature = "use_std" ) ]
@@ -1943,13 +1945,13 @@ pub trait Itertools : Iterator {
1943
1945
1944
1946
/// Return a `HashMap` of keys mapped to `Vec`s of values. Keys and values
1945
1947
/// are taken from `(Key, Value)` tuple pairs yielded by the input iterator.
1946
- ///
1948
+ ///
1947
1949
/// ```
1948
1950
/// use itertools::Itertools;
1949
- ///
1951
+ ///
1950
1952
/// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)];
1951
1953
/// let lookup = data.into_iter().into_group_map();
1952
- ///
1954
+ ///
1953
1955
/// assert_eq!(lookup[&0], vec![10, 20]);
1954
1956
/// assert_eq!(lookup.get(&1), None);
1955
1957
/// assert_eq!(lookup[&2], vec![12, 42]);
@@ -2038,6 +2040,42 @@ pub trait Itertools : Iterator {
2038
2040
|x, y, _, _| Ordering :: Less == compare ( x, y)
2039
2041
)
2040
2042
}
2043
+
2044
+ /// If the iterator yields exactly one element, that element will be returned, otherwise
2045
+ /// an error will be returned containing an iterator that has the same output as the input
2046
+ /// iterator.
2047
+ ///
2048
+ /// This provides an additional layer of validation over just calling `Iterator::next()`.
2049
+ /// If your assumption that there should only be one element yielded is false this provides
2050
+ /// the opportunity to detect and handle that, preventing errors at a distance.
2051
+ ///
2052
+ /// # Examples
2053
+ /// ```
2054
+ /// use itertools::Itertools;
2055
+ ///
2056
+ /// assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2);
2057
+ /// assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4));
2058
+ /// assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5));
2059
+ /// assert!((0..10).filter(|&x| false).exactly_one().unwrap_err().eq(0..0));
2060
+ /// ```
2061
+ fn exactly_one ( mut self ) -> Result < Self :: Item , ExactlyOneError < Self > >
2062
+ where
2063
+ Self : Sized ,
2064
+ {
2065
+ match self . next ( ) {
2066
+ Some ( first) => {
2067
+ match self . next ( ) {
2068
+ Some ( second) => {
2069
+ Err ( ExactlyOneError :: new ( ( Some ( first) , Some ( second) ) , self ) )
2070
+ }
2071
+ None => {
2072
+ Ok ( first)
2073
+ }
2074
+ }
2075
+ }
2076
+ None => Err ( ExactlyOneError :: new ( ( None , None ) , self ) ) ,
2077
+ }
2078
+ }
2041
2079
}
2042
2080
2043
2081
impl < T : ?Sized > Itertools for T where T : Iterator { }
0 commit comments