diff options
| author | bors <bors@rust-lang.org> | 2019-09-08 02:12:24 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-09-08 02:12:24 +0000 |
| commit | 4a8ccdbeeb346e80417bd6b5c9cb7d62e225659d (patch) | |
| tree | c27ad2da51d49a096e50adacd33c067e320f61df | |
| parent | f7b05af814f02681d8973438df4ed5792f581841 (diff) | |
| parent | 02c5c5cb597c873dd152f3ec8a6b74b5f28ccf36 (diff) | |
| download | rust-4a8ccdbeeb346e80417bd6b5c9cb7d62e225659d.tar.gz rust-4a8ccdbeeb346e80417bd6b5c9cb7d62e225659d.zip | |
Auto merge of #64044 - Mark-Simulacrum:rustdoc-clean-2, r=GuillaumeGomez
Rustdoc: formatting to buffers This should be reviewed commit-by-commit. I've not attempted to fully flesh out what the end state of this PR could look like yet as I wanted to get it up for some early feedback (I already think this has some wins, too, so we could land it as-is). The primary idea with `Buffer` is that it internally tracks whether we're printing to HTML or text, and the goal is that eventually instead of branch on `fmt.alternate()` anywhere, we'd call a helper like `buf.nbsp()` which would either return ` ` or ` ` depending on the target we're printing to. Obviously, that's not included in this PR, in part because it was already getting quite big.
| -rw-r--r-- | src/librustdoc/html/format.rs | 110 | ||||
| -rw-r--r-- | src/librustdoc/html/layout.rs | 35 | ||||
| -rw-r--r-- | src/librustdoc/html/render.rs | 1585 | ||||
| -rw-r--r-- | src/librustdoc/html/sources.rs | 50 |
4 files changed, 864 insertions, 916 deletions
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 313734e3fdd..dcd32192ff3 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,6 +18,100 @@ use crate::clean::{self, PrimitiveType}; use crate::html::item_type::ItemType; use crate::html::render::{self, cache, CURRENT_DEPTH}; +pub trait Print { + fn print(self, buffer: &mut Buffer); +} + +impl<F> Print for F + where F: FnOnce(&mut Buffer), +{ + fn print(self, buffer: &mut Buffer) { + (self)(buffer) + } +} + +impl Print for String { + fn print(self, buffer: &mut Buffer) { + buffer.write_str(&self); + } +} + +impl Print for &'_ str { + fn print(self, buffer: &mut Buffer) { + buffer.write_str(self); + } +} + +#[derive(Debug, Clone)] +pub struct Buffer { + for_html: bool, + buffer: String, +} + +impl Buffer { + crate fn empty_from(v: &Buffer) -> Buffer { + Buffer { + for_html: v.for_html, + buffer: String::new(), + } + } + + crate fn html() -> Buffer { + Buffer { + for_html: true, + buffer: String::new(), + } + } + + crate fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + + crate fn into_inner(self) -> String { + self.buffer + } + + crate fn insert_str(&mut self, idx: usize, s: &str) { + self.buffer.insert_str(idx, s); + } + + crate fn push_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + + // Intended for consumption by write! and writeln! (std::fmt) but without + // the fmt::Result return type imposed by fmt::Write (and avoiding the trait + // import). + crate fn write_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + + // Intended for consumption by write! and writeln! (std::fmt) but without + // the fmt::Result return type imposed by fmt::Write (and avoiding the trait + // import). + crate fn write_fmt(&mut self, v: fmt::Arguments<'_>) { + use fmt::Write; + self.buffer.write_fmt(v).unwrap(); + } + + crate fn to_display<T: Print>(mut self, t: T) -> String { + t.print(&mut self); + self.into_inner() + } + + crate fn with_formatter<T: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result>(&mut self, t: T) { + self.from_display(display_fn(move |f| (t)(f))); + } + + crate fn from_display<T: std::fmt::Display>(&mut self, t: T) { + if self.for_html { + write!(self, "{}", t); + } else { + write!(self, "{:#}", t); + } + } +} + /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) #[derive(Copy, Clone)] @@ -200,11 +294,11 @@ impl<'a> fmt::Display for WhereClause<'a> { } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { clause.push_str(&format!("{}: {}", - lifetime, - bounds.iter() - .map(|b| b.to_string()) - .collect::<Vec<_>>() - .join(" + "))); + lifetime, + bounds.iter() + .map(|b| b.to_string()) + .collect::<Vec<_>>() + .join(" + "))); } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { @@ -778,9 +872,9 @@ impl fmt::Display for clean::Impl { // The difference from above is that trait is not hyperlinked. pub fn fmt_impl_for_trait_page(i: &clean::Impl, - f: &mut fmt::Formatter<'_>, - use_absolute: bool) -> fmt::Result { - fmt_impl(i, f, false, use_absolute) + f: &mut Buffer, + use_absolute: bool) { + f.with_formatter(|f| fmt_impl(i, f, false, use_absolute)) } impl fmt::Display for clean::Arguments { diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index ae0bd1aafa8..56074f4ab11 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -1,9 +1,8 @@ -use std::fmt; -use std::io; use std::path::PathBuf; use crate::externalfiles::ExternalHtml; use crate::html::render::SlashChecker; +use crate::html::format::{Buffer, Print}; #[derive(Clone)] pub struct Layout { @@ -11,6 +10,12 @@ pub struct Layout { pub favicon: String, pub external_html: ExternalHtml, pub krate: String, + /// The given user css file which allow to customize the generated + /// documentation theme. + pub css_file_extension: Option<PathBuf>, + /// If false, the `select` element to have search filtering by crates on rendered docs + /// won't be generated. + pub generate_search_filter: bool, } pub struct Page<'a> { @@ -25,19 +30,15 @@ pub struct Page<'a> { pub static_extra_scripts: &'a [&'a str], } -pub fn render<T: fmt::Display, S: fmt::Display>( - dst: &mut dyn io::Write, +pub fn render<T: Print, S: Print>( layout: &Layout, page: &Page<'_>, - sidebar: &S, - t: &T, - css_file_extension: bool, + sidebar: S, + t: T, themes: &[PathBuf], - generate_search_filter: bool, -) -> io::Result<()> { +) -> String { let static_root_path = page.static_root_path.unwrap_or(page.root_path); - write!(dst, -"<!DOCTYPE html>\ + format!("<!DOCTYPE html>\ <html lang=\"en\">\ <head>\ <meta charset=\"utf-8\">\ @@ -164,7 +165,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>( <script defer src=\"{root_path}search-index{suffix}.js\"></script>\ </body>\ </html>", - css_extension = if css_file_extension { + css_extension = if layout.css_file_extension.is_some() { format!("<link rel=\"stylesheet\" \ type=\"text/css\" \ href=\"{static_root_path}theme{suffix}.css\">", @@ -173,7 +174,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>( } else { String::new() }, - content = *t, + content = Buffer::html().to_display(t), static_root_path = static_root_path, root_path = page.root_path, css_class = page.css_class, @@ -207,7 +208,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>( in_header = layout.external_html.in_header, before_content = layout.external_html.before_content, after_content = layout.external_html.after_content, - sidebar = *sidebar, + sidebar = Buffer::html().to_display(sidebar), krate = layout.krate, themes = themes.iter() .filter_map(|t| t.file_stem()) @@ -228,7 +229,7 @@ pub fn render<T: fmt::Display, S: fmt::Display>( root_path=page.root_path, extra_script=e) }).collect::<String>(), - filter_crates=if generate_search_filter { + filter_crates=if layout.generate_search_filter { "<select id=\"crate-search\">\ <option value=\"All crates\">All crates</option>\ </select>" @@ -238,9 +239,9 @@ pub fn render<T: fmt::Display, S: fmt::Display>( ) } -pub fn redirect(dst: &mut dyn io::Write, url: &str) -> io::Result<()> { +pub fn redirect(url: &str) -> String { // <script> triggers a redirect before refresh, so this is fine. - write!(dst, + format!( r##"<!DOCTYPE html> <html lang="en"> <head> diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 0e046b8cd44..9846073cad4 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -65,7 +65,7 @@ use crate::docfs::{DocFS, ErrorStorage, PathError}; use crate::doctree; use crate::fold::DocFolder; use crate::html::escape::Escape; -use crate::html::format::{AsyncSpace, ConstnessSpace}; +use crate::html::format::{Buffer, AsyncSpace, ConstnessSpace}; use crate::html::format::{GenericBounds, WhereClause, href, AbiSpace, DefaultSpace}; use crate::html::format::{VisSpace, Function, UnsafetySpace, MutableSpace}; use crate::html::format::fmt_impl_for_trait_page; @@ -192,9 +192,6 @@ crate struct SharedContext { /// The base-URL of the issue tracker for when an item has been tagged with /// an issue number. pub issue_tracker_base_url: Option<String>, - /// The given user css file which allow to customize the generated - /// documentation theme. - pub css_file_extension: Option<PathBuf>, /// The directories that have already been created in this doc run. Used to reduce the number /// of spurious `create_dir_all` calls. pub created_dirs: RefCell<FxHashSet<PathBuf>>, @@ -209,9 +206,6 @@ crate struct SharedContext { /// Optional path string to be used to load static files on output pages. If not set, uses /// combinations of `../` to reach the documentation root. pub static_root_path: Option<String>, - /// If false, the `select` element to have search filtering by crates on rendered docs - /// won't be generated. - pub generate_search_filter: bool, /// Option disabled by default to generate files used by RLS and some other tools. pub generate_redirect_pages: bool, /// The fs handle we are working with. @@ -387,14 +381,6 @@ pub struct RenderInfo { // Helper structs for rendering items/sidebars and carrying along contextual // information -#[derive(Copy, Clone)] -struct Item<'a> { - cx: &'a Context, - item: &'a clean::Item, -} - -struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, } - /// Struct representing one entry in the JS search index. These are all emitted /// by hand to a large JS file at the end of cache-creation. #[derive(Debug)] @@ -545,14 +531,14 @@ pub fn run(mut krate: clean::Crate, favicon: String::new(), external_html, krate: krate.name.clone(), + css_file_extension: extension_css, + generate_search_filter, }, - css_file_extension: extension_css, created_dirs: Default::default(), sort_modules_alphabetically, themes, resource_suffix, static_root_path, - generate_search_filter, generate_redirect_pages, fs: DocFS::new(&errors), }; @@ -932,7 +918,7 @@ themePicker.onblur = handleThemeButtonsBlur; options.enable_minification)?; } - if let Some(ref css) = cx.shared.css_file_extension { + if let Some(ref css) = cx.shared.layout.css_file_extension { let out = cx.dst.join(&format!("theme{}.css", cx.shared.resource_suffix)); let buffer = try_err!(fs::read_to_string(css), css); if !options.enable_minification { @@ -1031,12 +1017,12 @@ themePicker.onblur = handleThemeButtonsBlur; } all_aliases.push(format!("ALIASES[\"{}\"] = {{{}}};", krate.name, output)); all_aliases.sort(); - let mut v = Vec::new(); - try_err!(writeln!(&mut v, "var ALIASES = {{}};"), &dst); + let mut v = Buffer::html(); + writeln!(&mut v, "var ALIASES = {{}};"); for aliases in &all_aliases { - try_err!(writeln!(&mut v, "{}", aliases), &dst); + writeln!(&mut v, "{}", aliases); } - cx.shared.fs.write(&dst, &v)?; + cx.shared.fs.write(&dst, v.into_inner().into_bytes())?; } use std::ffi::OsString; @@ -1120,12 +1106,9 @@ themePicker.onblur = handleThemeButtonsBlur; &krate.name, hierarchy.to_json_string())); all_sources.sort(); - let mut v = Vec::new(); - try_err!(writeln!(&mut v, - "var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();", - all_sources.join("\n")), - &dst); - cx.shared.fs.write(&dst, &v)?; + let v = format!("var N = null;var sourcesIndex = {{}};\n{}\ncreateSourceSidebar();\n", + all_sources.join("\n")); + cx.shared.fs.write(&dst, v.as_bytes())?; } // Update the search index @@ -1140,14 +1123,11 @@ themePicker.onblur = handleThemeButtonsBlur; // with rustdoc running in parallel. all_indexes.sort(); { - let mut v = Vec::new(); - try_err!(writeln!(&mut v, "var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={{}};"), &dst); - try_err!(write_minify_replacer( - &mut v, + let mut v = String::from("var N=null,E=\"\",T=\"t\",U=\"u\",searchIndex={};\n"); + v.push_str(&minify_replacer( &format!("{}\n{}", variables.join(""), all_indexes.join("\n")), - options.enable_minification), - &dst); - try_err!(write!(&mut v, "initSearch(searchIndex);addSearchOptions(searchIndex);"), &dst); + options.enable_minification)); + v.push_str("initSearch(searchIndex);addSearchOptions(searchIndex);"); cx.shared.fs.write(&dst, &v)?; } if options.enable_index_page { @@ -1185,13 +1165,10 @@ themePicker.onblur = handleThemeButtonsBlur; SlashChecker(s), s) }) .collect::<String>()); - let mut v = Vec::new(); - try_err!(layout::render(&mut v, &cx.shared.layout, - &page, &(""), &content, - cx.shared.css_file_extension.is_some(), - &cx.shared.themes, - cx.shared.generate_search_filter), &dst); - cx.shared.fs.write(&dst, &v)?; + let v = layout::render(&cx.shared.layout, + &page, "", content, + &cx.shared.themes); + cx.shared.fs.write(&dst, v.as_bytes())?; } } @@ -1256,19 +1233,18 @@ themePicker.onblur = handleThemeButtonsBlur; // identically even with rustdoc running in parallel. all_implementors.sort(); - let mut v = Vec::new(); - try_err!(writeln!(&mut v, "(function() {{var implementors = {{}};"), &mydst); + let mut v = String::from("(function() {var implementors = {};\n"); for implementor in &all_implementors { - try_err!(writeln!(&mut v, "{}", *implementor), &mydst); + writeln!(v, "{}", *implementor).unwrap(); } - try_err!(writeln!(&mut v, "{}", r" + v.push_str(r" if (window.register_implementors) { window.register_implementors(implementors); } else { window.pending_implementors = implementors; } - "), &mydst); - try_err!(writeln!(&mut v, r"}})()"), &mydst); + "); + v.push_str("})()"); cx.shared.fs.write(&mydst, &v)?; } Ok(()) @@ -1288,68 +1264,65 @@ fn write_minify(fs:&DocFS, dst: PathBuf, contents: &str, enable_minification: bo } } -fn write_minify_replacer<W: Write>( - dst: &mut W, +fn minify_replacer( contents: &str, enable_minification: bool, -) -> io::Result<()> { +) -> String { use minifier::js::{simple_minify, Keyword, ReservedChar, Token, Tokens}; if enable_minification { - writeln!(dst, "{}", - { - let tokens: Tokens<'_> = simple_minify(contents) - .into_iter() - .filter(|(f, next)| { - // We keep backlines. - minifier::js::clean_token_except(f, next, &|c: &Token<'_>| { - c.get_char() != Some(ReservedChar::Backline) - }) - }) - .map(|(f, _)| { - minifier::js::replace_token_with(f, &|t: &Token<'_>| { - match *t { - Token::Keyword(Keyword::Null) => Some(Token::Other("N")), - Token::String(s) => { - let s = &s[1..s.len() -1]; // The quotes are included - if s.is_empty() { - Some(Token::Other("E")) - } else if s == "t" { - Some(Token::Other("T")) - } else if s == "u" { - Some(Token::Other("U")) - } else { - None - } - } - _ => None, - } - }) - }) - .collect::<Vec<_>>() - .into(); - tokens.apply(|f| { - // We add a backline after the newly created variables. - minifier::js::aggregate_strings_into_array_with_separation_filter( - f, - "R", - Token::Char(ReservedChar::Backline), - // This closure prevents crates' names from being aggregated. - // - // The point here is to check if the string is preceded by '[' and - // "searchIndex". If so, it means this is a crate name and that it - // shouldn't be aggregated. - |tokens, pos| { - pos < 2 || - !tokens[pos - 1].eq_char(ReservedChar::OpenBracket) || - tokens[pos - 2].get_other() != Some("searchIndex") + let tokens: Tokens<'_> = simple_minify(contents) + .into_iter() + .filter(|(f, next)| { + // We keep backlines. + minifier::js::clean_token_except(f, next, &|c: &Token<'_>| { + c.get_char() != Some(ReservedChar::Backline) + }) + }) + .map(|(f, _)| { + minifier::js::replace_token_with(f, &|t: &Token<'_>| { + match *t { + Token::Keyword(Keyword::Null) => Some(Token::Other("N")), + Token::String(s) => { + let s = &s[1..s.len() -1]; // The quotes are included + if s.is_empty() { + Some(Token::Other("E")) + } else if s == "t" { + Some(Token::Other("T")) + } else if s == "u" { + Some(Token::Other("U")) + } else { + None } - ) - }) - .to_string() + } + _ => None, + } }) + }) + .collect::<Vec<_>>() + .into(); + let o = tokens.apply(|f| { + // We add a backline after the newly created variables. + minifier::js::aggregate_strings_into_array_with_separation_filter( + f, + "R", + Token::Char(ReservedChar::Backline), + // This closure prevents crates' names from being aggregated. + // + // The point here is to check if the string is preceded by '[' and + // "searchIndex". If so, it means this is a crate name and that it + // shouldn't be aggregated. + |tokens, pos| { + pos < 2 || + !tokens[pos - 1].eq_char(ReservedChar::OpenBracket) || + tokens[pos - 2].get_other() != Some("searchIndex") + } + ) + }) + .to_string(); + format!("{}\n", o) } else { - writeln!(dst, "{}", contents) + format!("{}\n", contents) } } @@ -1778,8 +1751,7 @@ impl AllTypes { } } -fn print_entries(f: &mut fmt::Formatter<'_>, e: &FxHashSet<ItemEntry>, title: &str, - class: &str) -> fmt::Result { +fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &str) { if !e.is_empty() { let mut e: Vec<&ItemEntry> = e.iter().collect(); e.sort(); @@ -1787,90 +1759,71 @@ fn print_entries(f: &mut fmt::Formatter<'_>, e: &FxHashSet<ItemEntry>, title: &s title, Escape(title), class, - e.iter().map(|s| format!("<li>{}</li>", s)).collect::<String>())?; + e.iter().map(|s| format!("<li>{}</li>", s)).collect::<String>()); } - Ok(()) } -impl fmt::Display for AllTypes { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl AllTypes { + fn print(self, f: &mut Buffer) { write!(f, -"<h1 class='fqn'>\ - <span class='out-of-band'>\ - <span id='render-detail'>\ - <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" title=\"collapse all docs\">\ - [<span class='inner'>−</span>]\ - </a>\ - </span> - </span> - <span class='in-band'>List of all items</span>\ -</h1>")?; - print_entries(f, &self.structs, "Structs", "structs")?; - print_entries(f, &self.enums, "Enums", "enums")?; - print_entries(f, &self.unions, "Unions", "unions")?; - print_entries(f, &self.primitives, "Primitives", "primitives")?; - print_entries(f, &self.traits, "Traits", "traits")?; - print_entries(f, &self.macros, "Macros", "macros")?; - print_entries(f, &self.attributes, "Attribute Macros", "attributes")?; - print_entries(f, &self.derives, "Derive Macros", "derives")?; - print_entries(f, &self.functions, "Functions", "functions")?; - print_entries(f, &self.typedefs, "Typedefs", "typedefs")?; - print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases")?; - print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types")?; - print_entries(f, &self.statics, "Statics", "statics")?; + "<h1 class='fqn'>\ + <span class='out-of-band'>\ + <span id='render-detail'>\ + <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" title=\"collapse all docs\">\ + [<span class='inner'>−</span>]\ + </a>\ + </span> + </span> + <span class='in-band'>List of all items</span>\ + </h1>"); + print_entries(f, &self.structs, "Structs", "structs"); + print_entries(f, &self.enums, "Enums", "enums"); + print_entries(f, &self.unions, "Unions", "unions"); + print_entries(f, &self.primitives, "Primitives", "primitives"); + print_entries(f, &self.traits, "Traits", "traits"); + print_entries(f, &self.macros, "Macros", "macros"); + print_entries(f, &self.attributes, "Attribute Macros", "attributes"); + print_entries(f, &self.derives, "Derive Macros", "derives"); + print_entries(f, &self.functions, "Functions", "functions"); + print_entries(f, &self.typedefs, "Typedefs", "typedefs"); + print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases"); + print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types"); + print_entries(f, &self.statics, "Statics", "statics"); print_entries(f, &self.constants, "Constants", "constants") } } -#[derive(Debug)] -struct Settings<'a> { +fn settings(root_path: &str, suffix: &str) -> String { // (id, explanation, default value) - settings: Vec<(&'static str, &'static str, bool)>, - root_path: &'a str, - suffix: &'a str, -} - -impl<'a> Settings<'a> { - pub fn new(root_path: &'a str, suffix: &'a str) -> Settings<'a> { - Settings { - settings: vec![ - ("item-declarations", "Auto-hide item declarations.", true), - ("item-attributes", "Auto-hide item attributes.", true), - ("trait-implementations", "Auto-hide trait implementations documentation", - true), - ("method-docs", "Auto-hide item methods' documentation", false), - ("go-to-only-result", "Directly go to item in search if there is only one result", - false), - ("line-numbers", "Show line numbers on code examples", false), - ], - root_path, - suffix, - } - } -} - -impl<'a> fmt::Display for Settings<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, + let settings = [ + ("item-declarations", "Auto-hide item declarations.", true), + ("item-attributes", "Auto-hide item attributes.", true), + ("trait-implementations", "Auto-hide trait implementations documentation", + true), + ("method-docs", "Auto-hide item methods' documentation", false), + ("go-to-only-result", "Directly go to item in search if there is only one result", + false), + ("line-numbers", "Show line numbers on code examples", false), + ]; + format!( "<h1 class='fqn'>\ - <span class='in-band'>Rustdoc settings</span>\ + <span class='in-band'>Rustdoc settings</span>\ </h1>\ <div class='settings'>{}</div>\ <script src='{}settings{}.js'></script>", - self.settings.iter() - .map(|(id, text, enabled)| { - format!("<div class='setting-line'>\ - <label class='toggle'>\ - <input type='checkbox' id='{}' {}>\ - <span class='slider'></span>\ - </label>\ - <div>{}</div>\ - </div>", id, if *enabled { " checked" } else { "" }, text) - }) - .collect::<String>(), - self.root_path, - self.suffix) - } + settings.iter() + .map(|(id, text, enabled)| { + format!("<div class='setting-line'>\ + <label class='toggle'>\ + <input type='checkbox' id='{}' {}>\ + <span class='slider'></span>\ + </label>\ + <div>{}</div>\ + </div>", id, if *enabled { " checked" } else { "" }, text) + }) + .collect::<String>(), + root_path, + suffix) } impl Context { @@ -1939,18 +1892,12 @@ impl Context { } else { String::new() }; - let mut v = Vec::new(); - try_err!(layout::render(&mut v, &self.shared.layout, - &page, &sidebar, &all, - self.shared.css_file_extension.is_some(), - &self.shared.themes, - self.shared.generate_search_filter), - &final_file); - self.shared.fs.write(&final_file, &v)?; + let v = layout::render(&self.shared.layout, + &page, sidebar, |buf: &mut Buffer| all.print(buf), + &self.shared.themes); + self.shared.fs.write(&final_file, v.as_bytes())?; // Generating settings page. - let settings = Settings::new(self.shared.static_root_path.as_deref().unwrap_or("./"), - &self.shared.resource_suffix); page.title = "Rustdoc settings"; page.description = "Settings of Rustdoc"; page.root_path = "./"; @@ -1958,24 +1905,21 @@ impl Context { let mut themes = self.shared.themes.clone(); let sidebar = "<p class='location'>Settings</p><div class='sidebar-elems'></div>"; themes.push(PathBuf::from("settings.css")); - let layout = self.shared.layout.clone(); - let mut v = Vec::new(); - try_err!(layout::render(&mut v, &layout, - &page, &sidebar, &settings, - self.shared.css_file_extension.is_some(), - &themes, - self.shared.generate_search_filter), - &settings_file); - self.shared.fs.write(&settings_file, &v)?; + let v = layout::render( + &self.shared.layout, + &page, sidebar, settings( + self.shared.static_root_path.as_deref().unwrap_or("./"), + &self.shared.resource_suffix + ), + &themes); + self.shared.fs.write(&settings_file, v.as_bytes())?; Ok(()) } fn render_item(&self, - writer: &mut dyn io::Write, it: &clean::Item, - pushname: bool) - -> io::Result<()> { + pushname: bool) -> String { // A little unfortunate that this is done like this, but it sure // does make formatting *a lot* nicer. CURRENT_DEPTH.with(|slot| { @@ -2022,12 +1966,10 @@ impl Context { } if !self.render_redirect_pages { - layout::render(writer, &self.shared.layout, &page, - &Sidebar{ cx: self, item: it }, - &Item{ cx: self, item: it }, - self.shared.css_file_extension.is_some(), - &self.shared.themes, - self.shared.generate_search_filter)?; + layout::render(&self.shared.layout, &page, + |buf: &mut _| print_sidebar(self, it, buf), + |buf: &mut _| print_item(self, it, buf), + &self.shared.themes) } else { let mut url = self.root_path(); if let Some(&(ref names, ty)) = cache().paths.get(&it.def_id) { @@ -2036,10 +1978,11 @@ impl Context { url.push_str("/"); } url.push_str(&item_path(ty, names.last().unwrap())); - layout::redirect(writer, &url)?; + layout::redirect(&url) + } else { + String::new() } } - Ok(()) } /// Non-parallelized version of rendering an item. This will take the input @@ -2075,13 +2018,12 @@ impl Context { info!("Recursing into {}", self.dst.display()); - let mut buf = Vec::new(); - self.render_item(&mut buf, &item, false).unwrap(); + let buf = self.render_item(&item, false); // buf will be empty if the module is stripped and there is no redirect for it if !buf.is_empty() { self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join("index.html"); - scx.fs.write(&joint_dst, buf)?; + scx.fs.write(&joint_dst, buf.as_bytes())?; } let m = match item.inner { @@ -2094,9 +2036,7 @@ impl Context { if !self.render_redirect_pages { let items = self.build_sidebar_items(&m); let js_dst = self.dst.join("sidebar-items.js"); - let mut v = Vec::new(); - try_err!(write!(&mut v, "initSidebarItems({});", - as_json(&items)), &js_dst); + let v = format!("initSidebarItems({});", as_json(&items)); scx.fs.write(&js_dst, &v)?; } @@ -2110,8 +2050,7 @@ impl Context { self.dst = prev; self.current.pop().unwrap(); } else if item.name.is_some() { - let mut buf = Vec::new(); - self.render_item(&mut buf, &item, true).unwrap(); + let buf = self.render_item(&item, true); // buf will be empty if the item is stripped and there is no redirect for it if !buf.is_empty() { let name = item.name.as_ref().unwrap(); @@ -2119,7 +2058,7 @@ impl Context { let file_name = &item_path(item_type, name); self.shared.ensure_dir(&self.dst)?; let joint_dst = self.dst.join(file_name); - self.shared.fs.write(&joint_dst, buf)?; + self.shared.fs.write(&joint_dst, buf.as_bytes())?; if !self.render_redirect_pages { all.append(full_path(self, &item), &item_type); @@ -2129,18 +2068,16 @@ impl Context { // URL for the page. let redir_name = format!("{}.{}.html", name, item_type.name_space()); let redir_dst = self.dst.join(redir_name); - let mut v = Vec::new(); - try_err!(layout::redirect(&mut v, file_name), &redir_dst); - self.shared.fs.write(&redir_dst, &v)?; + let v = layout::redirect(file_name); + self.shared.fs.write(&redir_dst, v.as_bytes())?; } // If the item is a macro, redirect from the old macro URL (with !) // to the new one (without). if item_type == ItemType::Macro { let redir_name = format!("{}.{}!.html", item_type, name); let redir_dst = self.dst.join(redir_name); - let mut v = Vec::new(); - try_err!(layout::redirect(&mut v, file_name), &redir_dst); - self.shared.fs.write(&redir_dst, &v)?; + let v = layout::redirect(file_name); + self.shared.fs.write(&redir_dst, v.as_bytes())?; } } } @@ -2172,7 +2109,7 @@ impl Context { } } -impl<'a> Item<'a> { +impl Context { /// Generates a url appropriate for an `href` attribute back to the source of /// this item. /// @@ -2182,26 +2119,26 @@ impl<'a> Item<'a> { /// If `None` is returned, then a source link couldn't be generated. This /// may happen, for example, with externally inlined items where the source /// of their crate documentation isn't known. - fn src_href(&self) -> Option<String> { - let mut root = self.cx.root_path(); + fn src_href(&self, item: &clean::Item) -> Option<String> { + let mut root = self.root_path(); let cache = cache(); let mut path = String::new(); // We can safely ignore macros from other libraries - let file = match self.item.source.filename { + let file = match item.source.filename { FileName::Real(ref path) => path, _ => return None, }; - let (krate, path) = if self.item.def_id.is_local() { - if let Some(path) = self.cx.shared.local_sources.get(file) { - (&self.cx.shared.layout.krate, path) + let (krate, path) = if item.def_id.is_local() { + if let Some(path) = self.shared.local_sources.get(file) { + (&self.shared.layout.krate, path) } else { return None; } } else { - let (krate, src_root) = match *cache.extern_locations.get(&self.item.def_id.krate)? { + let (krate, src_root) = match *cache.extern_locations.get(&item.def_id.krate)? { (ref name, ref src, Local) => (name, src), (ref name, ref src, Remote(ref s)) => { root = s.to_string(); @@ -2221,10 +2158,10 @@ impl<'a> Item<'a> { (krate, &path) }; - let lines = if self.item.source.loline == self.item.source.hiline { - self.item.source.loline.to_string() + let lines = if item.source.loline == item.source.hiline { + item.source.loline.to_string() } else { - format!("{}-{}", self.item.source.loline, self.item.source.hiline) + format!("{}-{}", item.source.loline, item.source.hiline) }; Some(format!("{root}src/{krate}/{path}#{lines}", root = Escape(&root), @@ -2234,114 +2171,113 @@ impl<'a> Item<'a> { } } -fn wrap_into_docblock<F>(w: &mut fmt::Formatter<'_>, - f: F) -> fmt::Result -where F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result { - write!(w, "<div class=\"docblock type-decl hidden-by-usual-hider\">")?; - f(w)?; +fn wrap_into_docblock<F>(w: &mut Buffer, f: F) + where F: FnOnce(&mut Buffer) +{ + write!(w, "<div class=\"docblock type-decl hidden-by-usual-hider\">"); + f(w); write!(w, "</div>") } -impl<'a> fmt::Display for Item<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - debug_assert!(!self.item.is_stripped()); - // Write the breadcrumb trail header for the top - write!(fmt, "<h1 class='fqn'><span class='out-of-band'>")?; - if let Some(version) = self.item.stable_since() { - write!(fmt, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", - version)?; - } - write!(fmt, - "<span id='render-detail'>\ - <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \ - title=\"collapse all docs\">\ - [<span class='inner'>−</span>]\ - </a>\ - </span>")?; - - // Write `src` tag - // - // When this item is part of a `pub use` in a downstream crate, the - // [src] link in the downstream documentation will actually come back to - // this page, and this link will be auto-clicked. The `id` attribute is - // used to find the link to auto-click. - if self.cx.shared.include_sources && !self.item.is_primitive() { - if let Some(l) = self.src_href() { - write!(fmt, "<a class='srclink' href='{}' title='{}'>[src]</a>", - l, "goto source code")?; - } - } - - write!(fmt, "</span>")?; // out-of-band - write!(fmt, "<span class='in-band'>")?; - match self.item.inner { - clean::ModuleItem(ref m) => if m.is_crate { - write!(fmt, "Crate ")?; - } else { - write!(fmt, "Module ")?; - }, - clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => write!(fmt, "Function ")?, - clean::TraitItem(..) => write!(fmt, "Trait ")?, - clean::StructItem(..) => write!(fmt, "Struct ")?, - clean::UnionItem(..) => write!(fmt, "Union ")?, - clean::EnumItem(..) => write!(fmt, "Enum ")?, - clean::TypedefItem(..) => write!(fmt, "Type Definition ")?, - clean::MacroItem(..) => write!(fmt, "Macro ")?, - clean::ProcMacroItem(ref mac) => match mac.kind { - MacroKind::Bang => write!(fmt, "Macro ")?, - MacroKind::Attr => write!(fmt, "Attribute Macro ")?, - MacroKind::Derive => write!(fmt, "Derive Macro ")?, - } - clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, - clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?, - clean::ConstantItem(..) => write!(fmt, "Constant ")?, - clean::ForeignTypeItem => write!(fmt, "Foreign Type ")?, - clean::KeywordItem(..) => write!(fmt, "Keyword ")?, - clean::OpaqueTyItem(..) => write!(fmt, "Opaque Type ")?, - clean::TraitAliasItem(..) => write!(fmt, "Trait Alias ")?, - _ => { - // We don't generate pages for any other type. - unreachable!(); - } +fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer) { + debug_assert!(!item.is_stripped()); + // Write the breadcrumb trail header for the top + write!(buf, "<h1 class='fqn'><span class='out-of-band'>"); + if let Some(version) = item.stable_since() { + write!(buf, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", + version); + } + write!(buf, + "<span id='render-detail'>\ + <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \ + title=\"collapse all docs\">\ + [<span class='inner'>−</span>]\ + </a>\ + </span>"); + + // Write `src` tag + // + // When this item is part of a `pub use` in a downstream crate, the + // [src] link in the downstream documentation will actually come back to + // this page, and this link will be auto-clicked. The `id` attribute is + // used to find the link to auto-click. + if cx.shared.include_sources && !item.is_primitive() { + if let Some(l) = cx.src_href(item) { + write!(buf, "<a class='srclink' href='{}' title='{}'>[src]</a>", + l, "goto source code"); + } + } + + write!(buf, "</span>"); // out-of-band + write!(buf, "<span class='in-band'>"); + let name = match item.inner { + clean::ModuleItem(ref m) => if m.is_crate { + "Crate " + } else { + "Module " + }, + clean::FunctionItem(..) | clean::ForeignFunctionItem(..) => "Function ", + clean::TraitItem(..) => "Trait ", + clean::StructItem(..) => "Struct ", + clean::UnionItem(..) => "Union ", + clean::EnumItem(..) => "Enum ", + clean::TypedefItem(..) => "Type Definition ", + clean::MacroItem(..) => "Macro ", + clean::ProcMacroItem(ref mac) => match mac.kind { + MacroKind::Bang => "Macro ", + MacroKind::Attr => "Attribute Macro ", + MacroKind::Derive => "Derive Macro ", + } + clean::PrimitiveItem(..) => "Primitive Type ", + clean::StaticItem(..) | clean::ForeignStaticItem(..) => "Static ", + clean::ConstantItem(..) => "Constant ", + clean::ForeignTypeItem => "Foreign Type ", + clean::KeywordItem(..) => "Keyword ", + clean::OpaqueTyItem(..) => "Opaque Type ", + clean::TraitAliasItem(..) => "Trait Alias ", + _ => { + // We don't generate pages for any other type. + unreachable!(); } - if !self.item.is_primitive() && !self.item.is_keyword() { - let cur = &self.cx.current; - let amt = if self.item.is_mod() { cur.len() - 1 } else { cur.len() }; - for (i, component) in cur.iter().enumerate().take(amt) { - write!(fmt, "<a href='{}index.html'>{}</a>::<wbr>", - "../".repeat(cur.len() - i - 1), - component)?; - } + }; + buf.write_str(name); + if !item.is_primitive() && !item.is_keyword() { + let cur = &cx.current; + let amt = if item.is_mod() { cur.len() - 1 } else { cur.len() }; + for (i, component) in cur.iter().enumerate().take(amt) { + write!(buf, "<a href='{}index.html'>{}</a>::<wbr>", + "../".repeat(cur.len() - i - 1), + component); } - write!(fmt, "<a class=\"{}\" href=''>{}</a>", - self.item.type_(), self.item.name.as_ref().unwrap())?; - - write!(fmt, "</span></h1>")?; // in-band - - match self.item.inner { - clean::ModuleItem(ref m) => - item_module(fmt, self.cx, self.item, &m.items), - clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => - item_function(fmt, self.cx, self.item, f), - clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t), - clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s), - clean::UnionItem(ref s) => item_union(fmt, self.cx, self.item, s), - clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e), - clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t), - clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m), - clean::ProcMacroItem(ref m) => item_proc_macro(fmt, self.cx, self.item, m), - clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p), - clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => - item_static(fmt, self.cx, self.item, i), - clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c), - clean::ForeignTypeItem => item_foreign_type(fmt, self.cx, self.item), - clean::KeywordItem(ref k) => item_keyword(fmt, self.cx, self.item, k), - clean::OpaqueTyItem(ref e, _) => item_opaque_ty(fmt, self.cx, self.item, e), - clean::TraitAliasItem(ref ta) => item_trait_alias(fmt, self.cx, self.item, ta), - _ => { - // We don't generate pages for any other type. - unreachable!(); - } + } + write!(buf, "<a class=\"{}\" href=''>{}</a>", + item.type_(), item.name.as_ref().unwrap()); + + write!(buf, "</span></h1>"); // in-band + + match item.inner { + clean::ModuleItem(ref m) => + item_module(buf, cx, item, &m.items), + clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) => + item_function(buf, cx, item, f), + clean::TraitItem(ref t) => item_trait(buf, cx, item, t), + clean::StructItem(ref s) => item_struct(buf, cx, item, s), + clean::UnionItem(ref s) => item_union(buf, cx, item, s), + clean::EnumItem(ref e) => item_enum(buf, cx, item, e), + clean::TypedefItem(ref t, _) => item_typedef(buf, cx, item, t), + clean::MacroItem(ref m) => item_macro(buf, cx, item, m), + clean::ProcMacroItem(ref m) => item_proc_macro(buf, cx, item, m), + clean::PrimitiveItem(ref p) => item_primitive(buf, cx, item, p), + clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) => + item_static(buf, cx, item, i), + clean::ConstantItem(ref c) => item_constant(buf, cx, item, c), + clean::ForeignTypeItem => item_foreign_type(buf, cx, item), + clean::KeywordItem(ref k) => item_keyword(buf, cx, item, k), + clean::OpaqueTyItem(ref e, _) => item_opaque_ty(buf, cx, item, e), + clean::TraitAliasItem(ref ta) => item_trait_alias(buf, cx, item, ta), + _ => { + // We don't generate pages for any other type. + unreachable!(); } } } @@ -2395,24 +2331,23 @@ fn shorten(s: String) -> String { } } -fn document(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item) -> fmt::Result { +fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_stability(w, cx, item, false)?; - document_full(w, item, cx, "", false)?; - Ok(()) + document_stability(w, cx, item, false); + document_full(w, item, cx, "", false); } /// Render md_text as markdown. fn render_markdown( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, md_text: &str, links: Vec<(String, String)>, prefix: &str, is_hidden: bool, -) -> fmt::Result { +) { let mut ids = cx.id_map.borrow_mut(); write!(w, "<div class='docblock{}'>{}{}</div>", if is_hidden { " hidden" } else { "" }, @@ -2422,13 +2357,13 @@ fn render_markdown( } fn document_short( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, item: &clean::Item, link: AssocItemLink<'_>, prefix: &str, is_hidden: bool, -) -> fmt::Result { +) { if let Some(s) = item.doc_value() { let markdown = if s.contains('\n') { format!("{} [Read more]({})", @@ -2436,46 +2371,41 @@ fn document_short( } else { plain_summary_line(Some(s)) }; - render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden)?; + render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden); } else if !prefix.is_empty() { write!(w, "<div class='docblock{}'>{}</div>", if is_hidden { " hidden" } else { "" }, - prefix)?; + prefix); } - Ok(()) } -fn document_full(w: &mut fmt::Formatter<'_>, item: &clean::Item, - cx: &Context, prefix: &str, is_hidden: bool) -> fmt::Result { +fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, is_hidden: bool) { if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) { debug!("Doc block: =====\n{}\n=====", s); - render_markdown(w, cx, &*s, item.links(), prefix, is_hidden)?; + render_markdown(w, cx, &*s, item.links(), prefix, is_hidden); } else if !prefix.is_empty() { write!(w, "<div class='docblock{}'>{}</div>", if is_hidden { " hidden" } else { "" }, - prefix)?; + prefix); } - Ok(()) } -fn document_stability(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item, - is_hidden: bool) -> fmt::Result { +fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) { let stabilities = short_stability(item, cx); if !stabilities.is_empty() { - write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" })?; + write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" }); for stability in stabilities { - write!(w, "{}", stability)?; + write!(w, "{}", stability); } - write!(w, "</div>")?; + write!(w, "</div>"); } - Ok(()) } fn document_non_exhaustive_header(item: &clean::Item) -> &str { if item.is_non_exhaustive() { " (Non-exhaustive)" } else { "" } } -fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fmt::Result { +fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { if item.is_non_exhaustive() { write!(w, "<div class='docblock non-exhaustive non-exhaustive-{}'>", { if item.is_struct() { @@ -2487,31 +2417,29 @@ fn document_non_exhaustive(w: &mut fmt::Formatter<'_>, item: &clean::Item) -> fm } else { "type" } - })?; + }); if item.is_struct() { write!(w, "Non-exhaustive structs could have additional fields added in future. \ Therefore, non-exhaustive structs cannot be constructed in external crates \ using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \ matched against without a wildcard <code>..</code>; and \ - struct update syntax will not work.")?; + struct update syntax will not work."); } else if item.is_enum() { write!(w, "Non-exhaustive enums could have additional variants added in future. \ Therefore, when matching against variants of non-exhaustive enums, an \ - extra wildcard arm must be added to account for any future variants.")?; + extra wildcard arm must be added to account for any future variants."); } else if item.is_variant() { write!(w, "Non-exhaustive enum variants could have additional fields added in future. \ Therefore, non-exhaustive enum variants cannot be constructed in external \ - crates and cannot be matched against.")?; + crates and cannot be matched against."); } else { write!(w, "This type will require a wildcard arm in any match statements or \ - constructors.")?; + constructors."); } - write!(w, "</div>")?; + write!(w, "</div>"); } - - Ok(()) } fn name_key(name: &str) -> (&str, u64, usize) { @@ -2535,9 +2463,8 @@ fn name_key(name: &str) -> (&str, u64, usize) { } } -fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, - item: &clean::Item, items: &[clean::Item]) -> fmt::Result { - document(w, cx, item)?; +fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { + document(w, cx, item); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>(); @@ -2628,13 +2555,13 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, curty = myty; } else if myty != curty { if curty.is_some() { - write!(w, "</table>")?; + write!(w, "</table>"); } curty = myty; let (short, name) = item_ty_to_strs(&myty.unwrap()); write!(w, "<h2 id='{id}' class='section-header'>\ <a href=\"#{id}\">{name}</a></h2>\n<table>", - id = cx.derive_id(short.to_owned()), name = name)?; + id = cx.derive_id(short.to_owned()), name = name); } match myitem.inner { @@ -2646,20 +2573,20 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, write!(w, "<tr><td><code>{}extern crate {} as {};", VisSpace(&myitem.visibility), anchor(myitem.def_id, src), - name)? + name) } None => { write!(w, "<tr><td><code>{}extern crate {};", VisSpace(&myitem.visibility), - anchor(myitem.def_id, name))? + anchor(myitem.def_id, name)) } } - write!(w, "</code></td></tr>")?; + write!(w, "</code></td></tr>"); } clean::ImportItem(ref import) => { write!(w, "<tr><td><code>{}{}</code></td></tr>", - VisSpace(&myitem.visibility), *import)?; + VisSpace(&myitem.visibility), *import); } _ => { @@ -2704,15 +2631,14 @@ fn item_module(w: &mut fmt::Formatter<'_>, cx: &Context, }) .collect::<Vec<_>>() .join(" "), - )?; + ); } } } if curty.is_some() { - write!(w, "</table>")?; + write!(w, "</table>"); } - Ok(()) } /// Render the stability and deprecation tags that are displayed in the item's summary at the @@ -2861,33 +2787,30 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { stability } -fn item_constant(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - c: &clean::Constant) -> fmt::Result { - write!(w, "<pre class='rust const'>")?; - render_attributes(w, it, false)?; +fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Constant) { + write!(w, "<pre class='rust const'>"); + render_attributes(w, it, false); write!(w, "{vis}const \ {name}: {typ}</pre>", vis = VisSpace(&it.visibility), name = it.name.as_ref().unwrap(), - typ = c.type_)?; + typ = c.type_); document(w, cx, it) } -fn item_static(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - s: &clean::Static) -> fmt::Result { - write!(w, "<pre class='rust static'>")?; - render_attributes(w, it, false)?; +fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) { + write!(w, "<pre class='rust static'>"); + render_attributes(w, it, false); write!(w, "{vis}static {mutability}\ {name}: {typ}</pre>", vis = VisSpace(&it.visibility), mutability = MutableSpace(s.mutability), name = it.name.as_ref().unwrap(), - typ = s.type_)?; + typ = s.type_); document(w, cx, it) } -fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - f: &clean::Function) -> fmt::Result { +fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) { let header_len = format!( "{}{}{}{}{:#}fn {}{:#}", VisSpace(&it.visibility), @@ -2898,8 +2821,8 @@ fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, it.name.as_ref().unwrap(), f.generics ).len(); - write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)?)?; - render_attributes(w, it, false)?; + write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)); + render_attributes(w, it, false); write!(w, "{vis}{constness}{unsafety}{asyncness}{abi}fn \ {name}{generics}{decl}{where_clause}</pre>", @@ -2916,12 +2839,12 @@ fn item_function(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, header_len, indent: 0, asyncness: f.header.asyncness, - })?; + }); document(w, cx, it) } -fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<'_>, - implementor_dups: &FxHashMap<&str, (DefId, bool)>) -> fmt::Result { +fn render_implementor(cx: &Context, implementor: &Impl, w: &mut Buffer, + implementor_dups: &FxHashMap<&str, (DefId, bool)>) { // If there's already another implementor that has the same abbridged name, use the // full path, for example in `std::iter::ExactSizeIterator` let use_absolute = match implementor.inner_impl().for_ { @@ -2933,20 +2856,18 @@ fn render_implementor(cx: &Context, implementor: &Impl, w: &mut fmt::Formatter<' _ => false, }; render_impl(w, cx, implementor, AssocItemLink::Anchor(None), RenderMode::Normal, - implementor.impl_item.stable_since(), false, Some(use_absolute), false, false)?; - Ok(()) + implementor.impl_item.stable_since(), false, Some(use_absolute), false, false); } -fn render_impls(cx: &Context, w: &mut fmt::Formatter<'_>, +fn render_impls(cx: &Context, w: &mut Buffer, traits: &[&&Impl], - containing_item: &clean::Item) -> fmt::Result { + containing_item: &clean::Item) { for i in traits { let did = i.trait_did().unwrap(); let assoc_link = AssocItemLink::GotoSource(did, &i.inner_impl().provided_trait_methods); render_impl(w, cx, i, assoc_link, - RenderMode::Normal, containing_item.stable_since(), true, None, false, true)?; + RenderMode::Normal, containing_item.stable_since(), true, None, false, true); } - Ok(()) } fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool) -> String { @@ -2974,11 +2895,11 @@ fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl) -> Ordering { } fn item_trait( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, -) -> fmt::Result { +) { let bounds = bounds(&t.bounds, false); let types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::<Vec<_>>(); @@ -2987,146 +2908,144 @@ fn item_trait( // Output the trait definition wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust trait'>")?; - render_attributes(w, it, true)?; + write!(w, "<pre class='rust trait'>"); + render_attributes(w, it, true); write!(w, "{}{}{}trait {}{}{}", VisSpace(&it.visibility), UnsafetySpace(t.unsafety), if t.is_auto { "auto " } else { "" }, it.name.as_ref().unwrap(), t.generics, - bounds)?; + bounds); if !t.generics.where_predicates.is_empty() { - write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true })?; + write!(w, "{}", WhereClause { gens: &t.generics, indent: 0, end_newline: true }); } else { - write!(w, " ")?; + write!(w, " "); } if t.items.is_empty() { - write!(w, "{{ }}")?; + write!(w, "{{ }}"); } else { // FIXME: we should be using a derived_id for the Anchors here - write!(w, "{{\n")?; + write!(w, "{{\n"); for t in &types { - render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; - write!(w, ";\n")?; + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait); + write!(w, ";\n"); } if !types.is_empty() && !consts.is_empty() { - w.write_str("\n")?; + w.write_str("\n"); } for t in &consts { - render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; - write!(w, ";\n")?; + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait); + write!(w, ";\n"); } if !consts.is_empty() && !required.is_empty() { - w.write_str("\n")?; + w.write_str("\n"); } for (pos, m) in required.iter().enumerate() { - render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; - write!(w, ";\n")?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); + write!(w, ";\n"); if pos < required.len() - 1 { - write!(w, "<div class='item-spacer'></div>")?; + write!(w, "<div class='item-spacer'></div>"); } } if !required.is_empty() && !provided.is_empty() { - w.write_str("\n")?; + w.write_str("\n"); } for (pos, m) in provided.iter().enumerate() { - render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait); match m.inner { clean::MethodItem(ref inner) if !inner.generics.where_predicates.is_empty() => { - write!(w, ",\n {{ ... }}\n")?; + write!(w, ",\n {{ ... }}\n"); }, _ => { - write!(w, " {{ ... }}\n")?; + write!(w, " {{ ... }}\n"); }, } if pos < provided.len() - 1 { - write!(w, "<div class='item-spacer'></div>")?; + write!(w, "<div class='item-spacer'></div>"); } } - write!(w, "}}")?; + write!(w, "}}"); } write!(w, "</pre>") - })?; + }); // Trait documentation - document(w, cx, it)?; + document(w, cx, it); fn write_small_section_header( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, id: &str, title: &str, extra_content: &str, - ) -> fmt::Result { + ) { write!(w, " <h2 id='{0}' class='small-section-header'>\ {1}<a href='#{0}' class='anchor'></a>\ </h2>{2}", id, title, extra_content) } - fn write_loading_content(w: &mut fmt::Formatter<'_>, extra_content: &str) -> fmt::Result { + fn write_loading_content(w: &mut Buffer, extra_content: &str) { write!(w, "{}<span class='loading-content'>Loading content...</span>", extra_content) } - fn trait_item(w: &mut fmt::Formatter<'_>, cx: &Context, m: &clean::Item, t: &clean::Item) - -> fmt::Result { + fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) { let name = m.name.as_ref().unwrap(); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "<h3 id='{id}' class='method'>{extra}<code id='{ns_id}'>", - extra = render_spotlight_traits(m)?, + extra = render_spotlight_traits(m), id = id, - ns_id = ns_id)?; - render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?; - write!(w, "</code>")?; - render_stability_since(w, m, t)?; - write!(w, "</h3>")?; - document(w, cx, m)?; - Ok(()) + ns_id = ns_id); + render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); + write!(w, "</code>"); + render_stability_since(w, m, t); + write!(w, "</h3>"); + document(w, cx, m); } if !types.is_empty() { write_small_section_header(w, "associated-types", "Associated Types", - "<div class='methods'>")?; + "<div class='methods'>"); for t in &types { - trait_item(w, cx, *t, it)?; + trait_item(w, cx, *t, it); } - write_loading_content(w, "</div>")?; + write_loading_content(w, "</div>"); } if !consts.is_empty() { write_small_section_header(w, "associated-const", "Associated Constants", - "<div class='methods'>")?; + "<div class='methods'>"); for t in &consts { - trait_item(w, cx, *t, it)?; + trait_item(w, cx, *t, it); } - write_loading_content(w, "</div>")?; + write_loading_content(w, "</div>"); } // Output the documentation for each function individually if !required.is_empty() { write_small_section_header(w, "required-methods", "Required methods", - "<div class='methods'>")?; + "<div class='methods'>"); for m in &required { - trait_item(w, cx, *m, it)?; + trait_item(w, cx, *m, it); } - write_loading_content(w, "</div>")?; + write_loading_content(w, "</div>"); } if !provided.is_empty() { write_small_section_header(w, "provided-methods", "Provided methods", - "<div class='methods'>")?; + "<div class='methods'>"); for m in &provided { - trait_item(w, cx, *m, it)?; + trait_item(w, cx, *m, it); } - write_loading_content(w, "</div>")?; + write_loading_content(w, "</div>"); } // If there are methods directly on this trait object, render them here. - render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?; + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All); let cache = cache(); @@ -3165,7 +3084,7 @@ fn item_trait( concrete.sort_by(compare_impl); if !foreign.is_empty() { - write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", "")?; + write_small_section_header(w, "foreign-impls", "Implementations on Foreign Types", ""); for implementor in foreign { let assoc_link = AssocItemLink::GotoSource( @@ -3174,44 +3093,44 @@ fn item_trait( ); render_impl(w, cx, &implementor, assoc_link, RenderMode::Normal, implementor.impl_item.stable_since(), false, - None, true, false)?; + None, true, false); } - write_loading_content(w, "")?; + write_loading_content(w, ""); } write_small_section_header(w, "implementors", "Implementors", - "<div class='item-list' id='implementors-list'>")?; + "<div class='item-list' id='implementors-list'>"); for implementor in concrete { - render_implementor(cx, implementor, w, &implementor_dups)?; + render_implementor(cx, implementor, w, &implementor_dups); } - write_loading_content(w, "</div>")?; + write_loading_content(w, "</div>"); if t.auto { write_small_section_header(w, "synthetic-implementors", "Auto implementors", - "<div class='item-list' id='synthetic-implementors-list'>")?; + "<div class='item-list' id='synthetic-implementors-list'>"); for implementor in synthetic { synthetic_types.extend( collect_paths_for_type(implementor.inner_impl().for_.clone()) ); - render_implementor(cx, implementor, w, &implementor_dups)?; + render_implementor(cx, implementor, w, &implementor_dups); } - write_loading_content(w, "</div>")?; + write_loading_content(w, "</div>"); } } else { // even without any implementations to write in, we still want the heading and list, so the // implementors javascript file pulled in below has somewhere to write the impls into write_small_section_header(w, "implementors", "Implementors", - "<div class='item-list' id='implementors-list'>")?; - write_loading_content(w, "</div>")?; + "<div class='item-list' id='implementors-list'>"); + write_loading_content(w, "</div>"); if t.auto { write_small_section_header(w, "synthetic-implementors", "Auto implementors", - "<div class='item-list' id='synthetic-implementors-list'>")?; - write_loading_content(w, "</div>")?; + "<div class='item-list' id='synthetic-implementors-list'>"); + write_loading_content(w, "</div>"); } } write!(w, r#"<script type="text/javascript">window.inlined_types=new Set({});</script>"#, - as_json(&synthetic_types))?; + as_json(&synthetic_types)); write!(w, r#"<script type="text/javascript" async src="{root_path}/implementors/{path}/{ty}.{name}.js"> @@ -3224,8 +3143,7 @@ fn item_trait( path[..path.len() - 1].join("/") }, ty = it.type_().css_class(), - name = *it.name.as_ref().unwrap())?; - Ok(()) + name = *it.name.as_ref().unwrap()); } fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>) -> String { @@ -3247,70 +3165,60 @@ fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>) -> String { } } -fn assoc_const(w: &mut fmt::Formatter<'_>, +fn assoc_const(w: &mut Buffer, it: &clean::Item, ty: &clean::Type, _default: Option<&String>, link: AssocItemLink<'_>, - extra: &str) -> fmt::Result { + extra: &str) { write!(w, "{}{}const <a href='{}' class=\"constant\"><b>{}</b></a>: {}", extra, VisSpace(&it.visibility), naive_assoc_href(it, link), it.name.as_ref().unwrap(), - ty)?; - Ok(()) + ty); } -fn assoc_type<W: fmt::Write>(w: &mut W, it: &clean::Item, - bounds: &[clean::GenericBound], - default: Option<&clean::Type>, - link: AssocItemLink<'_>, - extra: &str) -> fmt::Result { +fn assoc_type(w: &mut Buffer, it: &clean::Item, + bounds: &[clean::GenericBound], + default: Option<&clean::Type>, + link: AssocItemLink<'_>, + extra: &str) { write!(w, "{}type <a href='{}' class=\"type\">{}</a>", extra, naive_assoc_href(it, link), - it.name.as_ref().unwrap())?; + it.name.as_ref().unwrap()); if !bounds.is_empty() { - write!(w, ": {}", GenericBounds(bounds))? + write!(w, ": {}", GenericBounds(bounds)) } if let Some(default) = default { - write!(w, " = {}", default)?; + write!(w, " = {}", default) } - Ok(()) } -fn render_stability_since_raw<'a, T: fmt::Write>( - w: &mut T, - ver: Option<&'a str>, - containing_ver: Option<&'a str>, -) -> fmt::Result { +fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: Option<&str>) { if let Some(v) = ver { if containing_ver != ver && v.len() > 0 { - write!(w, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", v)? + write!(w, "<span class='since' title='Stable since Rust version {0}'>{0}</span>", v) } } - Ok(()) } -fn render_stability_since(w: &mut fmt::Formatter<'_>, - item: &clean::Item, - containing_item: &clean::Item) -> fmt::Result { +fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) { render_stability_since_raw(w, item.stable_since(), containing_item.stable_since()) } -fn render_assoc_item(w: &mut fmt::Formatter<'_>, +fn render_assoc_item(w: &mut Buffer, item: &clean::Item, link: AssocItemLink<'_>, - parent: ItemType) -> fmt::Result { - fn method(w: &mut fmt::Formatter<'_>, + parent: ItemType) { + fn method(w: &mut Buffer, meth: &clean::Item, header: hir::FnHeader, g: &clean::Generics, d: &clean::FnDecl, link: AssocItemLink<'_>, - parent: ItemType) - -> fmt::Result { + parent: ItemType) { let name = meth.name.as_ref().unwrap(); let anchor = format!("#{}.{}", meth.type_(), name); let href = match link { @@ -3345,7 +3253,7 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>, } else { (0, true) }; - render_attributes(w, meth, false)?; + render_attributes(w, meth, false); write!(w, "{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\ {generics}{decl}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, @@ -3371,7 +3279,7 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>, }) } match item.inner { - clean::StrippedItem(..) => Ok(()), + clean::StrippedItem(..) => {}, clean::TyMethodItem(ref m) => { method(w, item, m.header, &m.generics, &m.decl, link, parent) } @@ -3390,22 +3298,21 @@ fn render_assoc_item(w: &mut fmt::Formatter<'_>, } } -fn item_struct(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - s: &clean::Struct) -> fmt::Result { +fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct) { wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust struct'>")?; - render_attributes(w, it, true)?; + write!(w, "<pre class='rust struct'>"); + render_attributes(w, it, true); render_struct(w, it, Some(&s.generics), s.struct_type, &s.fields, "", - true)?; + true); write!(w, "</pre>") - })?; + }); - document(w, cx, it)?; + document(w, cx, it); let mut fields = s.fields.iter().filter_map(|f| { match f.inner { clean::StructFieldItem(ref ty) => Some((f, ty)), @@ -3416,8 +3323,8 @@ fn item_struct(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, if fields.peek().is_some() { write!(w, "<h2 id='fields' class='fields small-section-header'> Fields{}<a href='#fields' class='anchor'></a></h2>", - document_non_exhaustive_header(it))?; - document_non_exhaustive(w, it)?; + document_non_exhaustive_header(it)); + document_non_exhaustive(w, it); for (field, ty) in fields { let id = cx.derive_id(format!("{}.{}", ItemType::StructField, @@ -3433,29 +3340,28 @@ fn item_struct(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, id = id, ns_id = ns_id, name = field.name.as_ref().unwrap(), - ty = ty)?; - document(w, cx, field)?; + ty = ty); + document(w, cx, field); } } } render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_union(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - s: &clean::Union) -> fmt::Result { +fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union) { wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust union'>")?; - render_attributes(w, it, true)?; + write!(w, "<pre class='rust union'>"); + render_attributes(w, it, true); render_union(w, it, Some(&s.generics), &s.fields, "", - true)?; + true); write!(w, "</pre>") - })?; + }); - document(w, cx, it)?; + document(w, cx, it); let mut fields = s.fields.iter().filter_map(|f| { match f.inner { clean::StructFieldItem(ref ty) => Some((f, ty)), @@ -3464,7 +3370,7 @@ fn item_union(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, }).peekable(); if fields.peek().is_some() { write!(w, "<h2 id='fields' class='fields small-section-header'> - Fields<a href='#fields' class='anchor'></a></h2>")?; + Fields<a href='#fields' class='anchor'></a></h2>"); for (field, ty) in fields { let name = field.name.as_ref().expect("union field name"); let id = format!("{}.{}", ItemType::StructField, name); @@ -3475,47 +3381,46 @@ fn item_union(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, id = id, name = name, shortty = ItemType::StructField, - ty = ty)?; + ty = ty); if let Some(stability_class) = field.stability_class() { write!(w, "<span class='stab {stab}'></span>", - stab = stability_class)?; + stab = stability_class); } - document(w, cx, field)?; + document(w, cx, field); } } render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - e: &clean::Enum) -> fmt::Result { +fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum) { wrap_into_docblock(w, |w| { - write!(w, "<pre class='rust enum'>")?; - render_attributes(w, it, true)?; + write!(w, "<pre class='rust enum'>"); + render_attributes(w, it, true); write!(w, "{}enum {}{}{}", VisSpace(&it.visibility), it.name.as_ref().unwrap(), e.generics, - WhereClause { gens: &e.generics, indent: 0, end_newline: true })?; + WhereClause { gens: &e.generics, indent: 0, end_newline: true }); if e.variants.is_empty() && !e.variants_stripped { - write!(w, " {{}}")?; + write!(w, " {{}}"); } else { - write!(w, " {{\n")?; + write!(w, " {{\n"); for v in &e.variants { - write!(w, " ")?; + write!(w, " "); let name = v.name.as_ref().unwrap(); match v.inner { clean::VariantItem(ref var) => { match var.kind { - clean::VariantKind::CLike => write!(w, "{}", name)?, + clean::VariantKind::CLike => write!(w, "{}", name), clean::VariantKind::Tuple(ref tys) => { - write!(w, "{}(", name)?; + write!(w, "{}(", name); for (i, ty) in tys.iter().enumerate() { if i > 0 { - write!(w, ", ")? + write!(w, ", ") } - write!(w, "{}", *ty)?; + write!(w, "{}", *ty); } - write!(w, ")")?; + write!(w, ")"); } clean::VariantKind::Struct(ref s) => { render_struct(w, @@ -3524,29 +3429,29 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, s.struct_type, &s.fields, " ", - false)?; + false); } } } _ => unreachable!() } - write!(w, ",\n")?; + write!(w, ",\n"); } if e.variants_stripped { - write!(w, " // some variants omitted\n")?; + write!(w, " // some variants omitted\n"); } - write!(w, "}}")?; + write!(w, "}}"); } write!(w, "</pre>") - })?; + }); - document(w, cx, it)?; + document(w, cx, it); if !e.variants.is_empty() { write!(w, "<h2 id='variants' class='variants small-section-header'> Variants{}<a href='#variants' class='anchor'></a></h2>\n", - document_non_exhaustive_header(it))?; - document_non_exhaustive(w, it)?; + document_non_exhaustive_header(it)); + document_non_exhaustive(w, it); for variant in &e.variants { let id = cx.derive_id(format!("{}.{}", ItemType::Variant, @@ -3559,22 +3464,22 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, <code id='{ns_id}'>{name}", id = id, ns_id = ns_id, - name = variant.name.as_ref().unwrap())?; + name = variant.name.as_ref().unwrap()); if let clean::VariantItem(ref var) = variant.inner { if let clean::VariantKind::Tuple(ref tys) = var.kind { - write!(w, "(")?; + write!(w, "("); for (i, ty) in tys.iter().enumerate() { if i > 0 { - write!(w, ", ")?; + write!(w, ", "); } - write!(w, "{}", *ty)?; + write!(w, "{}", *ty); } - write!(w, ")")?; + write!(w, ")"); } } - write!(w, "</code></div>")?; - document(w, cx, variant)?; - document_non_exhaustive(w, variant)?; + write!(w, "</code></div>"); + document(w, cx, variant); + document_non_exhaustive(w, variant); use crate::clean::{Variant, VariantKind}; if let clean::VariantItem(Variant { @@ -3584,9 +3489,9 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, ItemType::Variant, variant.name.as_ref().unwrap())); write!(w, "<div class='autohide sub-variant' id='{id}'>", - id = variant_id)?; + id = variant_id); write!(w, "<h3>Fields of <b>{name}</b></h3><div>", - name = variant.name.as_ref().unwrap())?; + name = variant.name.as_ref().unwrap()); for field in &s.fields { use crate::clean::StructFieldItem; if let StructFieldItem(ref ty) = field.inner { @@ -3605,17 +3510,16 @@ fn item_enum(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, id = id, ns_id = ns_id, f = field.name.as_ref().unwrap(), - t = *ty)?; - document(w, cx, field)?; + t = *ty); + document(w, cx, field); } } - write!(w, "</div></div>")?; + write!(w, "</div></div>"); } - render_stability_since(w, variant, it)?; + render_stability_since(w, variant, it); } } - render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All)?; - Ok(()) + render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } fn render_attribute(attr: &ast::MetaItem) -> Option<String> { @@ -3658,7 +3562,7 @@ const ATTRIBUTE_WHITELIST: &'static [Symbol] = &[ // #[bar] <---- not "top" attribute // bar: usize, // } -fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item, top: bool) -> fmt::Result { +fn render_attributes(w: &mut Buffer, it: &clean::Item, top: bool) { let mut attrs = String::new(); for attr in &it.attrs.other_attrs { @@ -3671,117 +3575,114 @@ fn render_attributes(w: &mut dyn fmt::Write, it: &clean::Item, top: bool) -> fmt } if attrs.len() > 0 { write!(w, "<span class=\"docblock attributes{}\">{}</span>", - if top { " top-attr" } else { "" }, &attrs)?; + if top { " top-attr" } else { "" }, &attrs); } - Ok(()) } -fn render_struct(w: &mut fmt::Formatter<'_>, it: &clean::Item, +fn render_struct(w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, ty: doctree::StructType, fields: &[clean::Item], tab: &str, - structhead: bool) -> fmt::Result { + structhead: bool) { write!(w, "{}{}{}", VisSpace(&it.visibility), if structhead {"struct "} else {""}, - it.name.as_ref().unwrap())?; + it.name.as_ref().unwrap()); if let Some(g) = g { - write!(w, "{}", g)? + write!(w, "{}", g) } match ty { doctree::Plain => { if let Some(g) = g { - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })? + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true }) } let mut has_visible_fields = false; - write!(w, " {{")?; + write!(w, " {{"); for field in fields { if let clean::StructFieldItem(ref ty) = field.inner { write!(w, "\n{} {}{}: {},", tab, VisSpace(&field.visibility), field.name.as_ref().unwrap(), - *ty)?; + *ty); has_visible_fields = true; } } if has_visible_fields { if it.has_stripped_fields().unwrap() { - write!(w, "\n{} // some fields omitted", tab)?; + write!(w, "\n{} // some fields omitted", tab); } - write!(w, "\n{}", tab)?; + write!(w, "\n{}", tab); } else if it.has_stripped_fields().unwrap() { // If there are no visible fields we can just display // `{ /* fields omitted */ }` to save space. - write!(w, " /* fields omitted */ ")?; + write!(w, " /* fields omitted */ "); } - write!(w, "}}")?; + write!(w, "}}"); } doctree::Tuple => { - write!(w, "(")?; + write!(w, "("); for (i, field) in fields.iter().enumerate() { if i > 0 { - write!(w, ", ")?; + write!(w, ", "); } match field.inner { clean::StrippedItem(box clean::StructFieldItem(..)) => { - write!(w, "_")? + write!(w, "_") } clean::StructFieldItem(ref ty) => { - write!(w, "{}{}", VisSpace(&field.visibility), *ty)? + write!(w, "{}{}", VisSpace(&field.visibility), *ty) } _ => unreachable!() } } - write!(w, ")")?; + write!(w, ")"); if let Some(g) = g { - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })? + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false }) } - write!(w, ";")?; + write!(w, ";"); } doctree::Unit => { // Needed for PhantomData. if let Some(g) = g { - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false })? + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: false }) } - write!(w, ";")?; + write!(w, ";"); } } - Ok(()) } -fn render_union(w: &mut fmt::Formatter<'_>, it: &clean::Item, +fn render_union(w: &mut Buffer, it: &clean::Item, g: Option<&clean::Generics>, fields: &[clean::Item], tab: &str, - structhead: bool) -> fmt::Result { + structhead: bool) { write!(w, "{}{}{}", VisSpace(&it.visibility), if structhead {"union "} else {""}, - it.name.as_ref().unwrap())?; + it.name.as_ref().unwrap()); if let Some(g) = g { - write!(w, "{}", g)?; - write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true })?; + write!(w, "{}", g); + write!(w, "{}", WhereClause { gens: g, indent: 0, end_newline: true }); } - write!(w, " {{\n{}", tab)?; + write!(w, " {{\n{}", tab); for field in fields { if let clean::StructFieldItem(ref ty) = field.inner { write!(w, " {}{}: {},\n{}", VisSpace(&field.visibility), field.name.as_ref().unwrap(), *ty, - tab)?; + tab); } } if it.has_stripped_fields().unwrap() { - write!(w, " // some fields omitted\n{}", tab)?; + write!(w, " // some fields omitted\n{}", tab); } - write!(w, "}}")?; - Ok(()) + write!(w, "}}"); } #[derive(Copy, Clone)] @@ -3810,15 +3711,15 @@ enum RenderMode { ForDeref { mut_: bool }, } -fn render_assoc_items(w: &mut fmt::Formatter<'_>, +fn render_assoc_items(w: &mut Buffer, cx: &Context, containing_item: &clean::Item, it: DefId, - what: AssocItemRender<'_>) -> fmt::Result { + what: AssocItemRender<'_>) { let c = cache(); let v = match c.impls.get(&it) { Some(v) => v, - None => return Ok(()), + None => return, }; let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| { i.inner_impl().trait_.is_none() @@ -3830,7 +3731,7 @@ fn render_assoc_items(w: &mut fmt::Formatter<'_>, <h2 id='methods' class='small-section-header'>\ Methods<a href='#methods' class='anchor'></a>\ </h2>\ - ")?; + "); RenderMode::Normal } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { @@ -3839,17 +3740,17 @@ fn render_assoc_items(w: &mut fmt::Formatter<'_>, Methods from {}<Target = {}>\ <a href='#deref-methods' class='anchor'></a>\ </h2>\ - ", trait_, type_)?; + ", trait_, type_); RenderMode::ForDeref { mut_: deref_mut_ } } }; for i in &non_trait { render_impl(w, cx, i, AssocItemLink::Anchor(None), render_mode, - containing_item.stable_since(), true, None, false, true)?; + containing_item.stable_since(), true, None, false, true); } } if let AssocItemRender::DerefFor { .. } = what { - return Ok(()); + return; } if !traits.is_empty() { let deref_impl = traits.iter().find(|t| { @@ -3859,31 +3760,25 @@ fn render_assoc_items(w: &mut fmt::Formatter<'_>, let has_deref_mut = traits.iter().find(|t| { t.inner_impl().trait_.def_id() == c.deref_mut_trait_did }).is_some(); - render_deref_methods(w, cx, impl_, containing_item, has_deref_mut)?; + render_deref_methods(w, cx, impl_, containing_item, has_deref_mut); } let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) = traits .iter() .partition(|t| t.inner_impl().synthetic); - let (blanket_impl, concrete) = concrete + let (blanket_impl, concrete): (Vec<&&Impl>, _) = concrete .into_iter() .partition(|t| t.inner_impl().blanket_impl.is_some()); - struct RendererStruct<'a, 'b, 'c>(&'a Context, Vec<&'b &'b Impl>, &'c clean::Item); - - impl<'a, 'b, 'c> fmt::Display for RendererStruct<'a, 'b, 'c> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - render_impls(self.0, fmt, &self.1, self.2) - } - } - - let impls = RendererStruct(cx, concrete, containing_item).to_string(); + let mut impls = Buffer::empty_from(&w); + render_impls(cx, &mut impls, &concrete, containing_item); + let impls = impls.into_inner(); if !impls.is_empty() { write!(w, "\ <h2 id='implementations' class='small-section-header'>\ Trait Implementations<a href='#implementations' class='anchor'></a>\ </h2>\ - <div id='implementations-list'>{}</div>", impls)?; + <div id='implementations-list'>{}</div>", impls); } if !synthetic.is_empty() { @@ -3893,9 +3788,9 @@ fn render_assoc_items(w: &mut fmt::Formatter<'_>, <a href='#synthetic-implementations' class='anchor'></a>\ </h2>\ <div id='synthetic-implementations-list'>\ - ")?; - render_impls(cx, w, &synthetic, containing_item)?; - write!(w, "</div>")?; + "); + render_impls(cx, w, &synthetic, containing_item); + write!(w, "</div>"); } if !blanket_impl.is_empty() { @@ -3905,16 +3800,15 @@ fn render_assoc_items(w: &mut fmt::Formatter<'_>, <a href='#blanket-implementations' class='anchor'></a>\ </h2>\ <div id='blanket-implementations-list'>\ - ")?; - render_impls(cx, w, &blanket_impl, containing_item)?; - write!(w, "</div>")?; + "); + render_impls(cx, w, &blanket_impl, containing_item); + write!(w, "</div>"); } } - Ok(()) } -fn render_deref_methods(w: &mut fmt::Formatter<'_>, cx: &Context, impl_: &Impl, - container_item: &clean::Item, deref_mut: bool) -> fmt::Result { +fn render_deref_methods(w: &mut Buffer, cx: &Context, impl_: &Impl, + container_item: &clean::Item, deref_mut: bool) { let deref_type = impl_.inner_impl().trait_.as_ref().unwrap(); let target = impl_.inner_impl().items.iter().filter_map(|item| { match item.inner { @@ -3929,10 +3823,9 @@ fn render_deref_methods(w: &mut fmt::Formatter<'_>, cx: &Context, impl_: &Impl, } else { if let Some(prim) = target.primitive_type() { if let Some(&did) = cache().primitive_locations.get(&prim) { - render_assoc_items(w, cx, container_item, did, what)?; + render_assoc_items(w, cx, container_item, did, what); } } - Ok(()) } } @@ -3962,7 +3855,7 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } } -fn render_spotlight_traits(item: &clean::Item) -> Result<String, fmt::Error> { +fn render_spotlight_traits(item: &clean::Item) -> String { let mut out = String::new(); match item.inner { @@ -3970,16 +3863,16 @@ fn render_spotlight_traits(item: &clean::Item) -> Result<String, fmt::Error> { clean::TyMethodItem(clean::TyMethod { ref decl, .. }) | clean::MethodItem(clean::Method { ref decl, .. }) | clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => { - out = spotlight_decl(decl)?; + out = spotlight_decl(decl); } _ => {} } - Ok(out) + out } -fn spotlight_decl(decl: &clean::FnDecl) -> Result<String, fmt::Error> { - let mut out = String::new(); +fn spotlight_decl(decl: &clean::FnDecl) -> String { + let mut out = Buffer::html(); let mut trait_ = String::new(); if let Some(did) = decl.output.def_id() { @@ -4005,7 +3898,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> Result<String, fmt::Error> { assoc_type(&mut out, it, &[], Some(&tydef.type_), AssocItemLink::GotoSource(t_did, &FxHashSet::default()), - "")?; + ""); out.push_str(";</span>"); } } @@ -4022,13 +3915,13 @@ fn spotlight_decl(decl: &clean::FnDecl) -> Result<String, fmt::Error> { out.push_str("</code></div></div>"); } - Ok(out) + out.into_inner() } -fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocItemLink<'_>, +fn render_impl(w: &mut Buffer, cx: &Context, i: &Impl, link: AssocItemLink<'_>, render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool, use_absolute: Option<bool>, is_on_foreign_type: bool, - show_default_items: bool) -> fmt::Result { + show_default_items: bool) { if render_mode == RenderMode::Normal { let id = cx.derive_id(match i.inner_impl().trait_ { Some(ref t) => if is_on_foreign_type { @@ -4039,45 +3932,45 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt None => "impl".to_string(), }); if let Some(use_absolute) = use_absolute { - write!(w, "<h3 id='{}' class='impl'><code class='in-band'>", id)?; - fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute)?; + write!(w, "<h3 id='{}' class='impl'><code class='in-band'>", id); + fmt_impl_for_trait_page(&i.inner_impl(), w, use_absolute); if show_def_docs { for it in &i.inner_impl().items { if let clean::TypedefItem(ref tydef, _) = it.inner { - write!(w, "<span class=\"where fmt-newline\"> ")?; + write!(w, "<span class=\"where fmt-newline\"> "); assoc_type(w, it, &vec![], Some(&tydef.type_), AssocItemLink::Anchor(None), - "")?; - write!(w, ";</span>")?; + ""); + write!(w, ";</span>"); } } } - write!(w, "</code>")?; + write!(w, "</code>"); } else { write!(w, "<h3 id='{}' class='impl'><code class='in-band'>{}</code>", id, i.inner_impl() - )?; + ); } - write!(w, "<a href='#{}' class='anchor'></a>", id)?; + write!(w, "<a href='#{}' class='anchor'></a>", id); let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]); - render_stability_since_raw(w, since, outer_version)?; - if let Some(l) = (Item { item: &i.impl_item, cx: cx }).src_href() { + render_stability_since_raw(w, since, outer_version); + if let Some(l) = cx.src_href(&i.impl_item) { write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>", - l, "goto source code")?; + l, "goto source code"); } - write!(w, "</h3>")?; + write!(w, "</h3>"); if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) { let mut ids = cx.id_map.borrow_mut(); write!(w, "<div class='docblock'>{}</div>", Markdown(&*dox, &i.impl_item.links(), &mut ids, - cx.codes, cx.edition, &cx.playground).to_string())?; + cx.codes, cx.edition, &cx.playground).to_string()); } } - fn doc_impl_item(w: &mut fmt::Formatter<'_>, cx: &Context, item: &clean::Item, + fn doc_impl_item(w: &mut Buffer, cx: &Context, item: &clean::Item, link: AssocItemLink<'_>, render_mode: RenderMode, is_default_item: bool, outer_version: Option<&str>, - trait_: Option<&clean::Trait>, show_def_docs: bool) -> fmt::Result { + trait_: Option<&clean::Trait>, show_def_docs: bool) { let item_type = item.type_(); let name = item.name.as_ref().unwrap(); @@ -4101,50 +3994,50 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if render_method_item { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); - write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?; - write!(w, "{}", spotlight_decl(decl)?)?; - write!(w, "<code id='{}'>", ns_id)?; - render_assoc_item(w, item, link.anchor(&id), ItemType::Impl)?; - write!(w, "</code>")?; - render_stability_since_raw(w, item.stable_since(), outer_version)?; - if let Some(l) = (Item { cx, item }).src_href() { + write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class); + write!(w, "{}", spotlight_decl(decl)); + write!(w, "<code id='{}'>", ns_id); + render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); + write!(w, "</code>"); + render_stability_since_raw(w, item.stable_since(), outer_version); + if let Some(l) = cx.src_href(item) { write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>", - l, "goto source code")?; + l, "goto source code"); } - write!(w, "</h4>")?; + write!(w, "</h4>"); } } clean::TypedefItem(ref tydef, _) => { let id = cx.derive_id(format!("{}.{}", ItemType::AssocType, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); - write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?; - write!(w, "<code id='{}'>", ns_id)?; - assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), "")?; - write!(w, "</code></h4>")?; + write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class); + write!(w, "<code id='{}'>", ns_id); + assoc_type(w, item, &Vec::new(), Some(&tydef.type_), link.anchor(&id), ""); + write!(w, "</code></h4>"); } clean::AssocConstItem(ref ty, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); - write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?; - write!(w, "<code id='{}'>", ns_id)?; - assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "")?; - write!(w, "</code>")?; - render_stability_since_raw(w, item.stable_since(), outer_version)?; - if let Some(l) = (Item { cx, item }).src_href() { + write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class); + write!(w, "<code id='{}'>", ns_id); + assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), ""); + write!(w, "</code>"); + render_stability_since_raw(w, item.stable_since(), outer_version); + if let Some(l) = cx.src_href(item) { write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>", - l, "goto source code")?; + l, "goto source code"); } - write!(w, "</h4>")?; + write!(w, "</h4>"); } clean::AssocTypeItem(ref bounds, ref default) => { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); - write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class)?; - write!(w, "<code id='{}'>", ns_id)?; - assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), "")?; - write!(w, "</code></h4>")?; + write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class); + write!(w, "<code id='{}'>", ns_id); + assoc_type(w, item, bounds, default.as_ref(), link.anchor(&id), ""); + write!(w, "</code></h4>"); } - clean::StrippedItem(..) => return Ok(()), + clean::StrippedItem(..) => return, _ => panic!("can't make docs for trait item with name {:?}", item.name) } @@ -4156,47 +4049,46 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if let Some(it) = t.items.iter().find(|i| i.name == item.name) { // We need the stability of the item from the trait // because impls can't have a stability. - document_stability(w, cx, it, is_hidden)?; + document_stability(w, cx, it, is_hidden); if item.doc_value().is_some() { - document_full(w, item, cx, "", is_hidden)?; + document_full(w, item, cx, "", is_hidden); } else if show_def_docs { // In case the item isn't documented, // provide short documentation from the trait. - document_short(w, cx, it, link, "", is_hidden)?; + document_short(w, cx, it, link, "", is_hidden); } } } else { - document_stability(w, cx, item, is_hidden)?; + document_stability(w, cx, item, is_hidden); if show_def_docs { - document_full(w, item, cx, "", is_hidden)?; + document_full(w, item, cx, "", is_hidden); } } } else { - document_stability(w, cx, item, is_hidden)?; + document_stability(w, cx, item, is_hidden); if show_def_docs { - document_short(w, cx, item, link, "", is_hidden)?; + document_short(w, cx, item, link, "", is_hidden); } } } - Ok(()) } let traits = &cache().traits; let trait_ = i.trait_did().map(|did| &traits[&did]); - write!(w, "<div class='impl-items'>")?; + write!(w, "<div class='impl-items'>"); for trait_item in &i.inner_impl().items { doc_impl_item(w, cx, trait_item, link, render_mode, - false, outer_version, trait_, show_def_docs)?; + false, outer_version, trait_, show_def_docs); } - fn render_default_items(w: &mut fmt::Formatter<'_>, + fn render_default_items(w: &mut Buffer, cx: &Context, t: &clean::Trait, i: &clean::Impl, render_mode: RenderMode, outer_version: Option<&str>, - show_def_docs: bool) -> fmt::Result { + show_def_docs: bool) { for trait_item in &t.items { let n = trait_item.name.clone(); if i.items.iter().find(|m| m.name == n).is_some() { @@ -4206,9 +4098,8 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt let assoc_link = AssocItemLink::GotoSource(did, &i.provided_trait_methods); doc_impl_item(w, cx, trait_item, assoc_link, render_mode, true, - outer_version, None, show_def_docs)?; + outer_version, None, show_def_docs); } - Ok(()) } // If we've implemented a trait, then also emit documentation for all @@ -4218,29 +4109,27 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt if show_default_items { if let Some(t) = trait_ { render_default_items(w, cx, t, &i.inner_impl(), - render_mode, outer_version, show_def_docs)?; + render_mode, outer_version, show_def_docs); } } - write!(w, "</div>")?; - - Ok(()) + write!(w, "</div>"); } fn item_opaque_ty( - w: &mut fmt::Formatter<'_>, + w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::OpaqueTy, -) -> fmt::Result { - write!(w, "<pre class='rust opaque'>")?; - render_attributes(w, it, false)?; +) { + write!(w, "<pre class='rust opaque'>"); + render_attributes(w, it, false); write!(w, "type {}{}{where_clause} = impl {bounds};</pre>", it.name.as_ref().unwrap(), t.generics, where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, - bounds = bounds(&t.bounds, false))?; + bounds = bounds(&t.bounds, false)); - document(w, cx, it)?; + document(w, cx, it); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -4249,17 +4138,17 @@ fn item_opaque_ty( render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - t: &clean::TraitAlias) -> fmt::Result { - write!(w, "<pre class='rust trait-alias'>")?; - render_attributes(w, it, false)?; +fn item_trait_alias(w: &mut Buffer, cx: &Context, it: &clean::Item, + t: &clean::TraitAlias) { + write!(w, "<pre class='rust trait-alias'>"); + render_attributes(w, it, false); write!(w, "trait {}{}{} = {};</pre>", it.name.as_ref().unwrap(), t.generics, WhereClause { gens: &t.generics, indent: 0, end_newline: true }, - bounds(&t.bounds, true))?; + bounds(&t.bounds, true)); - document(w, cx, it)?; + document(w, cx, it); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -4268,17 +4157,16 @@ fn item_trait_alias(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - t: &clean::Typedef) -> fmt::Result { - write!(w, "<pre class='rust typedef'>")?; - render_attributes(w, it, false)?; +fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typedef) { + write!(w, "<pre class='rust typedef'>"); + render_attributes(w, it, false); write!(w, "type {}{}{where_clause} = {type_};</pre>", it.name.as_ref().unwrap(), t.generics, where_clause = WhereClause { gens: &t.generics, indent: 0, end_newline: true }, - type_ = t.type_)?; + type_ = t.type_); - document(w, cx, it)?; + document(w, cx, it); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -4287,117 +4175,111 @@ fn item_typedef(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_foreign_type(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item) -> fmt::Result { - writeln!(w, "<pre class='rust foreigntype'>extern {{")?; - render_attributes(w, it, false)?; +fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item) { + writeln!(w, "<pre class='rust foreigntype'>extern {{"); + render_attributes(w, it, false); write!( w, " {}type {};\n}}</pre>", VisSpace(&it.visibility), it.name.as_ref().unwrap(), - )?; + ); - document(w, cx, it)?; + document(w, cx, it); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -impl<'a> fmt::Display for Sidebar<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let cx = self.cx; - let it = self.item; - let parentlen = cx.current.len() - if it.is_mod() {1} else {0}; - - if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union() - || it.is_enum() || it.is_mod() || it.is_typedef() { - write!(fmt, "<p class='location'>{}{}</p>", - match it.inner { - clean::StructItem(..) => "Struct ", - clean::TraitItem(..) => "Trait ", - clean::PrimitiveItem(..) => "Primitive Type ", - clean::UnionItem(..) => "Union ", - clean::EnumItem(..) => "Enum ", - clean::TypedefItem(..) => "Type Definition ", - clean::ForeignTypeItem => "Foreign Type ", - clean::ModuleItem(..) => if it.is_crate() { - "Crate " - } else { - "Module " - }, - _ => "", +fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer) { + let parentlen = cx.current.len() - if it.is_mod() {1} else {0}; + + if it.is_struct() || it.is_trait() || it.is_primitive() || it.is_union() + || it.is_enum() || it.is_mod() || it.is_typedef() { + write!(buffer, "<p class='location'>{}{}</p>", + match it.inner { + clean::StructItem(..) => "Struct ", + clean::TraitItem(..) => "Trait ", + clean::PrimitiveItem(..) => "Primitive Type ", + clean::UnionItem(..) => "Union ", + clean::EnumItem(..) => "Enum ", + clean::TypedefItem(..) => "Type Definition ", + clean::ForeignTypeItem => "Foreign Type ", + clean::ModuleItem(..) => if it.is_crate() { + "Crate " + } else { + "Module " }, - it.name.as_ref().unwrap())?; - } - - if it.is_crate() { - if let Some(ref version) = cache().crate_version { - write!(fmt, - "<div class='block version'>\ - <p>Version {}</p>\ - </div>", - version)?; - } - } - - write!(fmt, "<div class=\"sidebar-elems\">")?; - if it.is_crate() { - write!(fmt, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>", - it.name.as_ref().expect("crates always have a name"))?; - } - match it.inner { - clean::StructItem(ref s) => sidebar_struct(fmt, it, s)?, - clean::TraitItem(ref t) => sidebar_trait(fmt, it, t)?, - clean::PrimitiveItem(ref p) => sidebar_primitive(fmt, it, p)?, - clean::UnionItem(ref u) => sidebar_union(fmt, it, u)?, - clean::EnumItem(ref e) => sidebar_enum(fmt, it, e)?, - clean::TypedefItem(ref t, _) => sidebar_typedef(fmt, it, t)?, - clean::ModuleItem(ref m) => sidebar_module(fmt, it, &m.items)?, - clean::ForeignTypeItem => sidebar_foreign_type(fmt, it)?, - _ => (), - } - - // The sidebar is designed to display sibling functions, modules and - // other miscellaneous information. since there are lots of sibling - // items (and that causes quadratic growth in large modules), - // we refactor common parts into a shared JavaScript file per module. - // still, we don't move everything into JS because we want to preserve - // as much HTML as possible in order to allow non-JS-enabled browsers - // to navigate the documentation (though slightly inefficiently). - - write!(fmt, "<p class='location'>")?; - for (i, name) in cx.current.iter().take(parentlen).enumerate() { - if i > 0 { - write!(fmt, "::<wbr>")?; - } - write!(fmt, "<a href='{}index.html'>{}</a>", - &cx.root_path()[..(cx.current.len() - i - 1) * 3], - *name)?; - } - write!(fmt, "</p>")?; - - // Sidebar refers to the enclosing module, not this module. - let relpath = if it.is_mod() { "../" } else { "" }; - write!(fmt, - "<script>window.sidebarCurrent = {{\ - name: '{name}', \ - ty: '{ty}', \ - relpath: '{path}'\ - }};</script>", - name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), - ty = it.type_().css_class(), - path = relpath)?; - if parentlen == 0 { - // There is no sidebar-items.js beyond the crate root path - // FIXME maybe dynamic crate loading can be merged here - } else { - write!(fmt, "<script defer src=\"{path}sidebar-items.js\"></script>", - path = relpath)?; - } - // Closes sidebar-elems div. - write!(fmt, "</div>")?; - - Ok(()) + _ => "", + }, + it.name.as_ref().unwrap()); + } + + if it.is_crate() { + if let Some(ref version) = cache().crate_version { + write!(buffer, + "<div class='block version'>\ + <p>Version {}</p>\ + </div>", + version); + } + } + + write!(buffer, "<div class=\"sidebar-elems\">"); + if it.is_crate() { + write!(buffer, "<a id='all-types' href='all.html'><p>See all {}'s items</p></a>", + it.name.as_ref().expect("crates always have a name")); + } + match it.inner { + clean::StructItem(ref s) => sidebar_struct(buffer, it, s), + clean::TraitItem(ref t) => sidebar_trait(buffer, it, t), + clean::PrimitiveItem(ref p) => sidebar_primitive(buffer, it, p), + clean::UnionItem(ref u) => sidebar_union(buffer, it, u), + clean::EnumItem(ref e) => sidebar_enum(buffer, it, e), + clean::TypedefItem(ref t, _) => sidebar_typedef(buffer, it, t), + clean::ModuleItem(ref m) => sidebar_module(buffer, it, &m.items), + clean::ForeignTypeItem => sidebar_foreign_type(buffer, it), + _ => (), + } + + // The sidebar is designed to display sibling functions, modules and + // other miscellaneous information. since there are lots of sibling + // items (and that causes quadratic growth in large modules), + // we refactor common parts into a shared JavaScript file per module. + // still, we don't move everything into JS because we want to preserve + // as much HTML as possible in order to allow non-JS-enabled browsers + // to navigate the documentation (though slightly inefficiently). + + write!(buffer, "<p class='location'>"); + for (i, name) in cx.current.iter().take(parentlen).enumerate() { + if i > 0 { + write!(buffer, "::<wbr>"); + } + write!(buffer, "<a href='{}index.html'>{}</a>", + &cx.root_path()[..(cx.current.len() - i - 1) * 3], + *name); + } + write!(buffer, "</p>"); + + // Sidebar refers to the enclosing module, not this module. + let relpath = if it.is_mod() { "../" } else { "" }; + write!(buffer, + "<script>window.sidebarCurrent = {{\ + name: '{name}', \ + ty: '{ty}', \ + relpath: '{path}'\ + }};</script>", + name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""), + ty = it.type_().css_class(), + path = relpath); + if parentlen == 0 { + // There is no sidebar-items.js beyond the crate root path + // FIXME maybe dynamic crate loading can be merged here + } else { + write!(buffer, "<script defer src=\"{path}sidebar-items.js\"></script>", + path = relpath); } + // Closes sidebar-elems div. + write!(buffer, "</div>"); } fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String { @@ -4570,8 +4452,7 @@ fn sidebar_assoc_items(it: &clean::Item) -> String { out } -fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - s: &clean::Struct) -> fmt::Result { +fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) { let mut sidebar = String::new(); let fields = get_struct_fields_name(&s.fields); @@ -4585,9 +4466,8 @@ fn sidebar_struct(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; + write!(buf, "<div class=\"block items\">{}</div>", sidebar); } - Ok(()) } fn get_id_for_impl_on_foreign_type(for_: &clean::Type, trait_: &clean::Type) -> String { @@ -4611,8 +4491,7 @@ fn is_negative_impl(i: &clean::Impl) -> bool { i.polarity == Some(clean::ImplPolarity::Negative) } -fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - t: &clean::Trait) -> fmt::Result { +fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { let mut sidebar = String::new(); let types = t.items @@ -4720,27 +4599,23 @@ fn sidebar_trait(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); - write!(fmt, "<div class=\"block items\">{}</div>", sidebar) + write!(buf, "<div class=\"block items\">{}</div>", sidebar) } -fn sidebar_primitive(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - _p: &clean::PrimitiveType) -> fmt::Result { +fn sidebar_primitive(buf: &mut Buffer, it: &clean::Item, _p: &clean::PrimitiveType) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; + write!(buf, "<div class=\"block items\">{}</div>", sidebar); } - Ok(()) } -fn sidebar_typedef(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - _t: &clean::Typedef) -> fmt::Result { +fn sidebar_typedef(buf: &mut Buffer, it: &clean::Item, _t: &clean::Typedef) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; + write!(buf, "<div class=\"block items\">{}</div>", sidebar); } - Ok(()) } fn get_struct_fields_name(fields: &[clean::Item]) -> String { @@ -4758,8 +4633,7 @@ fn get_struct_fields_name(fields: &[clean::Item]) -> String { .collect() } -fn sidebar_union(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - u: &clean::Union) -> fmt::Result { +fn sidebar_union(buf: &mut Buffer, it: &clean::Item, u: &clean::Union) { let mut sidebar = String::new(); let fields = get_struct_fields_name(&u.fields); @@ -4771,13 +4645,11 @@ fn sidebar_union(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; + write!(buf, "<div class=\"block items\">{}</div>", sidebar); } - Ok(()) } -fn sidebar_enum(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, - e: &clean::Enum) -> fmt::Result { +fn sidebar_enum(buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) { let mut sidebar = String::new(); let variants = e.variants.iter() @@ -4795,9 +4667,8 @@ fn sidebar_enum(fmt: &mut fmt::Formatter<'_>, it: &clean::Item, sidebar.push_str(&sidebar_assoc_items(it)); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; + write!(buf, "<div class=\"block items\">{}</div>", sidebar); } - Ok(()) } fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { @@ -4831,8 +4702,7 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { } } -fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item, - items: &[clean::Item]) -> fmt::Result { +fn sidebar_module(buf: &mut Buffer, _it: &clean::Item, items: &[clean::Item]) { let mut sidebar = String::new(); if items.iter().any(|it| it.type_() == ItemType::ExternCrate || @@ -4859,72 +4729,67 @@ fn sidebar_module(fmt: &mut fmt::Formatter<'_>, _it: &clean::Item, } if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\"><ul>{}</ul></div>", sidebar)?; + write!(buf, "<div class=\"block items\"><ul>{}</ul></div>", sidebar); } - Ok(()) } -fn sidebar_foreign_type(fmt: &mut fmt::Formatter<'_>, it: &clean::Item) -> fmt::Result { +fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) { let sidebar = sidebar_assoc_items(it); if !sidebar.is_empty() { - write!(fmt, "<div class=\"block items\">{}</div>", sidebar)?; + write!(buf, "<div class=\"block items\">{}</div>", sidebar); } - Ok(()) } -fn item_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, - t: &clean::Macro) -> fmt::Result { +fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) { wrap_into_docblock(w, |w| { w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), None, None)) - })?; + }); document(w, cx, it) } -fn item_proc_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) - -> fmt::Result -{ +fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) { let name = it.name.as_ref().expect("proc-macros always have names"); match m.kind { MacroKind::Bang => { - write!(w, "<pre class='rust macro'>")?; - write!(w, "{}!() {{ /* proc-macro */ }}", name)?; - write!(w, "</pre>")?; + write!(w, "<pre class='rust macro'>"); + write!(w, "{}!() {{ /* proc-macro */ }}", name); + write!(w, "</pre>"); } MacroKind::Attr => { - write!(w, "<pre class='rust attr'>")?; - write!(w, "#[{}]", name)?; - write!(w, "</pre>")?; + write!(w, "<pre class='rust attr'>"); + write!(w, "#[{}]", name); + write!(w, "</pre>"); } MacroKind::Derive => { - write!(w, "<pre class='rust derive'>")?; - write!(w, "#[derive({})]", name)?; + write!(w, "<pre class='rust derive'>"); + write!(w, "#[derive({})]", name); if !m.helpers.is_empty() { - writeln!(w, "\n{{")?; - writeln!(w, " // Attributes available to this derive:")?; + writeln!(w, "\n{{"); + writeln!(w, " // Attributes available to this derive:"); for attr in &m.helpers { - writeln!(w, " #[{}]", attr)?; + writeln!(w, " #[{}]", attr); } - write!(w, "}}")?; + write!(w, "}}"); } - write!(w, "</pre>")?; + write!(w, "</pre>"); } } document(w, cx, it) } -fn item_primitive(w: &mut fmt::Formatter<'_>, cx: &Context, +fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, - _p: &clean::PrimitiveType) -> fmt::Result { - document(w, cx, it)?; + _p: &clean::PrimitiveType) { + document(w, cx, it); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All) } -fn item_keyword(w: &mut fmt::Formatter<'_>, cx: &Context, +fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item, - _p: &str) -> fmt::Result { + _p: &str) { document(w, cx, it) } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index c1f1f59d914..d840683a7af 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -4,10 +4,10 @@ use crate::fold::DocFolder; use crate::html::layout; use crate::html::render::{Error, SharedContext, BASIC_KEYWORDS}; use crate::html::highlight; +use crate::html::format::Buffer; use std::ffi::OsStr; use std::fs; use std::path::{Component, Path, PathBuf}; -use std::fmt; use syntax::source_map::FileName; crate fn render(dst: &Path, scx: &mut SharedContext, @@ -105,7 +105,6 @@ impl<'a> SourceCollector<'a> { cur.push(&fname); href.push_str(&fname.to_string_lossy()); - let mut v = Vec::new(); let title = format!("{} -- source", cur.file_name().expect("failed to get file name") .to_string_lossy()); let desc = format!("Source to the Rust file `{}`.", filename); @@ -120,15 +119,10 @@ impl<'a> SourceCollector<'a> { extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], }; - let result = layout::render(&mut v, &self.scx.layout, - &page, &(""), &Source(contents), - self.scx.css_file_extension.is_some(), - &self.scx.themes, - self.scx.generate_search_filter); - if let Err(e) = result { - return Err(Error::new(e, &cur)); - } - self.scx.fs.write(&cur, &v)?; + let v = layout::render(&self.scx.layout, + &page, "", |buf: &mut _| print_src(buf, &contents), + &self.scx.themes); + self.scx.fs.write(&cur, v.as_bytes())?; self.scx.local_sources.insert(p.clone(), href); Ok(()) } @@ -163,25 +157,19 @@ where /// Wrapper struct to render the source code of a file. This will do things like /// adding line numbers to the left-hand side. -struct Source<'a>(&'a str); - -impl<'a> fmt::Display for Source<'a> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Source(s) = *self; - let lines = s.lines().count(); - let mut cols = 0; - let mut tmp = lines; - while tmp > 0 { - cols += 1; - tmp /= 10; - } - write!(fmt, "<pre class=\"line-numbers\">")?; - for i in 1..=lines { - write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols)?; - } - write!(fmt, "</pre>")?; - write!(fmt, "{}", - highlight::render_with_highlighting(s, None, None, None))?; - Ok(()) +fn print_src(buf: &mut Buffer, s: &str) { + let lines = s.lines().count(); + let mut cols = 0; + let mut tmp = lines; + while tmp > 0 { + cols += 1; + tmp /= 10; + } + write!(buf, "<pre class=\"line-numbers\">"); + for i in 1..=lines { + write!(buf, "<span id=\"{0}\">{0:1$}</span>\n", i, cols); } + write!(buf, "</pre>"); + write!(buf, "{}", + highlight::render_with_highlighting(s, None, None, None)); } |
