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.
3431 fn 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).
3744 fn 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