1+ use std:: error:: Error ;
2+ use std:: fmt:: { Debug , Display , Formatter , Result as FmtResult } ;
13use std:: iter:: ExactSizeIterator ;
24
5+ use either:: Either ;
6+
37use crate :: size_hint;
48
59/// Iterator returned for the error case of `IterTools::exactly_one()`
@@ -10,12 +14,12 @@ use crate::size_hint;
1014///
1115/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
1216/// use a `Vec`.
13- #[ derive( Debug , Clone ) ]
17+ #[ derive( Clone ) ]
1418pub struct ExactlyOneError < I >
1519where
1620 I : Iterator ,
1721{
18- first_two : ( Option < I :: Item > , Option < I :: Item > ) ,
22+ first_two : Option < Either < [ I :: Item ; 2 ] , I :: Item > > ,
1923 inner : I ,
2024}
2125
2428 I : Iterator ,
2529{
2630 /// Creates a new `ExactlyOneErr` iterator.
27- pub ( crate ) fn new ( first_two : ( Option < I :: Item > , Option < I :: Item > ) , inner : I ) -> Self {
31+ pub ( crate ) fn new ( first_two : Option < Either < [ I :: Item ; 2 ] , I :: Item > > , inner : I ) -> Self {
2832 Self { first_two, inner }
2933 }
34+
35+ fn additional_len ( & self ) -> usize {
36+ match self . first_two {
37+ Some ( Either :: Left ( _) ) => 2 ,
38+ Some ( Either :: Right ( _) ) => 1 ,
39+ None => 0 ,
40+ }
41+ }
3042}
3143
3244impl < I > Iterator for ExactlyOneError < I >
@@ -36,23 +48,73 @@ where
3648 type Item = I :: Item ;
3749
3850 fn next ( & mut self ) -> Option < Self :: Item > {
39- self . first_two
40- . 0
41- . take ( )
42- . or_else ( || self . first_two . 1 . take ( ) )
43- . or_else ( || self . inner . next ( ) )
51+ match self . first_two . take ( ) {
52+ Some ( Either :: Left ( [ first, second] ) ) => {
53+ self . first_two = Some ( Either :: Right ( second) ) ;
54+ Some ( first)
55+ } ,
56+ Some ( Either :: Right ( second) ) => {
57+ Some ( second)
58+ }
59+ None => {
60+ self . inner . next ( )
61+ }
62+ }
4463 }
4564
4665 fn size_hint ( & self ) -> ( usize , Option < usize > ) {
47- let mut additional_len = 0 ;
48- if self . first_two . 0 . is_some ( ) {
49- additional_len += 1 ;
66+ size_hint:: add_scalar ( self . inner . size_hint ( ) , self . additional_len ( ) )
67+ }
68+ }
69+
70+
71+ impl < I > ExactSizeIterator for ExactlyOneError < I > where I : ExactSizeIterator { }
72+
73+ impl < I > Display for ExactlyOneError < I >
74+ where I : Iterator
75+ {
76+ fn fmt ( & self , f : & mut Formatter ) -> FmtResult {
77+ let additional = self . additional_len ( ) ;
78+ if additional > 0 {
79+ write ! ( f, "got at least 2 elements when exactly one was expected" )
80+ } else {
81+ write ! ( f, "got zero elements when exactly one was expected" )
5082 }
51- if self . first_two . 1 . is_some ( ) {
52- additional_len += 1 ;
83+ }
84+ }
85+
86+ impl < I > Debug for ExactlyOneError < I >
87+ where I : Iterator ,
88+ I :: Item : Debug ,
89+ {
90+ fn fmt ( & self , f : & mut Formatter ) -> FmtResult {
91+ match & self . first_two {
92+ Some ( Either :: Left ( [ first, second] ) ) => {
93+ write ! ( f, "ExactlyOneError[{:?}, {:?}, ...]" , first, second)
94+ } ,
95+ Some ( Either :: Right ( second) ) => {
96+ write ! ( f, "ExactlyOneError[{:?}, ...]" , second)
97+ }
98+ None => {
99+ write ! ( f, "ExactlyOneError[...]" )
100+ }
53101 }
54- size_hint:: add_scalar ( self . inner . size_hint ( ) , additional_len)
55102 }
56103}
57104
58- impl < I > ExactSizeIterator for ExactlyOneError < I > where I : ExactSizeIterator { }
105+ impl < I > Error for ExactlyOneError < I > where I : Iterator , I :: Item : Debug , { }
106+
107+ #[ cfg( test) ]
108+ mod tests {
109+ use super :: * ;
110+
111+ #[ test]
112+ fn question_mark_syntax_works ( ) {
113+ question_mark_return ( ) . unwrap_err ( )
114+ }
115+
116+ fn question_mark_return ( ) -> Result < ( ) , impl Error > {
117+ let x = Err ( ExactlyOneError :: new ( None , [ ] ) ) ?;
118+ Ok ( ( ) )
119+ }
120+ }
0 commit comments