@@ -16,6 +16,9 @@ pub struct Level {
1616
1717 #[ getset( get_copy = "pub" ) ]
1818 independent : bool ,
19+
20+ #[ getset( get_copy = "pub" ) ]
21+ closed : bool ,
1922}
2023
2124#[ derive( Debug , Clone , PartialEq , Eq , new, Getters ) ]
@@ -57,7 +60,7 @@ impl Graph {
5760 . flat_map ( |m| m. conv :: < FxHashSet < _ > > ( ) . with_descendants ( self ) )
5861 . collect :: < FxHashSet < _ > > ( ) ;
5962
60- self . generate_module_permutations ( levels)
63+ self . generate_illegal_import_permutations_for_layers ( levels)
6164 . into_par_iter ( )
6265 . try_fold (
6366 Vec :: new,
@@ -81,15 +84,20 @@ impl Graph {
8184 )
8285 }
8386
84- fn generate_module_permutations ( & self , levels : & [ Level ] ) -> Vec < ( ModuleToken , ModuleToken ) > {
85- let mut permutations = vec ! [ ] ;
87+ /// Returns a set of tuples (importer, imported) describing the illegal
88+ /// import permutations for the given layers.
89+ fn generate_illegal_import_permutations_for_layers (
90+ & self ,
91+ levels : & [ Level ] ,
92+ ) -> FxHashSet < ( ModuleToken , ModuleToken ) > {
93+ let mut permutations = FxHashSet :: default ( ) ;
8694
8795 for ( index, level) in levels. iter ( ) . enumerate ( ) {
8896 for module in & level. layers {
8997 // Should not be imported by lower layers.
9098 for lower_level in & levels[ index + 1 ..] {
9199 for lower_module in & lower_level. layers {
92- permutations. push ( ( * lower_module, * module) ) ;
100+ permutations. insert ( ( * lower_module, * module) ) ;
93101 }
94102 }
95103
@@ -99,8 +107,19 @@ impl Graph {
99107 if sibling_module == module {
100108 continue ;
101109 }
102- permutations. push ( ( * module, * sibling_module) ) ;
110+ permutations. insert ( ( * module, * sibling_module) ) ;
111+ }
112+ }
113+
114+ // Should not be imported by higher layers if there is a closed layer inbetween.
115+ let mut closed = false ;
116+ for higher_level in levels[ ..index] . iter ( ) . rev ( ) {
117+ if closed {
118+ for higher_module in & higher_level. layers {
119+ permutations. insert ( ( * higher_module, * module) ) ;
120+ }
103121 }
122+ closed |= higher_level. closed ;
104123 }
105124 }
106125 }
@@ -208,3 +227,106 @@ impl Graph {
208227 )
209228 }
210229}
230+
231+ #[ cfg( test) ]
232+ mod tests {
233+ use super :: * ;
234+ use crate :: graph:: Graph ;
235+ use rustc_hash:: FxHashSet ;
236+
237+ #[ test]
238+ fn test_generate_module_permutations_simple_layers ( ) {
239+ let mut graph = Graph :: default ( ) ;
240+
241+ let top_module = graph. get_or_add_module ( "app.top" ) . token ;
242+ let middle_module = graph. get_or_add_module ( "app.middle" ) . token ;
243+ let bottom_module = graph. get_or_add_module ( "app.bottom" ) . token ;
244+
245+ let mut top_layer = FxHashSet :: default ( ) ;
246+ top_layer. insert ( top_module) ;
247+
248+ let mut middle_layer = FxHashSet :: default ( ) ;
249+ middle_layer. insert ( middle_module) ;
250+
251+ let mut bottom_layer = FxHashSet :: default ( ) ;
252+ bottom_layer. insert ( bottom_module) ;
253+
254+ let top_level = Level :: new ( top_layer, false , false ) ;
255+ let middle_level = Level :: new ( middle_layer, false , false ) ;
256+ let bottom_level = Level :: new ( bottom_layer, false , false ) ;
257+
258+ let levels = vec ! [ top_level, middle_level, bottom_level] ;
259+
260+ let permutations = graph. generate_illegal_import_permutations_for_layers ( & levels) ;
261+
262+ assert_eq ! (
263+ permutations,
264+ FxHashSet :: from_iter( [
265+ ( bottom_module, middle_module) ,
266+ ( bottom_module, top_module) ,
267+ ( middle_module, top_module) ,
268+ ] )
269+ ) ;
270+ }
271+
272+ #[ test]
273+ fn test_generate_module_permutations_independent_layer ( ) {
274+ let mut graph = Graph :: default ( ) ;
275+
276+ let module_a = graph. get_or_add_module ( "app.independent.a" ) . token ;
277+ let module_b = graph. get_or_add_module ( "app.independent.b" ) . token ;
278+
279+ let mut independent_layer = FxHashSet :: default ( ) ;
280+ independent_layer. insert ( module_a) ;
281+ independent_layer. insert ( module_b) ;
282+
283+ let independent_level = Level :: new ( independent_layer, true , false ) ;
284+
285+ let levels = vec ! [ independent_level] ;
286+
287+ let permutations = graph. generate_illegal_import_permutations_for_layers ( & levels) ;
288+
289+ assert_eq ! (
290+ permutations,
291+ FxHashSet :: from_iter( [ ( module_a, module_b) , ( module_b, module_a) , ] )
292+ ) ;
293+ }
294+
295+ #[ test]
296+ fn test_generate_module_permutations_closed_layer ( ) {
297+ let mut graph = Graph :: default ( ) ;
298+
299+ // Create three layers with the middle one closed
300+ let top_module = graph. get_or_add_module ( "app.top" ) . token ;
301+ let middle_module = graph. get_or_add_module ( "app.middle" ) . token ;
302+ let bottom_module = graph. get_or_add_module ( "app.bottom" ) . token ;
303+
304+ let mut top_layer = FxHashSet :: default ( ) ;
305+ top_layer. insert ( top_module) ;
306+
307+ let mut middle_layer = FxHashSet :: default ( ) ;
308+ middle_layer. insert ( middle_module) ;
309+
310+ let mut bottom_layer = FxHashSet :: default ( ) ;
311+ bottom_layer. insert ( bottom_module) ;
312+
313+ let top_level = Level :: new ( top_layer, false , false ) ;
314+ let middle_level = Level :: new ( middle_layer, false , true ) ; // Closed layer
315+ let bottom_level = Level :: new ( bottom_layer, false , false ) ;
316+
317+ let levels = vec ! [ top_level, middle_level, bottom_level] ;
318+
319+ let permutations = graph. generate_illegal_import_permutations_for_layers ( & levels) ;
320+
321+ assert_eq ! (
322+ permutations,
323+ FxHashSet :: from_iter( [
324+ ( bottom_module, middle_module) ,
325+ ( bottom_module, top_module) ,
326+ ( middle_module, top_module) ,
327+ // Top should not import Bottom due to closed middle layer
328+ ( top_module, bottom_module) ,
329+ ] )
330+ ) ;
331+ }
332+ }
0 commit comments