11use  rustc_middle:: ty:: TyCtxt ; 
22use  rustc_span:: Symbol ; 
33
4- use  crate :: clean; 
4+ use  crate :: clean:: { self ,   Item } ; 
55use  crate :: config:: RenderOptions ; 
66use  crate :: error:: Error ; 
77use  crate :: formats:: cache:: Cache ; 
@@ -27,12 +27,19 @@ pub(crate) trait FormatRenderer<'tcx>: Sized {
2727        tcx :  TyCtxt < ' tcx > , 
2828    )  -> Result < ( Self ,  clean:: Crate ) ,  Error > ; 
2929
30-     /// Make a new renderer to render a child of the item currently being rendered. 
31- fn  make_child_renderer ( & self )  -> Self ; 
32- 
3330    /// Renders a single non-module item. This means no recursive sub-item rendering is required. 
3431fn  item ( & mut  self ,  item :  clean:: Item )  -> Result < ( ) ,  Error > ; 
3532
33+     /// Runs before rendering an item (not a module) 
34+ fn  before_item ( & mut  self ,  _item :  & clean:: Item )  -> Result < ( ) ,  Error >  { 
35+         Ok ( ( ) ) 
36+     } 
37+ 
38+     /// Runs after rendering an item (not a module) 
39+ fn  after_item ( & mut  self )  -> Result < ( ) ,  Error >  { 
40+         Ok ( ( ) ) 
41+     } 
42+ 
3643    /// Renders a module (should not handle recursing into children). 
3744fn  mod_item_in ( & mut  self ,  item :  & clean:: Item )  -> Result < ( ) ,  Error > ; 
3845
@@ -65,33 +72,66 @@ pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
6572        return  Ok ( ( ) ) ; 
6673    } 
6774
68-     // Render the crate documentation 
69-     let  mut  work = vec ! [ ( format_renderer. make_child_renderer( ) ,  krate. module) ] ; 
75+     enum  WorkUnit  { 
76+         Module  {  item :  Item ,  current_index :  usize  } , 
77+         Single ( Item ) , 
78+     } 
79+ 
80+     let  mut  work_units:  Vec < WorkUnit >  =
81+         vec ! [ WorkUnit :: Module  {  item:  krate. module,  current_index:  0  } ] ; 
7082
7183    let  unknown = Symbol :: intern ( "<unknown item>" ) ; 
72-     while  let  Some ( ( mut  cx,  item) )  = work. pop ( )  { 
73-         if  item. is_mod ( )  && T :: RUN_ON_MODULE  { 
74-             // modules are special because they add a namespace. We also need to 
75-             // recurse into the items of the module as well. 
76-             let  _timer =
77-                 prof. generic_activity_with_arg ( "render_mod_item" ,  item. name . unwrap ( ) . to_string ( ) ) ; 
78- 
79-             cx. mod_item_in ( & item) ?; 
80-             let  ( clean:: StrippedItem ( box clean:: ModuleItem ( module) )  | clean:: ModuleItem ( module) )  = * item. kind 
81-             else  {  unreachable ! ( )  } ; 
82-             for  it in  module. items  { 
83-                 debug ! ( "Adding {:?} to worklist" ,  it. name) ; 
84-                 work. push ( ( cx. make_child_renderer ( ) ,  it) ) ; 
84+     while  let  Some ( work_unit)  = work_units. pop ( )  { 
85+         match  work_unit { 
86+             WorkUnit :: Module  {  item,  current_index }  if  T :: RUN_ON_MODULE  => { 
87+                 let  ( clean:: StrippedItem ( box clean:: ModuleItem ( module) )  | clean:: ModuleItem ( module) )  = item. kind . as_ref ( ) 
88+                 else  {  unreachable ! ( )  } ; 
89+ 
90+                 if  current_index == 0  { 
91+                     // just enter the module 
92+                     format_renderer. mod_item_in ( & item) ?; 
93+                 } 
94+ 
95+                 if  current_index < module. items . len ( )  { 
96+                     // get the next item 
97+                     let  next_item = module. items [ current_index] . clone ( ) ; 
98+ 
99+                     // stay in the module 
100+                     work_units. push ( WorkUnit :: Module  {  item,  current_index :  current_index + 1  } ) ; 
101+ 
102+                     // push the next item 
103+                     if  next_item. is_mod ( )  { 
104+                         work_units. push ( WorkUnit :: Module  {  item :  next_item,  current_index :  0  } ) ; 
105+                     }  else  { 
106+                         work_units. push ( WorkUnit :: Single ( next_item) ) ; 
107+                     } 
108+                 }  else  { 
109+                     // the last item of the module has been rendered 
110+                     // -> exit the module 
111+                     format_renderer. mod_item_out ( ) ?; 
112+                 } 
85113            } 
86- 
87-             cx. mod_item_out ( ) ?; 
88-         // FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special 
89-         // cases. Use an explicit match instead. 
90-         }  else  if  item. name . is_some ( )  && !item. is_extern_crate ( )  { 
91-             prof. generic_activity_with_arg ( "render_item" ,  item. name . unwrap_or ( unknown) . as_str ( ) ) 
92-                 . run ( || cx. item ( item) ) ?; 
114+             // FIXME: checking `item.name.is_some()` is very implicit and leads to lots of special 
115+             // cases. Use an explicit match instead. 
116+             WorkUnit :: Module  {  item,  .. }  | WorkUnit :: Single ( item) 
117+                 if  item. name . is_some ( )  && !item. is_extern_crate ( )  =>
118+             { 
119+                 // render the item 
120+                 prof. generic_activity_with_arg ( 
121+                     "render_item" , 
122+                     item. name . unwrap_or ( unknown) . as_str ( ) , 
123+                 ) 
124+                 . run ( || { 
125+                     format_renderer. before_item ( & item) ?; 
126+                     let  result = format_renderer. item ( item) ?; 
127+                     format_renderer. after_item ( ) ?; 
128+                     Ok ( result) 
129+                 } ) ?; 
130+             } 
131+             _ => { } 
93132        } 
94133    } 
134+ 
95135    prof. extra_verbose_generic_activity ( "renderer_after_krate" ,  T :: descr ( ) ) 
96136        . run ( || format_renderer. after_krate ( ) ) 
97137} 
0 commit comments