]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/formats/renderer.rs
d4ba6726cd22a44f8f7bd7d8c5aaa31393f0d30d
[rust.git] / src / librustdoc / formats / renderer.rs
1 use std::sync::Arc;
2
3 use rustc_span::edition::Edition;
4
5 use crate::clean;
6 use crate::config::{RenderInfo, RenderOptions};
7 use crate::error::Error;
8 use crate::formats::cache::{Cache, CACHE_KEY};
9
10 pub trait FormatRenderer: Clone {
11     type Output: FormatRenderer;
12
13     /// Sets up any state required for the emulator. When this is called the cache has already been
14     /// populated.
15     fn init(
16         krate: clean::Crate,
17         options: RenderOptions,
18         renderinfo: RenderInfo,
19         edition: Edition,
20         cache: &mut Cache,
21     ) -> Result<(Self::Output, clean::Crate), Error>;
22
23     /// Renders a single non-module item. This means no recursive sub-item rendering is required.
24     fn item(&mut self, item: clean::Item, cache: &Cache) -> Result<(), Error>;
25
26     /// Renders a module (doesn't need to handle recursing into children).
27     fn mod_item_in(
28         &mut self,
29         item: &clean::Item,
30         item_name: &str,
31         cache: &Cache,
32     ) -> Result<(), Error>;
33
34     /// Runs after recursively rendering all sub-items of a module.
35     fn mod_item_out(&mut self, item_name: &str) -> Result<(), Error>;
36
37     /// Post processing hook for cleanup and dumping output to files.
38     fn after_krate(&mut self, krate: &clean::Crate, cache: &Cache) -> Result<(), Error>;
39
40     /// Called after everything else to write out errors.
41     fn after_run(&mut self, diag: &rustc_errors::Handler) -> Result<(), Error>;
42 }
43
44 #[derive(Clone)]
45 pub struct Renderer;
46
47 impl Renderer {
48     pub fn new() -> Renderer {
49         Renderer
50     }
51
52     /// Main method for rendering a crate.
53     pub fn run<T: FormatRenderer + Clone>(
54         self,
55         krate: clean::Crate,
56         options: RenderOptions,
57         renderinfo: RenderInfo,
58         diag: &rustc_errors::Handler,
59         edition: Edition,
60     ) -> Result<(), Error> {
61         let (krate, mut cache) = Cache::from_krate(
62             renderinfo.clone(),
63             options.document_private,
64             &options.extern_html_root_urls,
65             &options.output,
66             krate,
67         );
68
69         let (mut renderer, mut krate) = T::init(krate, options, renderinfo, edition, &mut cache)?;
70
71         let cache = Arc::new(cache);
72         // Freeze the cache now that the index has been built. Put an Arc into TLS for future
73         // parallelization opportunities
74         CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
75
76         let mut item = match krate.module.take() {
77             Some(i) => i,
78             None => return Ok(()),
79         };
80
81         item.name = Some(krate.name.clone());
82
83         // Render the crate documentation
84         let mut work = vec![(renderer.clone(), item)];
85
86         while let Some((mut cx, item)) = work.pop() {
87             if item.is_mod() {
88                 // modules are special because they add a namespace. We also need to
89                 // recurse into the items of the module as well.
90                 let name = item.name.as_ref().unwrap().to_string();
91                 if name.is_empty() {
92                     panic!("Unexpected module with empty name");
93                 }
94
95                 cx.mod_item_in(&item, &name, &cache)?;
96                 let module = match item.inner {
97                     clean::StrippedItem(box clean::ModuleItem(m)) | clean::ModuleItem(m) => m,
98                     _ => unreachable!(),
99                 };
100                 for it in module.items {
101                     info!("Adding {:?} to worklist", it.name);
102                     work.push((cx.clone(), it));
103                 }
104
105                 cx.mod_item_out(&name)?;
106             } else if item.name.is_some() {
107                 cx.item(item, &cache)?;
108             }
109         }
110
111         renderer.after_krate(&krate, &cache)?;
112         renderer.after_run(diag)
113     }
114 }