@@ -142,9 +142,8 @@ macro_rules! contains_each {
142
142
/// verify_that!(vec![3, 1], is_contained_in![ge(3), ge(3), ge(3)])?; // Fails: no matching
143
143
/// ```
144
144
///
145
- /// The actual value must be a container implementing [`IntoIterator`] and
146
- /// [`HasSize`][crate::matchers::has_size::HasSize]. This includes all common
147
- /// containers in the Rust standard library.
145
+ /// The actual value must be a container implementing [`IntoIterator`]. This
146
+ /// includes standard containers, slices (when dereferenced) and arrays.
148
147
///
149
148
/// This matcher does not support matching directly against an [`Iterator`]. To
150
149
/// match against an iterator, use [`Iterator::collect`] to build a [`Vec`].
@@ -191,10 +190,6 @@ pub mod internal {
191
190
use googletest:: matcher:: { MatchExplanation , Matcher , MatcherResult } ;
192
191
#[ cfg( not( google3) ) ]
193
192
use googletest:: matchers:: description:: Description ;
194
- #[ cfg( not( google3) ) ]
195
- use googletest:: matchers:: has_size:: HasSize ;
196
- #[ cfg( google3) ]
197
- use has_size:: HasSize ;
198
193
use std:: collections:: HashSet ;
199
194
use std:: fmt:: { Debug , Display } ;
200
195
@@ -259,17 +254,14 @@ pub mod internal {
259
254
// one expected element and vice versa.
260
255
// 3. `UnorderedElementsAre` verifies that a perfect matching exists using
261
256
// Ford-Fulkerson.
262
- impl < ' a , T : Debug , ContainerT : Debug + HasSize , const N : usize > Matcher < ContainerT >
257
+ impl < ' a , T : Debug , ContainerT : Debug + ? Sized , const N : usize > Matcher < ContainerT >
263
258
for UnorderedElementsAre < ' a , T , N >
264
259
where
265
260
for < ' b > & ' b ContainerT : IntoIterator < Item = & ' b T > ,
266
261
{
267
262
fn matches ( & self , actual : & ContainerT ) -> MatcherResult {
268
263
match self . requirements {
269
264
Requirements :: PerfectMatch => {
270
- if actual. size ( ) != N {
271
- return MatcherResult :: DoesNotMatch ;
272
- }
273
265
let match_matrix = MatchMatrix :: generate ( actual, & self . elements ) ;
274
266
if !match_matrix. find_unmatchable_elements ( ) . has_unmatchable_elements ( )
275
267
&& match_matrix. find_best_match ( ) . is_full_match ( )
@@ -280,9 +272,6 @@ pub mod internal {
280
272
}
281
273
}
282
274
Requirements :: Superset => {
283
- if actual. size ( ) < N {
284
- return MatcherResult :: DoesNotMatch ;
285
- }
286
275
let match_matrix = MatchMatrix :: generate ( actual, & self . elements ) ;
287
276
if !match_matrix. find_unmatched_expected ( ) . has_unmatchable_elements ( )
288
277
&& match_matrix. find_best_match ( ) . is_superset_match ( )
@@ -293,9 +282,6 @@ pub mod internal {
293
282
}
294
283
}
295
284
Requirements :: Subset => {
296
- if actual. size ( ) > N {
297
- return MatcherResult :: DoesNotMatch ;
298
- }
299
285
let match_matrix = MatchMatrix :: generate ( actual, & self . elements ) ;
300
286
if !match_matrix. find_unmatched_actual ( ) . has_unmatchable_elements ( )
301
287
&& match_matrix. find_best_match ( ) . is_subset_match ( )
@@ -309,33 +295,31 @@ pub mod internal {
309
295
}
310
296
311
297
fn explain_match ( & self , actual : & ContainerT ) -> MatchExplanation {
298
+ let actual_size = count_elements ( actual) ;
312
299
match self . requirements {
313
300
Requirements :: PerfectMatch => {
314
- if actual . size ( ) != N {
301
+ if actual_size != N {
315
302
return MatchExplanation :: create ( format ! (
316
303
"which has size {} (expected {})" ,
317
- actual. size( ) ,
318
- N
304
+ actual_size, N
319
305
) ) ;
320
306
}
321
307
}
322
308
323
309
Requirements :: Superset => {
324
- if actual . size ( ) < N {
310
+ if actual_size < N {
325
311
return MatchExplanation :: create ( format ! (
326
312
"which has size {} (expected at least {})" ,
327
- actual. size( ) ,
328
- N
313
+ actual_size, N
329
314
) ) ;
330
315
}
331
316
}
332
317
333
318
Requirements :: Subset => {
334
- if actual . size ( ) > N {
319
+ if actual_size > N {
335
320
return MatchExplanation :: create ( format ! (
336
321
"which has size {} (expected at most {})" ,
337
- actual. size( ) ,
338
- N
322
+ actual_size, N
339
323
) ) ;
340
324
}
341
325
}
@@ -379,14 +363,15 @@ pub mod internal {
379
363
struct MatchMatrix < const N : usize > ( Vec < [ MatcherResult ; N ] > ) ;
380
364
381
365
impl < const N : usize > MatchMatrix < N > {
382
- fn generate < ' a , T : Debug , ContainerT : Debug + HasSize > (
366
+ fn generate < ' a , T : Debug , ContainerT : Debug + ? Sized > (
383
367
actual : & ContainerT ,
384
368
expected : & [ & ' a dyn Matcher < T > ; N ] ,
385
369
) -> Self
386
370
where
387
371
for < ' b > & ' b ContainerT : IntoIterator < Item = & ' b T > ,
388
372
{
389
- let mut matrix = MatchMatrix ( vec ! [ [ MatcherResult :: DoesNotMatch ; N ] ; actual. size( ) ] ) ;
373
+ let mut matrix =
374
+ MatchMatrix ( vec ! [ [ MatcherResult :: DoesNotMatch ; N ] ; count_elements( actual) ] ) ;
390
375
for ( actual_idx, actual) in actual. into_iter ( ) . enumerate ( ) {
391
376
for ( expected_idx, expected) in expected. iter ( ) . enumerate ( ) {
392
377
matrix. 0 [ actual_idx] [ expected_idx] = expected. matches ( actual) ;
@@ -591,6 +576,25 @@ pub mod internal {
591
576
}
592
577
}
593
578
579
+ /// Counts the number of elements in `value`.
580
+ ///
581
+ /// This uses [`Iterator::size_hint`] when that function returns an
582
+ /// unambiguous answer, i.e., the upper bound exists and the lower and upper
583
+ /// bounds agree. Otherwise it iterates through `value` and counts the
584
+ /// elements.
585
+ fn count_elements < T , ContainerT : ?Sized > ( value : & ContainerT ) -> usize
586
+ where
587
+ for < ' b > & ' b ContainerT : IntoIterator < Item = & ' b T > ,
588
+ {
589
+ let iterator = value. into_iter ( ) ;
590
+ if let ( lower, Some ( higher) ) = iterator. size_hint ( ) {
591
+ if lower == higher {
592
+ return lower;
593
+ }
594
+ }
595
+ iterator. count ( )
596
+ }
597
+
594
598
/// The list of elements that do not match any element in the corresponding
595
599
/// set.
596
600
/// These lists are represented as fixed sized bit set to avoid
@@ -707,7 +711,7 @@ pub mod internal {
707
711
( 0 ..N ) . filter ( |expected_idx| !matched_expected. contains ( expected_idx) ) . collect ( )
708
712
}
709
713
710
- fn get_explanation < ' a , T : Debug , ContainerT : Debug > (
714
+ fn get_explanation < ' a , T : Debug , ContainerT : Debug + ? Sized > (
711
715
& self ,
712
716
actual : & ContainerT ,
713
717
expected : & [ & ' a dyn Matcher < T > ; N ] ,
@@ -773,6 +777,13 @@ mod tests {
773
777
verify_that ! ( value, unordered_elements_are![ eq( 1 ) , eq( 2 ) , eq( 3 ) ] )
774
778
}
775
779
780
+ #[ google_test]
781
+ fn unordered_elements_are_matches_slice ( ) -> Result < ( ) > {
782
+ let value = vec ! [ 1 , 2 , 3 ] ;
783
+ let slice = value. as_slice ( ) ;
784
+ verify_that ! ( * slice, unordered_elements_are![ eq( 1 ) , eq( 2 ) , eq( 3 ) ] )
785
+ }
786
+
776
787
#[ google_test]
777
788
fn unordered_elements_are_matches_vector_with_trailing_comma ( ) -> Result < ( ) > {
778
789
let value = vec ! [ 1 , 2 , 3 ] ;
0 commit comments