1
+ use std:: error:: Error ;
2
+ use std:: fmt:: { Debug , Display , Formatter , Result as FmtResult } ;
1
3
use std:: iter:: ExactSizeIterator ;
2
4
5
+ use either:: Either ;
6
+
3
7
use crate :: size_hint;
4
8
5
9
/// Iterator returned for the error case of `IterTools::exactly_one()`
@@ -10,12 +14,12 @@ use crate::size_hint;
10
14
///
11
15
/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not
12
16
/// use a `Vec`.
13
- #[ derive( Debug , Clone ) ]
17
+ #[ derive( Clone ) ]
14
18
pub struct ExactlyOneError < I >
15
19
where
16
20
I : Iterator ,
17
21
{
18
- first_two : ( Option < I :: Item > , Option < I :: Item > ) ,
22
+ first_two : Option < Either < [ I :: Item ; 2 ] , I :: Item > > ,
19
23
inner : I ,
20
24
}
21
25
24
28
I : Iterator ,
25
29
{
26
30
/// 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 {
28
32
Self { first_two, inner }
29
33
}
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
+ }
30
42
}
31
43
32
44
impl < I > Iterator for ExactlyOneError < I >
@@ -36,23 +48,73 @@ where
36
48
type Item = I :: Item ;
37
49
38
50
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
+ }
44
63
}
45
64
46
65
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" )
50
82
}
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
+ }
53
101
}
54
- size_hint:: add_scalar ( self . inner . size_hint ( ) , additional_len)
55
102
}
56
103
}
57
104
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