1
1
use rustc_middle:: ty:: TyCtxt ;
2
2
use rustc_span:: Symbol ;
3
3
4
- use crate :: clean;
4
+ use crate :: clean:: { self , Item } ;
5
5
use crate :: config:: RenderOptions ;
6
6
use crate :: error:: Error ;
7
7
use crate :: formats:: cache:: Cache ;
@@ -27,12 +27,19 @@ pub(crate) trait FormatRenderer<'tcx>: Sized {
27
27
tcx : TyCtxt < ' tcx > ,
28
28
) -> Result < ( Self , clean:: Crate ) , Error > ;
29
29
30
- /// Make a new renderer to render a child of the item currently being rendered.
31
- fn make_child_renderer ( & self ) -> Self ;
32
-
33
30
/// Renders a single non-module item. This means no recursive sub-item rendering is required.
34
31
fn item ( & mut self , item : clean:: Item ) -> Result < ( ) , Error > ;
35
32
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
+
36
43
/// Renders a module (should not handle recursing into children).
37
44
fn mod_item_in ( & mut self , item : & clean:: Item ) -> Result < ( ) , Error > ;
38
45
@@ -65,33 +72,66 @@ pub(crate) fn run_format<'tcx, T: FormatRenderer<'tcx>>(
65
72
return Ok ( ( ) ) ;
66
73
}
67
74
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 } ] ;
70
82
71
83
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
+ }
85
113
}
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
+ _ => { }
93
132
}
94
133
}
134
+
95
135
prof. extra_verbose_generic_activity ( "renderer_after_krate" , T :: descr ( ) )
96
136
. run ( || format_renderer. after_krate ( ) )
97
137
}
0 commit comments