@@ -2,6 +2,8 @@ use std::cmp::Ordering;
2
2
use std:: iter:: Fuse ;
3
3
use std:: fmt;
4
4
5
+ use either:: Either ;
6
+
5
7
use super :: adaptors:: { PutBack , put_back} ;
6
8
use crate :: either_or_both:: EitherOrBoth ;
7
9
#[ cfg( doc) ]
@@ -10,11 +12,11 @@ use crate::Itertools;
10
12
/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order.
11
13
///
12
14
/// [`IntoIterator`] enabled version of [`Itertools::merge_join_by`].
13
- pub fn merge_join_by < I , J , F > ( left : I , right : J , cmp_fn : F )
14
- -> MergeJoinBy < I :: IntoIter , J :: IntoIter , F >
15
+ pub fn merge_join_by < I , J , F , R > ( left : I , right : J , cmp_fn : F )
16
+ -> MergeJoinBy < I :: IntoIter , J :: IntoIter , F , R >
15
17
where I : IntoIterator ,
16
18
J : IntoIterator ,
17
- F : FnMut ( & I :: Item , & J :: Item ) -> Ordering
19
+ F : FnMut ( & I :: Item , & J :: Item ) -> R ,
18
20
{
19
21
MergeJoinBy {
20
22
left : put_back ( left. into_iter ( ) . fuse ( ) ) ,
@@ -27,56 +29,119 @@ pub fn merge_join_by<I, J, F>(left: I, right: J, cmp_fn: F)
27
29
///
28
30
/// See [`.merge_join_by()`](crate::Itertools::merge_join_by) for more information.
29
31
#[ must_use = "iterator adaptors are lazy and do nothing unless consumed" ]
30
- pub struct MergeJoinBy < I : Iterator , J : Iterator , F > {
32
+ pub struct MergeJoinBy < I , J , F , R >
33
+ where I : Iterator ,
34
+ J : Iterator ,
35
+ F : FnMut ( & I :: Item , & J :: Item ) -> R ,
36
+ {
31
37
left : PutBack < Fuse < I > > ,
32
38
right : PutBack < Fuse < J > > ,
33
39
cmp_fn : F
34
40
}
35
41
36
- impl < I , J , F > Clone for MergeJoinBy < I , J , F >
42
+ pub trait OrderingOrBool < I , J > {
43
+ type Item ;
44
+ fn into_cmp ( self ) -> Ordering ;
45
+ fn left ( left : I ) -> Self :: Item ;
46
+ fn right ( right : J ) -> Self :: Item ;
47
+ fn both ( left : I , right : J ) -> Self :: Item ;
48
+ }
49
+
50
+ impl < I , J , F , R > Clone for MergeJoinBy < I , J , F , R >
37
51
where I : Iterator ,
38
52
J : Iterator ,
39
53
PutBack < Fuse < I > > : Clone ,
40
54
PutBack < Fuse < J > > : Clone ,
41
- F : Clone ,
55
+ F : FnMut ( & I :: Item , & J :: Item ) -> R + Clone ,
42
56
{
43
57
clone_fields ! ( left, right, cmp_fn) ;
44
58
}
45
59
46
- impl < I , J , F > fmt:: Debug for MergeJoinBy < I , J , F >
60
+ impl < I , J , F , R > fmt:: Debug for MergeJoinBy < I , J , F , R >
47
61
where I : Iterator + fmt:: Debug ,
48
62
I :: Item : fmt:: Debug ,
49
63
J : Iterator + fmt:: Debug ,
50
64
J :: Item : fmt:: Debug ,
65
+ F : FnMut ( & I :: Item , & J :: Item ) -> R ,
51
66
{
52
67
debug_fmt_fields ! ( MergeJoinBy , left, right) ;
53
68
}
54
69
55
- impl < I , J , F > Iterator for MergeJoinBy < I , J , F >
70
+ impl < I , J > OrderingOrBool < I , J > for Ordering {
71
+ type Item = EitherOrBoth < I , J > ;
72
+
73
+ #[ inline( always) ]
74
+ fn into_cmp ( self ) -> Ordering {
75
+ self
76
+ }
77
+
78
+ #[ inline( always) ]
79
+ fn left ( left : I ) -> Self :: Item {
80
+ EitherOrBoth :: Left ( left)
81
+ }
82
+
83
+ #[ inline( always) ]
84
+ fn right ( right : J ) -> Self :: Item {
85
+ EitherOrBoth :: Right ( right)
86
+ }
87
+
88
+ #[ inline( always) ]
89
+ fn both ( left : I , right : J ) -> Self :: Item {
90
+ EitherOrBoth :: Both ( left, right)
91
+ }
92
+ }
93
+
94
+ impl < I , J > OrderingOrBool < I , J > for bool {
95
+ type Item = Either < I , J > ;
96
+
97
+ #[ inline( always) ]
98
+ fn into_cmp ( self ) -> Ordering {
99
+ if self {
100
+ Ordering :: Less
101
+ } else {
102
+ Ordering :: Greater
103
+ }
104
+ }
105
+
106
+ #[ inline( always) ]
107
+ fn left ( left : I ) -> Self :: Item {
108
+ Either :: Left ( left)
109
+ }
110
+
111
+ #[ inline( always) ]
112
+ fn right ( right : J ) -> Self :: Item {
113
+ Either :: Right ( right)
114
+ }
115
+
116
+ #[ inline( always) ]
117
+ fn both ( _left : I , _right : J ) -> Self :: Item {
118
+ unreachable ! ( "into_cmp never returns Ordering::Equal so this should never be called" )
119
+ }
120
+ }
121
+
122
+ impl < I , J , F , R > Iterator for MergeJoinBy < I , J , F , R >
56
123
where I : Iterator ,
57
124
J : Iterator ,
58
- F : FnMut ( & I :: Item , & J :: Item ) -> Ordering
125
+ F : FnMut ( & I :: Item , & J :: Item ) -> R ,
126
+ R : OrderingOrBool < I :: Item , J :: Item > ,
59
127
{
60
- type Item = EitherOrBoth < I :: Item , J :: Item > ;
128
+ type Item = R :: Item ;
61
129
62
130
fn next ( & mut self ) -> Option < Self :: Item > {
63
131
match ( self . left . next ( ) , self . right . next ( ) ) {
64
132
( None , None ) => None ,
65
- ( Some ( left) , None ) =>
66
- Some ( EitherOrBoth :: Left ( left) ) ,
67
- ( None , Some ( right) ) =>
68
- Some ( EitherOrBoth :: Right ( right) ) ,
133
+ ( Some ( left) , None ) => Some ( R :: left ( left) ) ,
134
+ ( None , Some ( right) ) => Some ( R :: right ( right) ) ,
69
135
( Some ( left) , Some ( right) ) => {
70
- match ( self . cmp_fn ) ( & left, & right) {
71
- Ordering :: Equal =>
72
- Some ( EitherOrBoth :: Both ( left, right) ) ,
136
+ match ( self . cmp_fn ) ( & left, & right) . into_cmp ( ) {
137
+ Ordering :: Equal => Some ( R :: both ( left, right) ) ,
73
138
Ordering :: Less => {
74
139
self . right . put_back ( right) ;
75
- Some ( EitherOrBoth :: Left ( left) )
140
+ Some ( R :: left ( left) )
76
141
} ,
77
142
Ordering :: Greater => {
78
143
self . left . put_back ( left) ;
79
- Some ( EitherOrBoth :: Right ( right) )
144
+ Some ( R :: right ( right) )
80
145
}
81
146
}
82
147
}
@@ -106,7 +171,7 @@ impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
106
171
( None , Some ( _right) ) => break count + 1 + self . right . into_parts ( ) . 1 . count ( ) ,
107
172
( Some ( left) , Some ( right) ) => {
108
173
count += 1 ;
109
- match ( self . cmp_fn ) ( & left, & right) {
174
+ match ( self . cmp_fn ) ( & left, & right) . into_cmp ( ) {
110
175
Ordering :: Equal => { }
111
176
Ordering :: Less => self . right . put_back ( right) ,
112
177
Ordering :: Greater => self . left . put_back ( left) ,
@@ -122,25 +187,25 @@ impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
122
187
match ( self . left . next ( ) , self . right . next ( ) ) {
123
188
( None , None ) => break previous_element,
124
189
( Some ( left) , None ) => {
125
- break Some ( EitherOrBoth :: Left (
190
+ break Some ( R :: left (
126
191
self . left . into_parts ( ) . 1 . last ( ) . unwrap_or ( left) ,
127
192
) )
128
193
}
129
194
( None , Some ( right) ) => {
130
- break Some ( EitherOrBoth :: Right (
195
+ break Some ( R :: right (
131
196
self . right . into_parts ( ) . 1 . last ( ) . unwrap_or ( right) ,
132
197
) )
133
198
}
134
199
( Some ( left) , Some ( right) ) => {
135
- previous_element = match ( self . cmp_fn ) ( & left, & right) {
136
- Ordering :: Equal => Some ( EitherOrBoth :: Both ( left, right) ) ,
200
+ previous_element = match ( self . cmp_fn ) ( & left, & right) . into_cmp ( ) {
201
+ Ordering :: Equal => Some ( R :: both ( left, right) ) ,
137
202
Ordering :: Less => {
138
203
self . right . put_back ( right) ;
139
- Some ( EitherOrBoth :: Left ( left) )
204
+ Some ( R :: left ( left) )
140
205
}
141
206
Ordering :: Greater => {
142
207
self . left . put_back ( left) ;
143
- Some ( EitherOrBoth :: Right ( right) )
208
+ Some ( R :: right ( right) )
144
209
}
145
210
}
146
211
}
@@ -156,9 +221,9 @@ impl<I, J, F> Iterator for MergeJoinBy<I, J, F>
156
221
n -= 1 ;
157
222
match ( self . left . next ( ) , self . right . next ( ) ) {
158
223
( None , None ) => break None ,
159
- ( Some ( _left) , None ) => break self . left . nth ( n) . map ( EitherOrBoth :: Left ) ,
160
- ( None , Some ( _right) ) => break self . right . nth ( n) . map ( EitherOrBoth :: Right ) ,
161
- ( Some ( left) , Some ( right) ) => match ( self . cmp_fn ) ( & left, & right) {
224
+ ( Some ( _left) , None ) => break self . left . nth ( n) . map ( R :: left ) ,
225
+ ( None , Some ( _right) ) => break self . right . nth ( n) . map ( R :: right ) ,
226
+ ( Some ( left) , Some ( right) ) => match ( self . cmp_fn ) ( & left, & right) . into_cmp ( ) {
162
227
Ordering :: Equal => { }
163
228
Ordering :: Less => self . right . put_back ( right) ,
164
229
Ordering :: Greater => self . left . put_back ( left) ,
0 commit comments