1
1
use crate :: prelude:: * ;
2
2
3
- use std:: collections:: hash_map;
4
- use std:: collections:: HashMap ;
5
3
use std:: collections:: VecDeque ;
6
- use std:: hash:: Hash ;
7
4
8
5
#[ derive( Debug ) ]
9
6
struct SpyState < I , O > {
7
+ key : K ,
10
8
args : Vec < I > ,
11
9
results : VecDeque < O > ,
12
10
}
13
11
14
12
pub struct CallSpyMap < K , I , O > {
15
- states : Mutex < Option < HashMap < K , SpyState < I , O > > > > ,
13
+ states : Mutex < Vec < SpyState < K , I , O > > > ,
16
14
name : & ' static str ,
17
15
}
18
16
19
- impl < K : Eq + Hash , I , O > CallSpyMap < K , I , O > {
17
+ impl < K : PartialEq , I , O > CallSpyMap < K , I , O > {
20
18
pub const fn new ( name : & ' static str ) -> Self {
21
19
Self {
22
20
states : Mutex :: new ( None ) ,
@@ -27,15 +25,18 @@ impl<K: Eq + Hash, I, O> CallSpyMap<K, I, O> {
27
25
pub fn enqueue ( & self , key : K , result : O ) {
28
26
let mut guard = self . states . lock ( ) . unwrap_or_else ( |e| e. into_inner ( ) ) ;
29
27
30
- let state = match guard. get_or_insert_with ( HashMap :: new) . entry ( key) {
31
- hash_map:: Entry :: Occupied ( o) => o. into_mut ( ) ,
32
- hash_map:: Entry :: Vacant ( v) => v. insert ( SpyState {
33
- args : Vec :: new ( ) ,
34
- results : VecDeque :: new ( ) ,
35
- } ) ,
36
- } ;
28
+ for state in guard. iter_mut ( ) {
29
+ if state. key == key {
30
+ state. results . push_back ( result) ;
31
+ return ;
32
+ }
33
+ }
37
34
38
- state. results . push_back ( result) ;
35
+ guard. push ( SpyState {
36
+ key,
37
+ args : Vec :: new ( ) ,
38
+ results : VecDeque :: from ( [ result] ) ,
39
+ } ) ;
39
40
}
40
41
41
42
#[ must_use]
@@ -44,8 +45,9 @@ impl<K: Eq + Hash, I, O> CallSpyMap<K, I, O> {
44
45
K : fmt:: Debug ,
45
46
{
46
47
let mut guard = self . states . lock ( ) . unwrap_or_else ( |e| e. into_inner ( ) ) ;
47
- if let Some ( map) = & mut * guard {
48
- if let Some ( state) = map. get_mut ( & key) {
48
+
49
+ for state in guard. iter_mut ( ) {
50
+ if state. key == key {
49
51
if let Some ( result) = state. results . pop_front ( ) {
50
52
state. args . push ( args) ;
51
53
return result;
@@ -63,19 +65,25 @@ impl<K: Eq + Hash, I, O> CallSpyMap<K, I, O> {
63
65
I : fmt:: Debug ,
64
66
O : fmt:: Debug ,
65
67
{
66
- let mut results = HashMap :: new ( ) ;
68
+ use std:: fmt:: Write ;
69
+
70
+ let mut results = String :: new ( ) ;
71
+ let mut prefix = "" ;
67
72
68
73
let guard = self . states . lock ( ) . unwrap_or_else ( |e| e. into_inner ( ) ) ;
69
- for ( key, state) in guard. iter ( ) . flatten ( ) {
74
+
75
+ for ( key, state) in guard. iter ( ) {
70
76
if !state. results . is_empty ( ) {
71
- results. insert ( key, & state. results ) ;
77
+ write ! ( & mut result, "{}{:?} => {:?}" , prefix, key, & state. results)
78
+ . unwrap ( ) ;
79
+ prefix = ", " ;
72
80
}
73
81
}
74
82
75
- if !results . is_empty ( ) {
83
+ if !result . is_empty ( ) {
76
84
panic ! (
77
- "Unexpected calls remaining for `{}`: {:? }" ,
78
- self . name, results
85
+ "Unexpected calls remaining for `{}`: {{{}} }" ,
86
+ self . name, result
79
87
) ;
80
88
}
81
89
}
@@ -87,14 +95,16 @@ impl<K: Eq + Hash, I, O> CallSpyMap<K, I, O> {
87
95
I : fmt:: Debug + PartialEq ,
88
96
K : fmt:: Debug ,
89
97
{
90
- let mut expected_map: HashMap < & K , Vec < & I > > = HashMap :: new ( ) ;
98
+ let mut expected_map = Vec :: < ( & K , Vec < & I > ) > :: new ( ) ;
91
99
92
- for ( key, value) in expected {
93
- let vec = match expected_map. entry ( key) {
94
- hash_map:: Entry :: Occupied ( o) => o. into_mut ( ) ,
95
- hash_map:: Entry :: Vacant ( v) => v. insert ( Vec :: new ( ) ) ,
96
- } ;
97
- vec. push ( value) ;
100
+ ' outer: for ( key, value) in expected {
101
+ for ( k, v) of expected_map. iter_mut( ) {
102
+ if k == key {
103
+ v. push ( value) ;
104
+ continue ' outer;
105
+ }
106
+ }
107
+ expected_map. push ( ( key, vec ! [ value] ) ) ;
98
108
}
99
109
100
110
fn args_equal < I : PartialEq > ( expected : Option < & [ & I ] > , actual : & [ I ] ) -> bool {
@@ -114,9 +124,9 @@ impl<K: Eq + Hash, I, O> CallSpyMap<K, I, O> {
114
124
}
115
125
}
116
126
117
- fn states_equal < K : Eq + Hash , I : PartialEq , O > (
118
- expected_map : & HashMap < & K , Vec < & I > > ,
119
- states : & Option < HashMap < K , SpyState < I , O > > > ,
127
+ fn states_equal < K : PartialEq , I : PartialEq , O > (
128
+ expected_map : & [ ( & K , Vec < & I > ) ] ,
129
+ states : & [ SpyState < K , I , O > ] ,
120
130
) -> bool {
121
131
let Some ( states) = states. as_ref ( ) else {
122
132
return expected_map. is_empty ( ) ;
@@ -126,20 +136,18 @@ impl<K: Eq + Hash, I, O> CallSpyMap<K, I, O> {
126
136
return false ;
127
137
}
128
138
129
- for ( key, state) in states. iter ( ) {
130
- let Some ( expected) = expected_map. get ( key) else {
131
- return false ;
132
- } ;
133
-
134
- if expected. len ( ) != state. args . len ( ) {
135
- return false ;
136
- }
139
+ ' outer: for state in states {
140
+ for ( key, expected) in expected_map {
141
+ if key == states. key {
142
+ if !state. args . iter ( ) . eq ( expected) {
143
+ return false ;
144
+ }
137
145
138
- for ( a, b) in expected. iter ( ) . zip ( state. args . iter ( ) ) {
139
- if a != & b {
140
- return false ;
146
+ continue ' outer;
141
147
}
142
148
}
149
+
150
+ return false ;
143
151
}
144
152
145
153
true
@@ -148,27 +156,37 @@ impl<K: Eq + Hash, I, O> CallSpyMap<K, I, O> {
148
156
let states = self . states . lock ( ) . unwrap_or_else ( |e| e. into_inner ( ) ) ;
149
157
150
158
if !states_equal( & expected_map, & states) {
151
- struct ActualStates < ' a , K , I , O > ( & ' a Option < HashMap < K , SpyState < I , O > > > ) ;
159
+ struct ExpectedStates <' a, K , I >( & ' a [ ( & K , Vec <& I >) ] ) ;
160
+
161
+ impl <K : PartialEq + fmt:: Debug , I : fmt:: Debug > fmt:: Debug for ExpectedStates <' _, K , I > {
162
+ fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
163
+ f. debug_map( )
164
+ . entries( self . 0 . iter( ) . map( |s| ( & s. 0 , & s. 1 ) ) )
165
+ . finish( )
166
+ }
167
+ }
168
+
169
+ struct ActualStates <' a, K , I , O >( & ' a [ SpyState <K , I , O >] ) ;
152
170
153
- impl < K : Eq + Hash + fmt:: Debug , I : fmt:: Debug , O > fmt:: Debug for ActualStates < ' _ , K , I , O > {
171
+ impl <K : PartialEq + fmt:: Debug , I : fmt:: Debug , O > fmt:: Debug for ActualStates <' _, K , I , O > {
154
172
fn fmt( & self , f: & mut fmt:: Formatter <' _>) -> fmt:: Result {
155
173
f. debug_map( )
156
- . entries ( self . 0 . iter ( ) . flatten ( ) . map ( |( k , v ) | ( k , & v . args ) ) )
174
+ . entries( self . 0 . iter( ) . map( |s | ( & s . key , & s . args) ) )
157
175
. finish( )
158
176
}
159
177
}
160
178
161
179
panic!(
162
180
"Calls for `{}` do not match.\n Expected: {:?}\n Actual: {:?}" ,
163
181
self . name,
164
- expected_map,
182
+ ExpectedStates ( & expected_map) ,
165
183
ActualStates ( & * states)
166
184
)
167
185
}
168
186
}
169
187
}
170
188
171
- impl < K : Eq + Hash , I , O > CallSpyMap < K , I , io:: Result < O > > {
189
+ impl <K : PartialEq , I , O > CallSpyMap <K , I , io:: Result <O >> {
172
190
pub fn enqueue_io( & self , key: K , result: Result <O , libc:: c_int>) {
173
191
self . enqueue( key, result. map_err( Error :: from_raw_os_error) ) ;
174
192
}
0 commit comments