@@ -195,52 +195,120 @@ impl AsRef<str> for Feature {
195195 }
196196}
197197
198+ // main.rs passes Vec<&Feature> and tests in this module passes &Vec<Feature>.
199+ pub ( crate ) trait RefVecOrVecRef < ' a , T : ' a > : IntoIterator < Item = & ' a T > {
200+ fn get_ ( & self , i : usize ) -> Option < & ' a T > ;
201+ fn len_ ( & self ) -> usize ;
202+ }
203+ impl < ' a , T > RefVecOrVecRef < ' a , T > for Vec < & ' a T > {
204+ fn get_ ( & self , i : usize ) -> Option < & ' a T > {
205+ self . get ( i) . copied ( )
206+ }
207+ fn len_ ( & self ) -> usize {
208+ self . len ( )
209+ }
210+ }
211+ impl < ' a , T > RefVecOrVecRef < ' a , T > for & ' a Vec < T > {
212+ fn get_ ( & self , i : usize ) -> Option < & ' a T > {
213+ self . get ( i)
214+ }
215+ fn len_ ( & self ) -> usize {
216+ self . len ( )
217+ }
218+ }
219+
198220pub ( crate ) fn feature_powerset < ' a > (
199- features : impl IntoIterator < Item = & ' a Feature > ,
221+ features : impl RefVecOrVecRef < ' a , Feature > ,
200222 depth : Option < usize > ,
223+ random : Option < usize > ,
201224 at_least_one_of : & [ Feature ] ,
202225 mutually_exclusive_features : & [ Feature ] ,
203226 package_features : & BTreeMap < String , Vec < String > > ,
204227) -> Vec < Vec < & ' a Feature > > {
205228 let deps_map = feature_deps ( package_features) ;
206229 let at_least_one_of = at_least_one_of_for_package ( at_least_one_of, & deps_map) ;
207230
208- powerset ( features, depth)
209- . into_iter ( )
210- . skip ( 1 ) // The first element of a powerset is `[]` so it should be skipped.
211- . filter ( |fs| {
212- !fs. iter ( ) . any ( |f| {
213- f. as_group ( ) . iter ( ) . filter_map ( |f| deps_map. get ( & & * * f) ) . any ( |deps| {
214- fs. iter ( ) . any ( |f| f. as_group ( ) . iter ( ) . all ( |f| deps. contains ( & & * * f) ) )
231+ if let Some ( num_samples) = random {
232+ // TODO:
233+ // - If duplicates are found, they should be de-duplicated and regenerated.
234+ // - Same for filtered case.
235+ // - If the total number of possible combinations is less than num_samples,
236+ // then we should use normal powerset().
237+ filter_powerset (
238+ at_least_one_of,
239+ mutually_exclusive_features,
240+ package_features,
241+ & deps_map,
242+ ( 0 ..)
243+ . map ( |_| {
244+ let mut n = fastrand:: u64 ( ..) ;
245+ let mut v = vec ! [ ] ;
246+ let mut i = 0 ;
247+ while i < features. len_ ( ) {
248+ if n & 0b1 == 1 {
249+ v. push ( features. get_ ( i) . unwrap ( ) ) ;
250+ }
251+ i += 1 ;
252+ if i % 64 == 0 {
253+ n = fastrand:: u64 ( ..) ;
254+ } else {
255+ n >>= 1 ;
256+ }
257+ }
258+ v
215259 } )
216- } )
260+ . take ( num_samples) ,
261+ )
262+ } else {
263+ filter_powerset (
264+ at_least_one_of,
265+ mutually_exclusive_features,
266+ package_features,
267+ & deps_map,
268+ // The first element of a powerset is `[]` so it should be skipped.
269+ powerset ( features, depth) . into_iter ( ) . skip ( 1 ) ,
270+ )
271+ }
272+ }
273+
274+ fn filter_powerset < ' a > (
275+ at_least_one_of : Vec < BTreeSet < & str > > ,
276+ mutually_exclusive_features : & [ Feature ] ,
277+ package_features : & BTreeMap < String , Vec < String > > ,
278+ deps_map : & BTreeMap < & str , BTreeSet < & str > > ,
279+ iter : impl Iterator < Item = Vec < & ' a Feature > > ,
280+ ) -> Vec < Vec < & ' a Feature > > {
281+ iter. filter ( |fs| {
282+ !fs. iter ( ) . any ( |& f| {
283+ f. as_group ( )
284+ . iter ( )
285+ . filter_map ( |f| deps_map. get ( & & * * f) )
286+ . any ( |deps| fs. iter ( ) . any ( |f| f. as_group ( ) . iter ( ) . all ( |f| deps. contains ( & & * * f) ) ) )
217287 } )
218- . filter ( move |fs| {
219- // all() returns true if at_least_one_of is empty
220- at_least_one_of. iter ( ) . all ( |required_set| {
221- fs
222- . iter ( )
223- . flat_map ( |f| f. as_group ( ) )
224- . any ( |f| required_set. contains ( f. as_str ( ) ) )
225- } )
288+ } )
289+ . filter ( move |fs| {
290+ // all() returns true if at_least_one_of is empty
291+ at_least_one_of. iter ( ) . all ( |required_set| {
292+ fs. iter ( ) . flat_map ( |& f| f. as_group ( ) ) . any ( |f| required_set. contains ( f. as_str ( ) ) )
226293 } )
227- . filter ( move |fs| {
228- // Filter any feature set containing more than one feature from the same mutually
229- // exclusive group.
230- for group in mutually_exclusive_features {
231- let mut count = 0 ;
232- for f in fs . iter ( ) . flat_map ( |f| f . as_group ( ) ) {
233- if group . matches_recursive ( f , package_features ) {
234- count += 1 ;
235- if count > 1 {
236- return false ;
237- }
294+ } )
295+ . filter ( move |fs| {
296+ // Filter any feature set containing more than one feature from the same mutually
297+ // exclusive group.
298+ for group in mutually_exclusive_features {
299+ let mut count = 0 ;
300+ for f in fs . iter ( ) . flat_map ( |f| f . as_group ( ) ) {
301+ if group . matches_recursive ( f , package_features ) {
302+ count += 1 ;
303+ if count > 1 {
304+ return false ;
238305 }
239306 }
240307 }
241- true
242- } )
243- . collect ( )
308+ }
309+ true
310+ } )
311+ . collect ( )
244312}
245313
246314fn feature_deps ( map : & BTreeMap < String , Vec < String > > ) -> BTreeMap < & str , BTreeSet < & str > > {
@@ -357,22 +425,22 @@ mod tests {
357425 let map = map ! [ ( "a" , v![ ] ) , ( "b" , v![ "a" ] ) , ( "c" , v![ "b" ] ) , ( "d" , v![ "a" , "b" ] ) ] ;
358426
359427 let list = v ! [ "a" , "b" , "c" , "d" ] ;
360- let filtered = feature_powerset ( & list, None , & [ ] , & [ ] , & map) ;
428+ let filtered = feature_powerset ( & list, None , None , & [ ] , & [ ] , & map) ;
361429 assert_eq ! ( filtered, vec![ vec![ "a" ] , vec![ "b" ] , vec![ "c" ] , vec![ "d" ] , vec![ "c" , "d" ] ] ) ;
362430
363- let filtered = feature_powerset ( & list, None , & [ "a" . into ( ) ] , & [ ] , & map) ;
431+ let filtered = feature_powerset ( & list, None , None , & [ "a" . into ( ) ] , & [ ] , & map) ;
364432 assert_eq ! ( filtered, vec![ vec![ "a" ] , vec![ "b" ] , vec![ "c" ] , vec![ "d" ] , vec![ "c" , "d" ] ] ) ;
365433
366- let filtered = feature_powerset ( & list, None , & [ "c" . into ( ) ] , & [ ] , & map) ;
434+ let filtered = feature_powerset ( & list, None , None , & [ "c" . into ( ) ] , & [ ] , & map) ;
367435 assert_eq ! ( filtered, vec![ vec![ "c" ] , vec![ "c" , "d" ] ] ) ;
368436
369- let filtered = feature_powerset ( & list, None , & [ "a" . into ( ) , "c" . into ( ) ] , & [ ] , & map) ;
437+ let filtered = feature_powerset ( & list, None , None , & [ "a" . into ( ) , "c" . into ( ) ] , & [ ] , & map) ;
370438 assert_eq ! ( filtered, vec![ vec![ "c" ] , vec![ "c" , "d" ] ] ) ;
371439
372440 let map = map ! [ ( "tokio" , v![ ] ) , ( "async-std" , v![ ] ) , ( "a" , v![ ] ) , ( "b" , v![ "a" ] ) ] ;
373441 let list = v ! [ "a" , "b" , "tokio" , "async-std" ] ;
374442 let mutually_exclusive_features = [ Feature :: group ( [ "tokio" , "async-std" ] ) ] ;
375- let filtered = feature_powerset ( & list, None , & [ ] , & mutually_exclusive_features, & map) ;
443+ let filtered = feature_powerset ( & list, None , None , & [ ] , & mutually_exclusive_features, & map) ;
376444 assert_eq ! ( filtered, vec![
377445 vec![ "a" ] ,
378446 vec![ "b" ] ,
@@ -386,7 +454,7 @@ mod tests {
386454
387455 let mutually_exclusive_features =
388456 [ Feature :: group ( [ "tokio" , "a" ] ) , Feature :: group ( [ "tokio" , "async-std" ] ) ] ;
389- let filtered = feature_powerset ( & list, None , & [ ] , & mutually_exclusive_features, & map) ;
457+ let filtered = feature_powerset ( & list, None , None , & [ ] , & mutually_exclusive_features, & map) ;
390458 assert_eq ! ( filtered, vec![
391459 vec![ "a" ] ,
392460 vec![ "b" ] ,
@@ -399,7 +467,7 @@ mod tests {
399467 let map = map ! [ ( "a" , v![ ] ) , ( "b" , v![ "a" ] ) , ( "c" , v![ ] ) , ( "d" , v![ "b" ] ) ] ;
400468 let list = v ! [ "a" , "b" , "c" , "d" ] ;
401469 let mutually_exclusive_features = [ Feature :: group ( [ "a" , "c" ] ) ] ;
402- let filtered = feature_powerset ( & list, None , & [ ] , & mutually_exclusive_features, & map) ;
470+ let filtered = feature_powerset ( & list, None , None , & [ ] , & mutually_exclusive_features, & map) ;
403471 assert_eq ! ( filtered, vec![ vec![ "a" ] , vec![ "b" ] , vec![ "c" ] , vec![ "d" ] ] ) ;
404472 }
405473
@@ -433,7 +501,7 @@ mod tests {
433501 vec![ "b" , "c" , "d" ] ,
434502 vec![ "a" , "b" , "c" , "d" ] ,
435503 ] ) ;
436- let filtered = feature_powerset ( & list, None , & [ ] , & [ ] , & map) ;
504+ let filtered = feature_powerset ( & list, None , None , & [ ] , & [ ] , & map) ;
437505 assert_eq ! ( filtered, vec![ vec![ "a" ] , vec![ "b" ] , vec![ "c" ] , vec![ "d" ] , vec![ "c" , "d" ] ] ) ;
438506 }
439507
0 commit comments