]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/render/mod.rs
Hide Crate Version on narrow Screens
[rust.git] / src / librustdoc / html / render / mod.rs
1 //! Rustdoc's HTML rendering module.
2 //!
3 //! This modules contains the bulk of the logic necessary for rendering a
4 //! rustdoc `clean::Crate` instance to a set of static HTML pages. This
5 //! rendering process is largely driven by the `format!` syntax extension to
6 //! perform all I/O into files and streams.
7 //!
8 //! The rendering process is largely driven by the `Context` and `Cache`
9 //! structures. The cache is pre-populated by crawling the crate in question,
10 //! and then it is shared among the various rendering threads. The cache is meant
11 //! to be a fairly large structure not implementing `Clone` (because it's shared
12 //! among threads). The context, however, should be a lightweight structure. This
13 //! is cloned per-thread and contains information about what is currently being
14 //! rendered.
15 //!
16 //! In order to speed up rendering (mostly because of markdown rendering), the
17 //! rendering process has been parallelized. This parallelization is only
18 //! exposed through the `crate` method on the context, and then also from the
19 //! fact that the shared cache is stored in TLS (and must be accessed as such).
20 //!
21 //! In addition to rendering the crate itself, this module is also responsible
22 //! for creating the corresponding search index and source file renderings.
23 //! These threads are not parallelized (they haven't been a bottleneck yet), and
24 //! both occur before the crate is rendered.
25
26 crate mod cache;
27
28 #[cfg(test)]
29 mod tests;
30
31 mod context;
32 mod print_item;
33 mod write_shared;
34
35 crate use context::*;
36
37 use std::collections::VecDeque;
38 use std::default::Default;
39 use std::fmt;
40 use std::path::PathBuf;
41 use std::str;
42 use std::string::ToString;
43
44 use rustc_ast_pretty::pprust;
45 use rustc_attr::{ConstStability, Deprecation, StabilityLevel};
46 use rustc_data_structures::fx::FxHashSet;
47 use rustc_hir as hir;
48 use rustc_hir::def::CtorKind;
49 use rustc_hir::def_id::DefId;
50 use rustc_hir::Mutability;
51 use rustc_middle::middle::stability;
52 use rustc_span::symbol::{kw, sym, Symbol};
53 use serde::ser::SerializeSeq;
54 use serde::{Serialize, Serializer};
55
56 use crate::clean::{self, FakeDefId, GetDefId, RenderedLink, SelfTy};
57 use crate::docfs::PathError;
58 use crate::error::Error;
59 use crate::formats::cache::Cache;
60 use crate::formats::item_type::ItemType;
61 use crate::formats::{AssocItemRender, Impl, RenderMode};
62 use crate::html::escape::Escape;
63 use crate::html::format::{
64     href, print_abi_with_space, print_constness_with_space, print_default_space,
65     print_generic_bounds, print_where_clause, Buffer, PrintWithSpace,
66 };
67 use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine};
68
69 /// A pair of name and its optional document.
70 crate type NameDoc = (String, Option<String>);
71
72 crate fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
73     crate::html::format::display_fn(move |f| {
74         if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
75     })
76 }
77
78 // Helper structs for rendering items/sidebars and carrying along contextual
79 // information
80
81 /// Struct representing one entry in the JS search index. These are all emitted
82 /// by hand to a large JS file at the end of cache-creation.
83 #[derive(Debug)]
84 crate struct IndexItem {
85     crate ty: ItemType,
86     crate name: String,
87     crate path: String,
88     crate desc: String,
89     crate parent: Option<DefId>,
90     crate parent_idx: Option<usize>,
91     crate search_type: Option<IndexItemFunctionType>,
92     crate aliases: Box<[String]>,
93 }
94
95 /// A type used for the search index.
96 #[derive(Debug)]
97 crate struct RenderType {
98     ty: Option<DefId>,
99     idx: Option<usize>,
100     name: Option<String>,
101     generics: Option<Vec<Generic>>,
102 }
103
104 /// A type used for the search index.
105 #[derive(Debug)]
106 crate struct Generic {
107     name: String,
108     defid: Option<DefId>,
109     idx: Option<usize>,
110 }
111
112 impl Serialize for Generic {
113     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
114     where
115         S: Serializer,
116     {
117         if let Some(id) = self.idx {
118             serializer.serialize_some(&id)
119         } else {
120             serializer.serialize_some(&self.name)
121         }
122     }
123 }
124
125 /// Full type of functions/methods in the search index.
126 #[derive(Debug)]
127 crate struct IndexItemFunctionType {
128     inputs: Vec<TypeWithKind>,
129     output: Option<Vec<TypeWithKind>>,
130 }
131
132 impl Serialize for IndexItemFunctionType {
133     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
134     where
135         S: Serializer,
136     {
137         // If we couldn't figure out a type, just write `null`.
138         let mut iter = self.inputs.iter();
139         if match self.output {
140             Some(ref output) => iter.chain(output.iter()).any(|ref i| i.ty.name.is_none()),
141             None => iter.any(|ref i| i.ty.name.is_none()),
142         } {
143             serializer.serialize_none()
144         } else {
145             let mut seq = serializer.serialize_seq(None)?;
146             seq.serialize_element(&self.inputs)?;
147             if let Some(output) = &self.output {
148                 if output.len() > 1 {
149                     seq.serialize_element(&output)?;
150                 } else {
151                     seq.serialize_element(&output[0])?;
152                 }
153             }
154             seq.end()
155         }
156     }
157 }
158
159 #[derive(Debug)]
160 crate struct TypeWithKind {
161     ty: RenderType,
162     kind: ItemType,
163 }
164
165 impl From<(RenderType, ItemType)> for TypeWithKind {
166     fn from(x: (RenderType, ItemType)) -> TypeWithKind {
167         TypeWithKind { ty: x.0, kind: x.1 }
168     }
169 }
170
171 impl Serialize for TypeWithKind {
172     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
173     where
174         S: Serializer,
175     {
176         (&self.ty.name, self.kind).serialize(serializer)
177     }
178 }
179
180 #[derive(Debug, Clone)]
181 crate struct StylePath {
182     /// The path to the theme
183     crate path: PathBuf,
184     /// What the `disabled` attribute should be set to in the HTML tag
185     crate disabled: bool,
186 }
187
188 fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
189     if let Some(l) = cx.src_href(item) {
190         write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">[src]</a>", l)
191     }
192 }
193
194 #[derive(Debug, Eq, PartialEq, Hash)]
195 struct ItemEntry {
196     url: String,
197     name: String,
198 }
199
200 impl ItemEntry {
201     fn new(mut url: String, name: String) -> ItemEntry {
202         while url.starts_with('/') {
203             url.remove(0);
204         }
205         ItemEntry { url, name }
206     }
207 }
208
209 impl ItemEntry {
210     crate fn print(&self) -> impl fmt::Display + '_ {
211         crate::html::format::display_fn(move |f| {
212             write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))
213         })
214     }
215 }
216
217 impl PartialOrd for ItemEntry {
218     fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
219         Some(self.cmp(other))
220     }
221 }
222
223 impl Ord for ItemEntry {
224     fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
225         self.name.cmp(&other.name)
226     }
227 }
228
229 #[derive(Debug)]
230 struct AllTypes {
231     structs: FxHashSet<ItemEntry>,
232     enums: FxHashSet<ItemEntry>,
233     unions: FxHashSet<ItemEntry>,
234     primitives: FxHashSet<ItemEntry>,
235     traits: FxHashSet<ItemEntry>,
236     macros: FxHashSet<ItemEntry>,
237     functions: FxHashSet<ItemEntry>,
238     typedefs: FxHashSet<ItemEntry>,
239     opaque_tys: FxHashSet<ItemEntry>,
240     statics: FxHashSet<ItemEntry>,
241     constants: FxHashSet<ItemEntry>,
242     keywords: FxHashSet<ItemEntry>,
243     attributes: FxHashSet<ItemEntry>,
244     derives: FxHashSet<ItemEntry>,
245     trait_aliases: FxHashSet<ItemEntry>,
246 }
247
248 impl AllTypes {
249     fn new() -> AllTypes {
250         let new_set = |cap| FxHashSet::with_capacity_and_hasher(cap, Default::default());
251         AllTypes {
252             structs: new_set(100),
253             enums: new_set(100),
254             unions: new_set(100),
255             primitives: new_set(26),
256             traits: new_set(100),
257             macros: new_set(100),
258             functions: new_set(100),
259             typedefs: new_set(100),
260             opaque_tys: new_set(100),
261             statics: new_set(100),
262             constants: new_set(100),
263             keywords: new_set(100),
264             attributes: new_set(100),
265             derives: new_set(100),
266             trait_aliases: new_set(100),
267         }
268     }
269
270     fn append(&mut self, item_name: String, item_type: &ItemType) {
271         let mut url: Vec<_> = item_name.split("::").skip(1).collect();
272         if let Some(name) = url.pop() {
273             let new_url = format!("{}/{}.{}.html", url.join("/"), item_type, name);
274             url.push(name);
275             let name = url.join("::");
276             match *item_type {
277                 ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
278                 ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
279                 ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
280                 ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
281                 ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
282                 ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
283                 ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
284                 ItemType::Typedef => self.typedefs.insert(ItemEntry::new(new_url, name)),
285                 ItemType::OpaqueTy => self.opaque_tys.insert(ItemEntry::new(new_url, name)),
286                 ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
287                 ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
288                 ItemType::ProcAttribute => self.attributes.insert(ItemEntry::new(new_url, name)),
289                 ItemType::ProcDerive => self.derives.insert(ItemEntry::new(new_url, name)),
290                 ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
291                 _ => true,
292             };
293         }
294     }
295 }
296
297 impl AllTypes {
298     fn print(self, f: &mut Buffer) {
299         fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &str) {
300             if !e.is_empty() {
301                 let mut e: Vec<&ItemEntry> = e.iter().collect();
302                 e.sort();
303                 write!(
304                     f,
305                     "<h3 id=\"{}\">{}</h3><ul class=\"{} docblock\">",
306                     title.replace(' ', "-"), // IDs cannot contain whitespaces.
307                     title,
308                     class
309                 );
310
311                 for s in e.iter() {
312                     write!(f, "<li>{}</li>", s.print());
313                 }
314
315                 f.write_str("</ul>");
316             }
317         }
318
319         f.write_str(
320             "<h1 class=\"fqn\">\
321                  <span class=\"in-band\">List of all items</span>\
322                  <span class=\"out-of-band\">\
323                      <span id=\"render-detail\">\
324                          <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
325                             title=\"collapse all docs\">\
326                              [<span class=\"inner\">&#x2212;</span>]\
327                          </a>\
328                      </span>
329                  </span>
330              </h1>",
331         );
332         // Note: print_entries does not escape the title, because we know the current set of titles
333         // doesn't require escaping.
334         print_entries(f, &self.structs, "Structs", "structs");
335         print_entries(f, &self.enums, "Enums", "enums");
336         print_entries(f, &self.unions, "Unions", "unions");
337         print_entries(f, &self.primitives, "Primitives", "primitives");
338         print_entries(f, &self.traits, "Traits", "traits");
339         print_entries(f, &self.macros, "Macros", "macros");
340         print_entries(f, &self.attributes, "Attribute Macros", "attributes");
341         print_entries(f, &self.derives, "Derive Macros", "derives");
342         print_entries(f, &self.functions, "Functions", "functions");
343         print_entries(f, &self.typedefs, "Typedefs", "typedefs");
344         print_entries(f, &self.trait_aliases, "Trait Aliases", "trait-aliases");
345         print_entries(f, &self.opaque_tys, "Opaque Types", "opaque-types");
346         print_entries(f, &self.statics, "Statics", "statics");
347         print_entries(f, &self.constants, "Constants", "constants")
348     }
349 }
350
351 #[derive(Debug)]
352 enum Setting {
353     Section {
354         description: &'static str,
355         sub_settings: Vec<Setting>,
356     },
357     Toggle {
358         js_data_name: &'static str,
359         description: &'static str,
360         default_value: bool,
361     },
362     Select {
363         js_data_name: &'static str,
364         description: &'static str,
365         default_value: &'static str,
366         options: Vec<(String, String)>,
367     },
368 }
369
370 impl Setting {
371     fn display(&self, root_path: &str, suffix: &str) -> String {
372         match *self {
373             Setting::Section { description, ref sub_settings } => format!(
374                 "<div class=\"setting-line\">\
375                      <div class=\"title\">{}</div>\
376                      <div class=\"sub-settings\">{}</div>
377                  </div>",
378                 description,
379                 sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>()
380             ),
381             Setting::Toggle { js_data_name, description, default_value } => format!(
382                 "<div class=\"setting-line\">\
383                      <label class=\"toggle\">\
384                      <input type=\"checkbox\" id=\"{}\" {}>\
385                      <span class=\"slider\"></span>\
386                      </label>\
387                      <div>{}</div>\
388                  </div>",
389                 js_data_name,
390                 if default_value { " checked" } else { "" },
391                 description,
392             ),
393             Setting::Select { js_data_name, description, default_value, ref options } => format!(
394                 "<div class=\"setting-line\">\
395                      <div>{}</div>\
396                      <label class=\"select-wrapper\">\
397                          <select id=\"{}\" autocomplete=\"off\">{}</select>\
398                          <img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\
399                      </label>\
400                  </div>",
401                 description,
402                 js_data_name,
403                 options
404                     .iter()
405                     .map(|opt| format!(
406                         "<option value=\"{}\" {}>{}</option>",
407                         opt.0,
408                         if opt.0 == default_value { "selected" } else { "" },
409                         opt.1,
410                     ))
411                     .collect::<String>(),
412                 root_path,
413                 suffix,
414             ),
415         }
416     }
417 }
418
419 impl From<(&'static str, &'static str, bool)> for Setting {
420     fn from(values: (&'static str, &'static str, bool)) -> Setting {
421         Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 }
422     }
423 }
424
425 impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
426     fn from(values: (&'static str, Vec<T>)) -> Setting {
427         Setting::Section {
428             description: values.0,
429             sub_settings: values.1.into_iter().map(|v| v.into()).collect::<Vec<_>>(),
430         }
431     }
432 }
433
434 fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> {
435     let theme_names: Vec<(String, String)> = themes
436         .iter()
437         .map(|entry| {
438             let theme =
439                 try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path)
440                     .to_string();
441
442             Ok((theme.clone(), theme))
443         })
444         .collect::<Result<_, Error>>()?;
445
446     // (id, explanation, default value)
447     let settings: &[Setting] = &[
448         (
449             "Theme preferences",
450             vec![
451                 Setting::from(("use-system-theme", "Use system theme", true)),
452                 Setting::Select {
453                     js_data_name: "preferred-dark-theme",
454                     description: "Preferred dark theme",
455                     default_value: "dark",
456                     options: theme_names.clone(),
457                 },
458                 Setting::Select {
459                     js_data_name: "preferred-light-theme",
460                     description: "Preferred light theme",
461                     default_value: "light",
462                     options: theme_names,
463                 },
464             ],
465         )
466             .into(),
467         ("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
468         ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
469         ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
470             .into(),
471         ("go-to-only-result", "Directly go to item in search if there is only one result", false)
472             .into(),
473         ("line-numbers", "Show line numbers on code examples", false).into(),
474         ("disable-shortcuts", "Disable keyboard shortcuts", false).into(),
475     ];
476
477     Ok(format!(
478         "<h1 class=\"fqn\">\
479             <span class=\"in-band\">Rustdoc settings</span>\
480         </h1>\
481         <div class=\"settings\">{}</div>\
482         <script src=\"{}settings{}.js\"></script>",
483         settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(),
484         root_path,
485         suffix
486     ))
487 }
488
489 fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option<&clean::Item>) {
490     if let Some(ref name) = item.name {
491         info!("Documenting {}", name);
492     }
493     document_item_info(w, cx, item, parent);
494     if parent.is_none() {
495         document_full_collapsible(w, item, cx);
496     } else {
497         document_full(w, item, cx);
498     }
499 }
500
501 /// Render md_text as markdown.
502 fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec<RenderedLink>) {
503     let mut ids = cx.id_map.borrow_mut();
504     write!(
505         w,
506         "<div class=\"docblock\">{}</div>",
507         Markdown(
508             md_text,
509             &links,
510             &mut ids,
511             cx.shared.codes,
512             cx.shared.edition(),
513             &cx.shared.playground
514         )
515         .into_string()
516     )
517 }
518
519 /// Writes a documentation block containing only the first paragraph of the documentation. If the
520 /// docs are longer, a "Read more" link is appended to the end.
521 fn document_short(
522     w: &mut Buffer,
523     item: &clean::Item,
524     cx: &Context<'_>,
525     link: AssocItemLink<'_>,
526     parent: &clean::Item,
527     show_def_docs: bool,
528 ) {
529     document_item_info(w, cx, item, Some(parent));
530     if !show_def_docs {
531         return;
532     }
533     if let Some(s) = item.doc_value() {
534         let mut summary_html = MarkdownSummaryLine(&s, &item.links(cx)).into_string();
535
536         if s.contains('\n') {
537             let link = format!(r#" <a href="{}">Read more</a>"#, naive_assoc_href(item, link, cx));
538
539             if let Some(idx) = summary_html.rfind("</p>") {
540                 summary_html.insert_str(idx, &link);
541             } else {
542                 summary_html.push_str(&link);
543             }
544         }
545
546         write!(w, "<div class='docblock'>{}</div>", summary_html,);
547     }
548 }
549
550 fn document_full_collapsible(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
551     document_full_inner(w, item, cx, true);
552 }
553
554 fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
555     document_full_inner(w, item, cx, false);
556 }
557
558 fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_collapsible: bool) {
559     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
560         debug!("Doc block: =====\n{}\n=====", s);
561         if is_collapsible {
562             w.write_str(
563                 "<details class=\"rustdoc-toggle top-doc\" open>\
564                 <summary class=\"hideme\">\
565                      <span>Expand description</span>\
566                 </summary>",
567             );
568             render_markdown(w, cx, &s, item.links(cx));
569             w.write_str("</details>");
570         } else {
571             render_markdown(w, cx, &s, item.links(cx));
572         }
573     }
574 }
575
576 /// Add extra information about an item such as:
577 ///
578 /// * Stability
579 /// * Deprecated
580 /// * Required features (through the `doc_cfg` feature)
581 fn document_item_info(
582     w: &mut Buffer,
583     cx: &Context<'_>,
584     item: &clean::Item,
585     parent: Option<&clean::Item>,
586 ) {
587     let item_infos = short_item_info(item, cx, parent);
588     if !item_infos.is_empty() {
589         w.write_str("<div class=\"item-info\">");
590         for info in item_infos {
591             w.write_str(&info);
592         }
593         w.write_str("</div>");
594     }
595 }
596
597 fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
598     let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) {
599         (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
600         (cfg, _) => cfg.as_deref().cloned(),
601     };
602
603     debug!("Portability {:?} - {:?} = {:?}", item.cfg, parent.and_then(|p| p.cfg.as_ref()), cfg);
604
605     Some(format!("<div class=\"stab portability\">{}</div>", cfg?.render_long_html()))
606 }
607
608 /// Render the stability, deprecation and portability information that is displayed at the top of
609 /// the item's documentation.
610 fn short_item_info(
611     item: &clean::Item,
612     cx: &Context<'_>,
613     parent: Option<&clean::Item>,
614 ) -> Vec<String> {
615     let mut extra_info = vec![];
616     let error_codes = cx.shared.codes;
617
618     if let Some(Deprecation { note, since, is_since_rustc_version, suggestion: _ }) =
619         item.deprecation(cx.tcx())
620     {
621         // We display deprecation messages for #[deprecated] and #[rustc_deprecated]
622         // but only display the future-deprecation messages for #[rustc_deprecated].
623         let mut message = if let Some(since) = since {
624             let since = &since.as_str();
625             if !stability::deprecation_in_effect(is_since_rustc_version, Some(since)) {
626                 if *since == "TBD" {
627                     String::from("Deprecating in a future Rust version")
628                 } else {
629                     format!("Deprecating in {}", Escape(since))
630                 }
631             } else {
632                 format!("Deprecated since {}", Escape(since))
633             }
634         } else {
635             String::from("Deprecated")
636         };
637
638         if let Some(note) = note {
639             let note = note.as_str();
640             let mut ids = cx.id_map.borrow_mut();
641             let html = MarkdownHtml(
642                 &note,
643                 &mut ids,
644                 error_codes,
645                 cx.shared.edition(),
646                 &cx.shared.playground,
647             );
648             message.push_str(&format!(": {}", html.into_string()));
649         }
650         extra_info.push(format!(
651             "<div class=\"stab deprecated\"><span class=\"emoji\">👎</span> {}</div>",
652             message,
653         ));
654     }
655
656     // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
657     // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
658     if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item
659         .stability(cx.tcx())
660         .as_ref()
661         .filter(|stab| stab.feature != sym::rustc_private)
662         .map(|stab| (stab.level, stab.feature))
663     {
664         let mut message =
665             "<span class=\"emoji\">🔬</span> This is a nightly-only experimental API.".to_owned();
666
667         let mut feature = format!("<code>{}</code>", Escape(&feature.as_str()));
668         if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) {
669             feature.push_str(&format!(
670                 "&nbsp;<a href=\"{url}{issue}\">#{issue}</a>",
671                 url = url,
672                 issue = issue
673             ));
674         }
675
676         message.push_str(&format!(" ({})", feature));
677
678         if let Some(unstable_reason) = reason {
679             let mut ids = cx.id_map.borrow_mut();
680             message = format!(
681                 "<details><summary>{}</summary>{}</details>",
682                 message,
683                 MarkdownHtml(
684                     &unstable_reason.as_str(),
685                     &mut ids,
686                     error_codes,
687                     cx.shared.edition(),
688                     &cx.shared.playground,
689                 )
690                 .into_string()
691             );
692         }
693
694         extra_info.push(format!("<div class=\"stab unstable\">{}</div>", message));
695     }
696
697     if let Some(portability) = portability(item, parent) {
698         extra_info.push(portability);
699     }
700
701     extra_info
702 }
703
704 // Render the list of items inside one of the sections "Trait Implementations",
705 // "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
706 fn render_impls(
707     cx: &Context<'_>,
708     w: &mut Buffer,
709     traits: &[&&Impl],
710     containing_item: &clean::Item,
711 ) {
712     let cache = cx.cache();
713     let tcx = cx.tcx();
714     let mut impls = traits
715         .iter()
716         .map(|i| {
717             let did = i.trait_did_full(cache).unwrap();
718             let provided_trait_methods = i.inner_impl().provided_trait_methods(tcx);
719             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
720             let mut buffer = if w.is_for_html() { Buffer::html() } else { Buffer::new() };
721             render_impl(
722                 &mut buffer,
723                 cx,
724                 i,
725                 containing_item,
726                 assoc_link,
727                 RenderMode::Normal,
728                 true,
729                 None,
730                 false,
731                 true,
732                 &[],
733             );
734             buffer.into_inner()
735         })
736         .collect::<Vec<_>>();
737     impls.sort();
738     w.write_str(&impls.join(""));
739 }
740
741 fn naive_assoc_href(it: &clean::Item, link: AssocItemLink<'_>, cx: &Context<'_>) -> String {
742     use crate::formats::item_type::ItemType::*;
743
744     let name = it.name.as_ref().unwrap();
745     let ty = match it.type_() {
746         Typedef | AssocType => AssocType,
747         s => s,
748     };
749
750     let anchor = format!("#{}.{}", ty, name);
751     match link {
752         AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
753         AssocItemLink::Anchor(None) => anchor,
754         AssocItemLink::GotoSource(did, _) => {
755             href(did.expect_real(), cx).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
756         }
757     }
758 }
759
760 fn assoc_const(
761     w: &mut Buffer,
762     it: &clean::Item,
763     ty: &clean::Type,
764     _default: Option<&String>,
765     link: AssocItemLink<'_>,
766     extra: &str,
767     cx: &Context<'_>,
768 ) {
769     write!(
770         w,
771         "{}{}const <a href=\"{}\" class=\"constant\"><b>{}</b></a>: {}",
772         extra,
773         it.visibility.print_with_space(it.def_id, cx),
774         naive_assoc_href(it, link, cx),
775         it.name.as_ref().unwrap(),
776         ty.print(cx)
777     );
778 }
779
780 fn assoc_type(
781     w: &mut Buffer,
782     it: &clean::Item,
783     bounds: &[clean::GenericBound],
784     default: Option<&clean::Type>,
785     link: AssocItemLink<'_>,
786     extra: &str,
787     cx: &Context<'_>,
788 ) {
789     write!(
790         w,
791         "{}type <a href=\"{}\" class=\"type\">{}</a>",
792         extra,
793         naive_assoc_href(it, link, cx),
794         it.name.as_ref().unwrap()
795     );
796     if !bounds.is_empty() {
797         write!(w, ": {}", print_generic_bounds(bounds, cx))
798     }
799     if let Some(default) = default {
800         write!(w, " = {}", default.print(cx))
801     }
802 }
803
804 fn render_stability_since_raw(
805     w: &mut Buffer,
806     ver: Option<&str>,
807     const_stability: Option<&ConstStability>,
808     containing_ver: Option<&str>,
809     containing_const_ver: Option<&str>,
810 ) {
811     let ver = ver.filter(|inner| !inner.is_empty());
812
813     match (ver, const_stability) {
814         // stable and const stable
815         (Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. }))
816             if Some(since.as_str()).as_deref() != containing_const_ver =>
817         {
818             write!(
819                 w,
820                 "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
821                 v, since
822             );
823         }
824         // stable and const unstable
825         (
826             Some(v),
827             Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }),
828         ) => {
829             write!(
830                 w,
831                 "<span class=\"since\" title=\"Stable since Rust version {0}, const unstable\">{0} (const: ",
832                 v
833             );
834             if let Some(n) = issue {
835                 write!(
836                     w,
837                     "<a href=\"https://github.com/rust-lang/rust/issues/{}\" title=\"Tracking issue for {}\">unstable</a>",
838                     n, feature
839                 );
840             } else {
841                 write!(w, "unstable");
842             }
843             write!(w, ")</span>");
844         }
845         // stable
846         (Some(v), _) if ver != containing_ver => {
847             write!(
848                 w,
849                 "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
850                 v
851             );
852         }
853         _ => {}
854     }
855 }
856
857 fn render_assoc_item(
858     w: &mut Buffer,
859     item: &clean::Item,
860     link: AssocItemLink<'_>,
861     parent: ItemType,
862     cx: &Context<'_>,
863 ) {
864     fn method(
865         w: &mut Buffer,
866         meth: &clean::Item,
867         header: hir::FnHeader,
868         g: &clean::Generics,
869         d: &clean::FnDecl,
870         link: AssocItemLink<'_>,
871         parent: ItemType,
872         cx: &Context<'_>,
873     ) {
874         let name = meth.name.as_ref().unwrap();
875         let href = match link {
876             AssocItemLink::Anchor(Some(ref id)) => format!("#{}", id),
877             AssocItemLink::Anchor(None) => format!("#{}.{}", meth.type_(), name),
878             AssocItemLink::GotoSource(did, provided_methods) => {
879                 // We're creating a link from an impl-item to the corresponding
880                 // trait-item and need to map the anchored type accordingly.
881                 let ty = if provided_methods.contains(&name) {
882                     ItemType::Method
883                 } else {
884                     ItemType::TyMethod
885                 };
886
887                 href(did.expect_real(), cx)
888                     .map(|p| format!("{}#{}.{}", p.0, ty, name))
889                     .unwrap_or_else(|| format!("#{}.{}", ty, name))
890             }
891         };
892         let vis = meth.visibility.print_with_space(meth.def_id, cx).to_string();
893         let constness =
894             print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()));
895         let asyncness = header.asyncness.print_with_space();
896         let unsafety = header.unsafety.print_with_space();
897         let defaultness = print_default_space(meth.is_default());
898         let abi = print_abi_with_space(header.abi).to_string();
899
900         // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
901         let generics_len = format!("{:#}", g.print(cx)).len();
902         let mut header_len = "fn ".len()
903             + vis.len()
904             + constness.len()
905             + asyncness.len()
906             + unsafety.len()
907             + defaultness.len()
908             + abi.len()
909             + name.as_str().len()
910             + generics_len;
911
912         let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
913             header_len += 4;
914             let indent_str = "    ";
915             render_attributes_in_pre(w, meth, indent_str);
916             (4, indent_str, false)
917         } else {
918             render_attributes_in_code(w, meth);
919             (0, "", true)
920         };
921         w.reserve(header_len + "<a href=\"\" class=\"fnname\">{".len() + "</a>".len());
922         write!(
923             w,
924             "{indent}{vis}{constness}{asyncness}{unsafety}{defaultness}{abi}fn <a href=\"{href}\" class=\"fnname\">{name}</a>\
925              {generics}{decl}{notable_traits}{where_clause}",
926             indent = indent_str,
927             vis = vis,
928             constness = constness,
929             asyncness = asyncness,
930             unsafety = unsafety,
931             defaultness = defaultness,
932             abi = abi,
933             href = href,
934             name = name,
935             generics = g.print(cx),
936             decl = d.full_print(header_len, indent, header.asyncness, cx),
937             notable_traits = notable_traits_decl(&d, cx),
938             where_clause = print_where_clause(g, cx, indent, end_newline),
939         )
940     }
941     match *item.kind {
942         clean::StrippedItem(..) => {}
943         clean::TyMethodItem(ref m) => {
944             method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
945         }
946         clean::MethodItem(ref m, _) => {
947             method(w, item, m.header, &m.generics, &m.decl, link, parent, cx)
948         }
949         clean::AssocConstItem(ref ty, ref default) => assoc_const(
950             w,
951             item,
952             ty,
953             default.as_ref(),
954             link,
955             if parent == ItemType::Trait { "    " } else { "" },
956             cx,
957         ),
958         clean::AssocTypeItem(ref bounds, ref default) => assoc_type(
959             w,
960             item,
961             bounds,
962             default.as_ref(),
963             link,
964             if parent == ItemType::Trait { "    " } else { "" },
965             cx,
966         ),
967         _ => panic!("render_assoc_item called on non-associated-item"),
968     }
969 }
970
971 const ALLOWED_ATTRIBUTES: &[Symbol] =
972     &[sym::export_name, sym::link_section, sym::no_mangle, sym::repr, sym::non_exhaustive];
973
974 fn attributes(it: &clean::Item) -> Vec<String> {
975     it.attrs
976         .other_attrs
977         .iter()
978         .filter_map(|attr| {
979             if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
980                 Some(pprust::attribute_to_string(&attr).replace("\n", "").replace("  ", " "))
981             } else {
982                 None
983             }
984         })
985         .collect()
986 }
987
988 // When an attribute is rendered inside a `<pre>` tag, it is formatted using
989 // a whitespace prefix and newline.
990 fn render_attributes_in_pre(w: &mut Buffer, it: &clean::Item, prefix: &str) {
991     for a in attributes(it) {
992         writeln!(w, "{}{}", prefix, a);
993     }
994 }
995
996 // When an attribute is rendered inside a <code> tag, it is formatted using
997 // a div to produce a newline after it.
998 fn render_attributes_in_code(w: &mut Buffer, it: &clean::Item) {
999     for a in attributes(it) {
1000         write!(w, "<div class=\"code-attribute\">{}</div>", a);
1001     }
1002 }
1003
1004 #[derive(Copy, Clone)]
1005 enum AssocItemLink<'a> {
1006     Anchor(Option<&'a str>),
1007     GotoSource(FakeDefId, &'a FxHashSet<Symbol>),
1008 }
1009
1010 impl<'a> AssocItemLink<'a> {
1011     fn anchor(&self, id: &'a str) -> Self {
1012         match *self {
1013             AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(&id)),
1014             ref other => *other,
1015         }
1016     }
1017 }
1018
1019 fn render_assoc_items(
1020     w: &mut Buffer,
1021     cx: &Context<'_>,
1022     containing_item: &clean::Item,
1023     it: DefId,
1024     what: AssocItemRender<'_>,
1025 ) {
1026     info!("Documenting associated items of {:?}", containing_item.name);
1027     let v = match cx.cache.impls.get(&it) {
1028         Some(v) => v,
1029         None => return,
1030     };
1031     let cache = cx.cache();
1032     let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| i.inner_impl().trait_.is_none());
1033     if !non_trait.is_empty() {
1034         let render_mode = match what {
1035             AssocItemRender::All => {
1036                 w.write_str(
1037                     "<h2 id=\"implementations\" class=\"small-section-header\">\
1038                          Implementations<a href=\"#implementations\" class=\"anchor\"></a>\
1039                     </h2>",
1040                 );
1041                 RenderMode::Normal
1042             }
1043             AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
1044                 write!(
1045                     w,
1046                     "<h2 id=\"deref-methods\" class=\"small-section-header\">\
1047                          Methods from {trait_}&lt;Target = {type_}&gt;\
1048                          <a href=\"#deref-methods\" class=\"anchor\"></a>\
1049                      </h2>",
1050                     trait_ = trait_.print(cx),
1051                     type_ = type_.print(cx),
1052                 );
1053                 RenderMode::ForDeref { mut_: deref_mut_ }
1054             }
1055         };
1056         for i in &non_trait {
1057             render_impl(
1058                 w,
1059                 cx,
1060                 i,
1061                 containing_item,
1062                 AssocItemLink::Anchor(None),
1063                 render_mode,
1064                 true,
1065                 None,
1066                 false,
1067                 true,
1068                 &[],
1069             );
1070         }
1071     }
1072     if let AssocItemRender::DerefFor { .. } = what {
1073         return;
1074     }
1075     if !traits.is_empty() {
1076         let deref_impl = traits
1077             .iter()
1078             .find(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did);
1079         if let Some(impl_) = deref_impl {
1080             let has_deref_mut = traits
1081                 .iter()
1082                 .any(|t| t.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_mut_trait_did);
1083             render_deref_methods(w, cx, impl_, containing_item, has_deref_mut);
1084         }
1085         let (synthetic, concrete): (Vec<&&Impl>, Vec<&&Impl>) =
1086             traits.iter().partition(|t| t.inner_impl().synthetic);
1087         let (blanket_impl, concrete): (Vec<&&Impl>, _) =
1088             concrete.into_iter().partition(|t| t.inner_impl().blanket_impl.is_some());
1089
1090         let mut impls = Buffer::empty_from(&w);
1091         render_impls(cx, &mut impls, &concrete, containing_item);
1092         let impls = impls.into_inner();
1093         if !impls.is_empty() {
1094             write!(
1095                 w,
1096                 "<h2 id=\"trait-implementations\" class=\"small-section-header\">\
1097                      Trait Implementations<a href=\"#trait-implementations\" class=\"anchor\"></a>\
1098                  </h2>\
1099                  <div id=\"trait-implementations-list\">{}</div>",
1100                 impls
1101             );
1102         }
1103
1104         if !synthetic.is_empty() {
1105             w.write_str(
1106                 "<h2 id=\"synthetic-implementations\" class=\"small-section-header\">\
1107                      Auto Trait Implementations\
1108                      <a href=\"#synthetic-implementations\" class=\"anchor\"></a>\
1109                  </h2>\
1110                  <div id=\"synthetic-implementations-list\">",
1111             );
1112             render_impls(cx, w, &synthetic, containing_item);
1113             w.write_str("</div>");
1114         }
1115
1116         if !blanket_impl.is_empty() {
1117             w.write_str(
1118                 "<h2 id=\"blanket-implementations\" class=\"small-section-header\">\
1119                      Blanket Implementations\
1120                      <a href=\"#blanket-implementations\" class=\"anchor\"></a>\
1121                  </h2>\
1122                  <div id=\"blanket-implementations-list\">",
1123             );
1124             render_impls(cx, w, &blanket_impl, containing_item);
1125             w.write_str("</div>");
1126         }
1127     }
1128 }
1129
1130 fn render_deref_methods(
1131     w: &mut Buffer,
1132     cx: &Context<'_>,
1133     impl_: &Impl,
1134     container_item: &clean::Item,
1135     deref_mut: bool,
1136 ) {
1137     let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
1138     let (target, real_target) = impl_
1139         .inner_impl()
1140         .items
1141         .iter()
1142         .find_map(|item| match *item.kind {
1143             clean::TypedefItem(ref t, true) => Some(match *t {
1144                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
1145                 _ => (&t.type_, &t.type_),
1146             }),
1147             _ => None,
1148         })
1149         .expect("Expected associated type binding");
1150     debug!("Render deref methods for {:#?}, target {:#?}", impl_.inner_impl().for_, target);
1151     let what =
1152         AssocItemRender::DerefFor { trait_: deref_type, type_: real_target, deref_mut_: deref_mut };
1153     if let Some(did) = target.def_id_full(cx.cache()) {
1154         if let Some(type_did) = impl_.inner_impl().for_.def_id_full(cx.cache()) {
1155             // `impl Deref<Target = S> for S`
1156             if did == type_did {
1157                 // Avoid infinite cycles
1158                 return;
1159             }
1160         }
1161         render_assoc_items(w, cx, container_item, did, what);
1162     } else {
1163         if let Some(prim) = target.primitive_type() {
1164             if let Some(&did) = cx.cache.primitive_locations.get(&prim) {
1165                 render_assoc_items(w, cx, container_item, did, what);
1166             }
1167         }
1168     }
1169 }
1170
1171 fn should_render_item(item: &clean::Item, deref_mut_: bool, cache: &Cache) -> bool {
1172     let self_type_opt = match *item.kind {
1173         clean::MethodItem(ref method, _) => method.decl.self_type(),
1174         clean::TyMethodItem(ref method) => method.decl.self_type(),
1175         _ => None,
1176     };
1177
1178     if let Some(self_ty) = self_type_opt {
1179         let (by_mut_ref, by_box, by_value) = match self_ty {
1180             SelfTy::SelfBorrowed(_, mutability)
1181             | SelfTy::SelfExplicit(clean::BorrowedRef { mutability, .. }) => {
1182                 (mutability == Mutability::Mut, false, false)
1183             }
1184             SelfTy::SelfExplicit(clean::ResolvedPath { did, .. }) => {
1185                 (false, Some(did) == cache.owned_box_did, false)
1186             }
1187             SelfTy::SelfValue => (false, false, true),
1188             _ => (false, false, false),
1189         };
1190
1191         (deref_mut_ || !by_mut_ref) && !by_box && !by_value
1192     } else {
1193         false
1194     }
1195 }
1196
1197 fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
1198     let mut out = Buffer::html();
1199     let mut trait_ = String::new();
1200
1201     if let Some(did) = decl.output.def_id_full(cx.cache()) {
1202         if let Some(impls) = cx.cache().impls.get(&did) {
1203             for i in impls {
1204                 let impl_ = i.inner_impl();
1205                 if impl_.trait_.def_id().map_or(false, |d| {
1206                     cx.cache().traits.get(&d).map(|t| t.is_notable).unwrap_or(false)
1207                 }) {
1208                     if out.is_empty() {
1209                         write!(
1210                             &mut out,
1211                             "<h3 class=\"notable\">Notable traits for {}</h3>\
1212                              <code class=\"content\">",
1213                             impl_.for_.print(cx)
1214                         );
1215                         trait_.push_str(&impl_.for_.print(cx).to_string());
1216                     }
1217
1218                     //use the "where" class here to make it small
1219                     write!(
1220                         &mut out,
1221                         "<span class=\"where fmt-newline\">{}</span>",
1222                         impl_.print(false, cx)
1223                     );
1224                     let t_did = impl_.trait_.def_id_full(cx.cache()).unwrap();
1225                     for it in &impl_.items {
1226                         if let clean::TypedefItem(ref tydef, _) = *it.kind {
1227                             out.push_str("<span class=\"where fmt-newline\">    ");
1228                             assoc_type(
1229                                 &mut out,
1230                                 it,
1231                                 &[],
1232                                 Some(&tydef.type_),
1233                                 AssocItemLink::GotoSource(t_did.into(), &FxHashSet::default()),
1234                                 "",
1235                                 cx,
1236                             );
1237                             out.push_str(";</span>");
1238                         }
1239                     }
1240                 }
1241             }
1242         }
1243     }
1244
1245     if !out.is_empty() {
1246         out.insert_str(
1247             0,
1248             "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
1249             <div class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
1250         );
1251         out.push_str("</code></span></div></span></span>");
1252     }
1253
1254     out.into_inner()
1255 }
1256
1257 fn render_impl(
1258     w: &mut Buffer,
1259     cx: &Context<'_>,
1260     i: &Impl,
1261     parent: &clean::Item,
1262     link: AssocItemLink<'_>,
1263     render_mode: RenderMode,
1264     show_def_docs: bool,
1265     use_absolute: Option<bool>,
1266     is_on_foreign_type: bool,
1267     show_default_items: bool,
1268     // This argument is used to reference same type with different paths to avoid duplication
1269     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
1270     aliases: &[String],
1271 ) {
1272     let cache = cx.cache();
1273     let traits = &cache.traits;
1274     let trait_ = i.trait_did_full(cache).map(|did| &traits[&did]);
1275     let mut close_tags = String::new();
1276
1277     // For trait implementations, the `interesting` output contains all methods that have doc
1278     // comments, and the `boring` output contains all methods that do not. The distinction is
1279     // used to allow hiding the boring methods.
1280     // `containing_item` is used for rendering stability info. If the parent is a trait impl,
1281     // `containing_item` will the grandparent, since trait impls can't have stability attached.
1282     fn doc_impl_item(
1283         boring: &mut Buffer,
1284         interesting: &mut Buffer,
1285         cx: &Context<'_>,
1286         item: &clean::Item,
1287         parent: &clean::Item,
1288         containing_item: &clean::Item,
1289         link: AssocItemLink<'_>,
1290         render_mode: RenderMode,
1291         is_default_item: bool,
1292         trait_: Option<&clean::Trait>,
1293         show_def_docs: bool,
1294     ) {
1295         let item_type = item.type_();
1296         let name = item.name.as_ref().unwrap();
1297
1298         let render_method_item = match render_mode {
1299             RenderMode::Normal => true,
1300             RenderMode::ForDeref { mut_: deref_mut_ } => {
1301                 should_render_item(&item, deref_mut_, &cx.cache)
1302             }
1303         };
1304
1305         let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
1306
1307         let mut doc_buffer = Buffer::empty_from(boring);
1308         let mut info_buffer = Buffer::empty_from(boring);
1309         let mut short_documented = true;
1310
1311         if render_method_item {
1312             if !is_default_item {
1313                 if let Some(t) = trait_ {
1314                     // The trait item may have been stripped so we might not
1315                     // find any documentation or stability for it.
1316                     if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
1317                         // We need the stability of the item from the trait
1318                         // because impls can't have a stability.
1319                         if item.doc_value().is_some() {
1320                             document_item_info(&mut info_buffer, cx, it, Some(parent));
1321                             document_full(&mut doc_buffer, item, cx);
1322                             short_documented = false;
1323                         } else {
1324                             // In case the item isn't documented,
1325                             // provide short documentation from the trait.
1326                             document_short(&mut doc_buffer, it, cx, link, parent, show_def_docs);
1327                         }
1328                     }
1329                 } else {
1330                     document_item_info(&mut info_buffer, cx, item, Some(parent));
1331                     if show_def_docs {
1332                         document_full(&mut doc_buffer, item, cx);
1333                         short_documented = false;
1334                     }
1335                 }
1336             } else {
1337                 document_short(&mut doc_buffer, item, cx, link, parent, show_def_docs);
1338             }
1339         }
1340         let w = if short_documented && trait_.is_some() { interesting } else { boring };
1341
1342         let toggled = !doc_buffer.is_empty();
1343         if toggled {
1344             let method_toggle_class =
1345                 if item_type == ItemType::Method { " method-toggle" } else { "" };
1346             write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class);
1347         }
1348         match *item.kind {
1349             clean::MethodItem(..) | clean::TyMethodItem(_) => {
1350                 // Only render when the method is not static or we allow static methods
1351                 if render_method_item {
1352                     let id = cx.derive_id(format!("{}.{}", item_type, name));
1353                     let source_id = trait_
1354                         .and_then(|trait_| {
1355                             trait_.items.iter().find(|item| {
1356                                 item.name.map(|n| n.as_str().eq(&name.as_str())).unwrap_or(false)
1357                             })
1358                         })
1359                         .map(|item| format!("{}.{}", item.type_(), name));
1360                     write!(
1361                         w,
1362                         "<div id=\"{}\" class=\"{}{} has-srclink\">",
1363                         id, item_type, in_trait_class,
1364                     );
1365                     render_rightside(w, cx, item, containing_item);
1366                     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1367                     w.write_str("<code>");
1368                     render_assoc_item(
1369                         w,
1370                         item,
1371                         link.anchor(source_id.as_ref().unwrap_or(&id)),
1372                         ItemType::Impl,
1373                         cx,
1374                     );
1375                     w.write_str("</code>");
1376                     w.write_str("</div>");
1377                 }
1378             }
1379             clean::TypedefItem(ref tydef, _) => {
1380                 let source_id = format!("{}.{}", ItemType::AssocType, name);
1381                 let id = cx.derive_id(source_id.clone());
1382                 write!(
1383                     w,
1384                     "<div id=\"{}\" class=\"{}{} has-srclink\">",
1385                     id, item_type, in_trait_class
1386                 );
1387                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1388                 w.write_str("<code>");
1389                 assoc_type(
1390                     w,
1391                     item,
1392                     &Vec::new(),
1393                     Some(&tydef.type_),
1394                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1395                     "",
1396                     cx,
1397                 );
1398                 w.write_str("</code>");
1399                 w.write_str("</div>");
1400             }
1401             clean::AssocConstItem(ref ty, ref default) => {
1402                 let source_id = format!("{}.{}", item_type, name);
1403                 let id = cx.derive_id(source_id.clone());
1404                 write!(
1405                     w,
1406                     "<div id=\"{}\" class=\"{}{} has-srclink\">",
1407                     id, item_type, in_trait_class
1408                 );
1409                 render_rightside(w, cx, item, containing_item);
1410                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1411                 w.write_str("<code>");
1412                 assoc_const(
1413                     w,
1414                     item,
1415                     ty,
1416                     default.as_ref(),
1417                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1418                     "",
1419                     cx,
1420                 );
1421                 w.write_str("</code>");
1422                 w.write_str("</div>");
1423             }
1424             clean::AssocTypeItem(ref bounds, ref default) => {
1425                 let source_id = format!("{}.{}", item_type, name);
1426                 let id = cx.derive_id(source_id.clone());
1427                 write!(w, "<div id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
1428                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1429                 w.write_str("<code>");
1430                 assoc_type(
1431                     w,
1432                     item,
1433                     bounds,
1434                     default.as_ref(),
1435                     link.anchor(if trait_.is_some() { &source_id } else { &id }),
1436                     "",
1437                     cx,
1438                 );
1439                 w.write_str("</code>");
1440                 w.write_str("</div>");
1441             }
1442             clean::StrippedItem(..) => return,
1443             _ => panic!("can't make docs for trait item with name {:?}", item.name),
1444         }
1445
1446         w.push_buffer(info_buffer);
1447         if toggled {
1448             w.write_str("</summary>");
1449             w.push_buffer(doc_buffer);
1450             w.push_str("</details>");
1451         }
1452     }
1453
1454     let mut impl_items = Buffer::empty_from(w);
1455     let mut default_impl_items = Buffer::empty_from(w);
1456
1457     for trait_item in &i.inner_impl().items {
1458         doc_impl_item(
1459             &mut default_impl_items,
1460             &mut impl_items,
1461             cx,
1462             trait_item,
1463             if trait_.is_some() { &i.impl_item } else { parent },
1464             parent,
1465             link,
1466             render_mode,
1467             false,
1468             trait_.map(|t| &t.trait_),
1469             show_def_docs,
1470         );
1471     }
1472
1473     fn render_default_items(
1474         boring: &mut Buffer,
1475         interesting: &mut Buffer,
1476         cx: &Context<'_>,
1477         t: &clean::Trait,
1478         i: &clean::Impl,
1479         parent: &clean::Item,
1480         containing_item: &clean::Item,
1481         render_mode: RenderMode,
1482         show_def_docs: bool,
1483     ) {
1484         for trait_item in &t.items {
1485             let n = trait_item.name;
1486             if i.items.iter().any(|m| m.name == n) {
1487                 continue;
1488             }
1489             let did = i.trait_.as_ref().unwrap().def_id_full(cx.cache()).unwrap();
1490             let provided_methods = i.provided_trait_methods(cx.tcx());
1491             let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
1492
1493             doc_impl_item(
1494                 boring,
1495                 interesting,
1496                 cx,
1497                 trait_item,
1498                 parent,
1499                 containing_item,
1500                 assoc_link,
1501                 render_mode,
1502                 true,
1503                 Some(t),
1504                 show_def_docs,
1505             );
1506         }
1507     }
1508
1509     // If we've implemented a trait, then also emit documentation for all
1510     // default items which weren't overridden in the implementation block.
1511     // We don't emit documentation for default items if they appear in the
1512     // Implementations on Foreign Types or Implementors sections.
1513     if show_default_items {
1514         if let Some(t) = trait_ {
1515             render_default_items(
1516                 &mut default_impl_items,
1517                 &mut impl_items,
1518                 cx,
1519                 &t.trait_,
1520                 &i.inner_impl(),
1521                 &i.impl_item,
1522                 parent,
1523                 render_mode,
1524                 show_def_docs,
1525             );
1526         }
1527     }
1528     if render_mode == RenderMode::Normal {
1529         let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
1530         if toggled {
1531             close_tags.insert_str(0, "</details>");
1532             write!(w, "<details class=\"rustdoc-toggle implementors-toggle\" open>");
1533             write!(w, "<summary>")
1534         }
1535         render_impl_summary(
1536             w,
1537             cx,
1538             i,
1539             parent,
1540             parent,
1541             show_def_docs,
1542             use_absolute,
1543             is_on_foreign_type,
1544             aliases,
1545         );
1546         if toggled {
1547             write!(w, "</summary>")
1548         }
1549
1550         if let Some(ref dox) = cx.shared.maybe_collapsed_doc_value(&i.impl_item) {
1551             let mut ids = cx.id_map.borrow_mut();
1552             write!(
1553                 w,
1554                 "<div class=\"docblock\">{}</div>",
1555                 Markdown(
1556                     &*dox,
1557                     &i.impl_item.links(cx),
1558                     &mut ids,
1559                     cx.shared.codes,
1560                     cx.shared.edition(),
1561                     &cx.shared.playground
1562                 )
1563                 .into_string()
1564             );
1565         }
1566     }
1567     if !default_impl_items.is_empty() || !impl_items.is_empty() {
1568         w.write_str("<div class=\"impl-items\">");
1569         w.push_buffer(default_impl_items);
1570         w.push_buffer(impl_items);
1571         close_tags.insert_str(0, "</div>");
1572     }
1573     w.write_str(&close_tags);
1574 }
1575
1576 // Render the items that appear on the right side of methods, impls, and
1577 // associated types. For example "1.0.0 (const: 1.39.0) [src]".
1578 fn render_rightside(
1579     w: &mut Buffer,
1580     cx: &Context<'_>,
1581     item: &clean::Item,
1582     containing_item: &clean::Item,
1583 ) {
1584     let tcx = cx.tcx();
1585
1586     write!(w, "<div class=\"rightside\">");
1587     render_stability_since_raw(
1588         w,
1589         item.stable_since(tcx).as_deref(),
1590         item.const_stability(tcx),
1591         containing_item.stable_since(tcx).as_deref(),
1592         containing_item.const_stable_since(tcx).as_deref(),
1593     );
1594
1595     write_srclink(cx, item, w);
1596     w.write_str("</div>");
1597 }
1598
1599 pub(crate) fn render_impl_summary(
1600     w: &mut Buffer,
1601     cx: &Context<'_>,
1602     i: &Impl,
1603     parent: &clean::Item,
1604     containing_item: &clean::Item,
1605     show_def_docs: bool,
1606     use_absolute: Option<bool>,
1607     is_on_foreign_type: bool,
1608     // This argument is used to reference same type with different paths to avoid duplication
1609     // in documentation pages for trait with automatic implementations like "Send" and "Sync".
1610     aliases: &[String],
1611 ) {
1612     let id = cx.derive_id(match i.inner_impl().trait_ {
1613         Some(ref t) => {
1614             if is_on_foreign_type {
1615                 get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx)
1616             } else {
1617                 format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx))))
1618             }
1619         }
1620         None => "impl".to_string(),
1621     });
1622     let aliases = if aliases.is_empty() {
1623         String::new()
1624     } else {
1625         format!(" data-aliases=\"{}\"", aliases.join(","))
1626     };
1627     write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
1628     render_rightside(w, cx, &i.impl_item, containing_item);
1629     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
1630     write!(w, "<code class=\"in-band\">");
1631
1632     if let Some(use_absolute) = use_absolute {
1633         write!(w, "{}", i.inner_impl().print(use_absolute, cx));
1634         if show_def_docs {
1635             for it in &i.inner_impl().items {
1636                 if let clean::TypedefItem(ref tydef, _) = *it.kind {
1637                     w.write_str("<span class=\"where fmt-newline\">  ");
1638                     assoc_type(w, it, &[], Some(&tydef.type_), AssocItemLink::Anchor(None), "", cx);
1639                     w.write_str(";</span>");
1640                 }
1641             }
1642         }
1643     } else {
1644         write!(w, "{}", i.inner_impl().print(false, cx));
1645     }
1646     write!(w, "</code>");
1647
1648     let is_trait = i.inner_impl().trait_.is_some();
1649     if is_trait {
1650         if let Some(portability) = portability(&i.impl_item, Some(parent)) {
1651             write!(w, "<div class=\"item-info\">{}</div>", portability);
1652         }
1653     }
1654
1655     w.write_str("</div>");
1656 }
1657
1658 fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
1659     let parentlen = cx.current.len() - if it.is_mod() { 1 } else { 0 };
1660
1661     if it.is_struct()
1662         || it.is_trait()
1663         || it.is_primitive()
1664         || it.is_union()
1665         || it.is_enum()
1666         || it.is_mod()
1667         || it.is_typedef()
1668     {
1669         write!(
1670             buffer,
1671             "<p class=\"location\">{}{}</p>",
1672             match *it.kind {
1673                 clean::StructItem(..) => "Struct ",
1674                 clean::TraitItem(..) => "Trait ",
1675                 clean::PrimitiveItem(..) => "Primitive Type ",
1676                 clean::UnionItem(..) => "Union ",
1677                 clean::EnumItem(..) => "Enum ",
1678                 clean::TypedefItem(..) => "Type Definition ",
1679                 clean::ForeignTypeItem => "Foreign Type ",
1680                 clean::ModuleItem(..) =>
1681                     if it.is_crate() {
1682                         "Crate "
1683                     } else {
1684                         "Module "
1685                     },
1686                 _ => "",
1687             },
1688             it.name.as_ref().unwrap()
1689         );
1690     }
1691
1692     if it.is_crate() {
1693         if let Some(ref version) = cx.cache.crate_version {
1694             write!(
1695                 buffer,
1696                 "<div class=\"block version\">\
1697                      <div class=\"narrow-helper\"></div>
1698                      <p>Version {}</p>\
1699                  </div>",
1700                 Escape(version),
1701             );
1702         }
1703     }
1704
1705     buffer.write_str("<div class=\"sidebar-elems\">");
1706     if it.is_crate() {
1707         write!(
1708             buffer,
1709             "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
1710             it.name.as_ref().expect("crates always have a name"),
1711         );
1712     }
1713
1714     match *it.kind {
1715         clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s),
1716         clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t),
1717         clean::PrimitiveItem(_) => sidebar_primitive(cx, buffer, it),
1718         clean::UnionItem(ref u) => sidebar_union(cx, buffer, it, u),
1719         clean::EnumItem(ref e) => sidebar_enum(cx, buffer, it, e),
1720         clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it),
1721         clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items),
1722         clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it),
1723         _ => {}
1724     }
1725
1726     // The sidebar is designed to display sibling functions, modules and
1727     // other miscellaneous information. since there are lots of sibling
1728     // items (and that causes quadratic growth in large modules),
1729     // we refactor common parts into a shared JavaScript file per module.
1730     // still, we don't move everything into JS because we want to preserve
1731     // as much HTML as possible in order to allow non-JS-enabled browsers
1732     // to navigate the documentation (though slightly inefficiently).
1733
1734     if !it.is_mod() {
1735         buffer.write_str("<p class=\"location\">Other items in<br>");
1736         for (i, name) in cx.current.iter().take(parentlen).enumerate() {
1737             if i > 0 {
1738                 buffer.write_str("::<wbr>");
1739             }
1740             write!(
1741                 buffer,
1742                 "<a href=\"{}index.html\">{}</a>",
1743                 &cx.root_path()[..(cx.current.len() - i - 1) * 3],
1744                 *name
1745             );
1746         }
1747         buffer.write_str("</p>");
1748     }
1749
1750     // Sidebar refers to the enclosing module, not this module.
1751     let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" };
1752     write!(
1753         buffer,
1754         "<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\
1755         </div>",
1756         name = it.name.unwrap_or(kw::Empty),
1757         ty = it.type_(),
1758         path = relpath
1759     );
1760     write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
1761     // Closes sidebar-elems div.
1762     buffer.write_str("</div>");
1763 }
1764
1765 fn get_next_url(used_links: &mut FxHashSet<String>, url: String) -> String {
1766     if used_links.insert(url.clone()) {
1767         return url;
1768     }
1769     let mut add = 1;
1770     while !used_links.insert(format!("{}-{}", url, add)) {
1771         add += 1;
1772     }
1773     format!("{}-{}", url, add)
1774 }
1775
1776 fn get_methods(
1777     i: &clean::Impl,
1778     for_deref: bool,
1779     used_links: &mut FxHashSet<String>,
1780     deref_mut: bool,
1781     cache: &Cache,
1782 ) -> Vec<String> {
1783     i.items
1784         .iter()
1785         .filter_map(|item| match item.name {
1786             Some(ref name) if !name.is_empty() && item.is_method() => {
1787                 if !for_deref || should_render_item(item, deref_mut, cache) {
1788                     Some(format!(
1789                         "<a href=\"#{}\">{}</a>",
1790                         get_next_url(used_links, format!("method.{}", name)),
1791                         name
1792                     ))
1793                 } else {
1794                     None
1795                 }
1796             }
1797             _ => None,
1798         })
1799         .collect::<Vec<_>>()
1800 }
1801
1802 // The point is to url encode any potential character from a type with genericity.
1803 fn small_url_encode(s: String) -> String {
1804     let mut st = String::new();
1805     let mut last_match = 0;
1806     for (idx, c) in s.char_indices() {
1807         let escaped = match c {
1808             '<' => "%3C",
1809             '>' => "%3E",
1810             ' ' => "%20",
1811             '?' => "%3F",
1812             '\'' => "%27",
1813             '&' => "%26",
1814             ',' => "%2C",
1815             ':' => "%3A",
1816             ';' => "%3B",
1817             '[' => "%5B",
1818             ']' => "%5D",
1819             '"' => "%22",
1820             _ => continue,
1821         };
1822
1823         st += &s[last_match..idx];
1824         st += escaped;
1825         // NOTE: we only expect single byte characters here - which is fine as long as we
1826         // only match single byte characters
1827         last_match = idx + 1;
1828     }
1829
1830     if last_match != 0 {
1831         st += &s[last_match..];
1832         st
1833     } else {
1834         s
1835     }
1836 }
1837
1838 fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
1839     let did = it.def_id.expect_real();
1840     if let Some(v) = cx.cache.impls.get(&did) {
1841         let mut used_links = FxHashSet::default();
1842         let cache = cx.cache();
1843
1844         {
1845             let used_links_bor = &mut used_links;
1846             let mut ret = v
1847                 .iter()
1848                 .filter(|i| i.inner_impl().trait_.is_none())
1849                 .flat_map(move |i| {
1850                     get_methods(i.inner_impl(), false, used_links_bor, false, &cx.cache)
1851                 })
1852                 .collect::<Vec<_>>();
1853             if !ret.is_empty() {
1854                 // We want links' order to be reproducible so we don't use unstable sort.
1855                 ret.sort();
1856
1857                 out.push_str(
1858                     "<a class=\"sidebar-title\" href=\"#implementations\">Methods</a>\
1859                      <div class=\"sidebar-links\">",
1860                 );
1861                 for line in ret {
1862                     out.push_str(&line);
1863                 }
1864                 out.push_str("</div>");
1865             }
1866         }
1867
1868         if v.iter().any(|i| i.inner_impl().trait_.is_some()) {
1869             if let Some(impl_) = v
1870                 .iter()
1871                 .filter(|i| i.inner_impl().trait_.is_some())
1872                 .find(|i| i.inner_impl().trait_.def_id_full(cache) == cx.cache.deref_trait_did)
1873             {
1874                 sidebar_deref_methods(cx, out, impl_, v);
1875             }
1876
1877             let format_impls = |impls: Vec<&Impl>| {
1878                 let mut links = FxHashSet::default();
1879
1880                 let mut ret = impls
1881                     .iter()
1882                     .filter_map(|it| {
1883                         if let Some(ref i) = it.inner_impl().trait_ {
1884                             let i_display = format!("{:#}", i.print(cx));
1885                             let out = Escape(&i_display);
1886                             let encoded = small_url_encode(format!("{:#}", i.print(cx)));
1887                             let generated = format!(
1888                                 "<a href=\"#impl-{}\">{}{}</a>",
1889                                 encoded,
1890                                 if it.inner_impl().negative_polarity { "!" } else { "" },
1891                                 out
1892                             );
1893                             if links.insert(generated.clone()) { Some(generated) } else { None }
1894                         } else {
1895                             None
1896                         }
1897                     })
1898                     .collect::<Vec<String>>();
1899                 ret.sort();
1900                 ret
1901             };
1902
1903             let write_sidebar_links = |out: &mut Buffer, links: Vec<String>| {
1904                 out.push_str("<div class=\"sidebar-links\">");
1905                 for link in links {
1906                     out.push_str(&link);
1907                 }
1908                 out.push_str("</div>");
1909             };
1910
1911             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
1912                 v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().synthetic);
1913             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) = concrete
1914                 .into_iter()
1915                 .partition::<Vec<_>, _>(|i| i.inner_impl().blanket_impl.is_some());
1916
1917             let concrete_format = format_impls(concrete);
1918             let synthetic_format = format_impls(synthetic);
1919             let blanket_format = format_impls(blanket_impl);
1920
1921             if !concrete_format.is_empty() {
1922                 out.push_str(
1923                     "<a class=\"sidebar-title\" href=\"#trait-implementations\">\
1924                         Trait Implementations</a>",
1925                 );
1926                 write_sidebar_links(out, concrete_format);
1927             }
1928
1929             if !synthetic_format.is_empty() {
1930                 out.push_str(
1931                     "<a class=\"sidebar-title\" href=\"#synthetic-implementations\">\
1932                         Auto Trait Implementations</a>",
1933                 );
1934                 write_sidebar_links(out, synthetic_format);
1935             }
1936
1937             if !blanket_format.is_empty() {
1938                 out.push_str(
1939                     "<a class=\"sidebar-title\" href=\"#blanket-implementations\">\
1940                         Blanket Implementations</a>",
1941                 );
1942                 write_sidebar_links(out, blanket_format);
1943             }
1944         }
1945     }
1946 }
1947
1948 fn sidebar_deref_methods(cx: &Context<'_>, out: &mut Buffer, impl_: &Impl, v: &Vec<Impl>) {
1949     let c = cx.cache();
1950
1951     debug!("found Deref: {:?}", impl_);
1952     if let Some((target, real_target)) =
1953         impl_.inner_impl().items.iter().find_map(|item| match *item.kind {
1954             clean::TypedefItem(ref t, true) => Some(match *t {
1955                 clean::Typedef { item_type: Some(ref type_), .. } => (type_, &t.type_),
1956                 _ => (&t.type_, &t.type_),
1957             }),
1958             _ => None,
1959         })
1960     {
1961         debug!("found target, real_target: {:?} {:?}", target, real_target);
1962         if let Some(did) = target.def_id_full(c) {
1963             if let Some(type_did) = impl_.inner_impl().for_.def_id_full(c) {
1964                 // `impl Deref<Target = S> for S`
1965                 if did == type_did {
1966                     // Avoid infinite cycles
1967                     return;
1968                 }
1969             }
1970         }
1971         let deref_mut = v
1972             .iter()
1973             .filter(|i| i.inner_impl().trait_.is_some())
1974             .any(|i| i.inner_impl().trait_.def_id_full(c) == c.deref_mut_trait_did);
1975         let inner_impl = target
1976             .def_id_full(c)
1977             .or_else(|| {
1978                 target.primitive_type().and_then(|prim| c.primitive_locations.get(&prim).cloned())
1979             })
1980             .and_then(|did| c.impls.get(&did));
1981         if let Some(impls) = inner_impl {
1982             debug!("found inner_impl: {:?}", impls);
1983             let mut used_links = FxHashSet::default();
1984             let mut ret = impls
1985                 .iter()
1986                 .filter(|i| i.inner_impl().trait_.is_none())
1987                 .flat_map(|i| get_methods(i.inner_impl(), true, &mut used_links, deref_mut, c))
1988                 .collect::<Vec<_>>();
1989             if !ret.is_empty() {
1990                 write!(
1991                     out,
1992                     "<a class=\"sidebar-title\" href=\"#deref-methods\">Methods from {}&lt;Target={}&gt;</a>",
1993                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
1994                     Escape(&format!("{:#}", real_target.print(cx))),
1995                 );
1996                 // We want links' order to be reproducible so we don't use unstable sort.
1997                 ret.sort();
1998                 out.push_str("<div class=\"sidebar-links\">");
1999                 for link in ret {
2000                     out.push_str(&link);
2001                 }
2002                 out.push_str("</div>");
2003             }
2004         }
2005     }
2006 }
2007
2008 fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) {
2009     let mut sidebar = Buffer::new();
2010     let fields = get_struct_fields_name(&s.fields);
2011
2012     if !fields.is_empty() {
2013         if let CtorKind::Fictive = s.struct_type {
2014             sidebar.push_str(
2015                 "<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
2016                 <div class=\"sidebar-links\">",
2017             );
2018
2019             for field in fields {
2020                 sidebar.push_str(&field);
2021             }
2022
2023             sidebar.push_str("</div>");
2024         }
2025     }
2026
2027     sidebar_assoc_items(cx, &mut sidebar, it);
2028
2029     if !sidebar.is_empty() {
2030         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2031     }
2032 }
2033
2034 fn get_id_for_impl_on_foreign_type(
2035     for_: &clean::Type,
2036     trait_: &clean::Type,
2037     cx: &Context<'_>,
2038 ) -> String {
2039     small_url_encode(format!("impl-{:#}-for-{:#}", trait_.print(cx), for_.print(cx),))
2040 }
2041
2042 fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
2043     match *item.kind {
2044         clean::ItemKind::ImplItem(ref i) => {
2045             if let Some(ref trait_) = i.trait_ {
2046                 // Alternative format produces no URLs,
2047                 // so this parameter does nothing.
2048                 Some((
2049                     format!("{:#}", i.for_.print(cx)),
2050                     get_id_for_impl_on_foreign_type(&i.for_, trait_, cx),
2051                 ))
2052             } else {
2053                 None
2054             }
2055         }
2056         _ => None,
2057     }
2058 }
2059
2060 fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
2061     buf.write_str("<div class=\"block items\">");
2062
2063     fn print_sidebar_section(
2064         out: &mut Buffer,
2065         items: &[clean::Item],
2066         before: &str,
2067         filter: impl Fn(&clean::Item) -> bool,
2068         write: impl Fn(&mut Buffer, &str),
2069         after: &str,
2070     ) {
2071         let mut items = items
2072             .iter()
2073             .filter_map(|m| match m.name {
2074                 Some(ref name) if filter(m) => Some(name.as_str()),
2075                 _ => None,
2076             })
2077             .collect::<Vec<_>>();
2078
2079         if !items.is_empty() {
2080             items.sort_unstable();
2081             out.push_str(before);
2082             for item in items.into_iter() {
2083                 write(out, &item);
2084             }
2085             out.push_str(after);
2086         }
2087     }
2088
2089     print_sidebar_section(
2090         buf,
2091         &t.items,
2092         "<a class=\"sidebar-title\" href=\"#associated-types\">\
2093             Associated Types</a><div class=\"sidebar-links\">",
2094         |m| m.is_associated_type(),
2095         |out, sym| write!(out, "<a href=\"#associatedtype.{0}\">{0}</a>", sym),
2096         "</div>",
2097     );
2098
2099     print_sidebar_section(
2100         buf,
2101         &t.items,
2102         "<a class=\"sidebar-title\" href=\"#associated-const\">\
2103             Associated Constants</a><div class=\"sidebar-links\">",
2104         |m| m.is_associated_const(),
2105         |out, sym| write!(out, "<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
2106         "</div>",
2107     );
2108
2109     print_sidebar_section(
2110         buf,
2111         &t.items,
2112         "<a class=\"sidebar-title\" href=\"#required-methods\">\
2113             Required Methods</a><div class=\"sidebar-links\">",
2114         |m| m.is_ty_method(),
2115         |out, sym| write!(out, "<a href=\"#tymethod.{0}\">{0}</a>", sym),
2116         "</div>",
2117     );
2118
2119     print_sidebar_section(
2120         buf,
2121         &t.items,
2122         "<a class=\"sidebar-title\" href=\"#provided-methods\">\
2123             Provided Methods</a><div class=\"sidebar-links\">",
2124         |m| m.is_method(),
2125         |out, sym| write!(out, "<a href=\"#method.{0}\">{0}</a>", sym),
2126         "</div>",
2127     );
2128
2129     if let Some(implementors) = cx.cache.implementors.get(&it.def_id.expect_real()) {
2130         let cache = cx.cache();
2131         let mut res = implementors
2132             .iter()
2133             .filter(|i| {
2134                 i.inner_impl()
2135                     .for_
2136                     .def_id_full(cache)
2137                     .map_or(false, |d| !cx.cache.paths.contains_key(&d))
2138             })
2139             .filter_map(|i| extract_for_impl_name(&i.impl_item, cx))
2140             .collect::<Vec<_>>();
2141
2142         if !res.is_empty() {
2143             res.sort();
2144             buf.push_str(
2145                 "<a class=\"sidebar-title\" href=\"#foreign-impls\">\
2146                     Implementations on Foreign Types</a>\
2147                  <div class=\"sidebar-links\">",
2148             );
2149             for (name, id) in res.into_iter() {
2150                 write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name));
2151             }
2152             buf.push_str("</div>");
2153         }
2154     }
2155
2156     sidebar_assoc_items(cx, buf, it);
2157
2158     buf.push_str("<a class=\"sidebar-title\" href=\"#implementors\">Implementors</a>");
2159     if t.is_auto {
2160         buf.push_str(
2161             "<a class=\"sidebar-title\" \
2162                 href=\"#synthetic-implementors\">Auto Implementors</a>",
2163         );
2164     }
2165
2166     buf.push_str("</div>")
2167 }
2168
2169 fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2170     let mut sidebar = Buffer::new();
2171     sidebar_assoc_items(cx, &mut sidebar, it);
2172
2173     if !sidebar.is_empty() {
2174         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2175     }
2176 }
2177
2178 fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2179     let mut sidebar = Buffer::new();
2180     sidebar_assoc_items(cx, &mut sidebar, it);
2181
2182     if !sidebar.is_empty() {
2183         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2184     }
2185 }
2186
2187 fn get_struct_fields_name(fields: &[clean::Item]) -> Vec<String> {
2188     let mut fields = fields
2189         .iter()
2190         .filter(|f| matches!(*f.kind, clean::StructFieldItem(..)))
2191         .filter_map(|f| {
2192             f.name.map(|name| format!("<a href=\"#structfield.{name}\">{name}</a>", name = name))
2193         })
2194         .collect::<Vec<_>>();
2195     fields.sort();
2196     fields
2197 }
2198
2199 fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean::Union) {
2200     let mut sidebar = Buffer::new();
2201     let fields = get_struct_fields_name(&u.fields);
2202
2203     if !fields.is_empty() {
2204         sidebar.push_str(
2205             "<a class=\"sidebar-title\" href=\"#fields\">Fields</a>\
2206             <div class=\"sidebar-links\">",
2207         );
2208
2209         for field in fields {
2210             sidebar.push_str(&field);
2211         }
2212
2213         sidebar.push_str("</div>");
2214     }
2215
2216     sidebar_assoc_items(cx, &mut sidebar, it);
2217
2218     if !sidebar.is_empty() {
2219         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2220     }
2221 }
2222
2223 fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean::Enum) {
2224     let mut sidebar = Buffer::new();
2225
2226     let mut variants = e
2227         .variants
2228         .iter()
2229         .filter_map(|v| match v.name {
2230             Some(ref name) => Some(format!("<a href=\"#variant.{name}\">{name}</a>", name = name)),
2231             _ => None,
2232         })
2233         .collect::<Vec<_>>();
2234     if !variants.is_empty() {
2235         variants.sort_unstable();
2236         sidebar.push_str(&format!(
2237             "<a class=\"sidebar-title\" href=\"#variants\">Variants</a>\
2238              <div class=\"sidebar-links\">{}</div>",
2239             variants.join(""),
2240         ));
2241     }
2242
2243     sidebar_assoc_items(cx, &mut sidebar, it);
2244
2245     if !sidebar.is_empty() {
2246         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2247     }
2248 }
2249
2250 fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
2251     match ty {
2252         ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
2253         ItemType::Module => ("modules", "Modules"),
2254         ItemType::Struct => ("structs", "Structs"),
2255         ItemType::Union => ("unions", "Unions"),
2256         ItemType::Enum => ("enums", "Enums"),
2257         ItemType::Function => ("functions", "Functions"),
2258         ItemType::Typedef => ("types", "Type Definitions"),
2259         ItemType::Static => ("statics", "Statics"),
2260         ItemType::Constant => ("constants", "Constants"),
2261         ItemType::Trait => ("traits", "Traits"),
2262         ItemType::Impl => ("impls", "Implementations"),
2263         ItemType::TyMethod => ("tymethods", "Type Methods"),
2264         ItemType::Method => ("methods", "Methods"),
2265         ItemType::StructField => ("fields", "Struct Fields"),
2266         ItemType::Variant => ("variants", "Variants"),
2267         ItemType::Macro => ("macros", "Macros"),
2268         ItemType::Primitive => ("primitives", "Primitive Types"),
2269         ItemType::AssocType => ("associated-types", "Associated Types"),
2270         ItemType::AssocConst => ("associated-consts", "Associated Constants"),
2271         ItemType::ForeignType => ("foreign-types", "Foreign Types"),
2272         ItemType::Keyword => ("keywords", "Keywords"),
2273         ItemType::OpaqueTy => ("opaque-types", "Opaque Types"),
2274         ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
2275         ItemType::ProcDerive => ("derives", "Derive Macros"),
2276         ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
2277     }
2278 }
2279
2280 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
2281     let mut sidebar = String::new();
2282
2283     // Re-exports are handled a bit differently because they can be extern crates or imports.
2284     if items.iter().any(|it| {
2285         it.name.is_some()
2286             && (it.type_() == ItemType::ExternCrate
2287                 || (it.type_() == ItemType::Import && !it.is_stripped()))
2288     }) {
2289         let (id, name) = item_ty_to_strs(ItemType::Import);
2290         sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
2291     }
2292
2293     // ordering taken from item_module, reorder, where it prioritized elements in a certain order
2294     // to print its headings
2295     for &myty in &[
2296         ItemType::Primitive,
2297         ItemType::Module,
2298         ItemType::Macro,
2299         ItemType::Struct,
2300         ItemType::Enum,
2301         ItemType::Constant,
2302         ItemType::Static,
2303         ItemType::Trait,
2304         ItemType::Function,
2305         ItemType::Typedef,
2306         ItemType::Union,
2307         ItemType::Impl,
2308         ItemType::TyMethod,
2309         ItemType::Method,
2310         ItemType::StructField,
2311         ItemType::Variant,
2312         ItemType::AssocType,
2313         ItemType::AssocConst,
2314         ItemType::ForeignType,
2315         ItemType::Keyword,
2316     ] {
2317         if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
2318             let (id, name) = item_ty_to_strs(myty);
2319             sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
2320         }
2321     }
2322
2323     if !sidebar.is_empty() {
2324         write!(buf, "<div class=\"block items\"><ul>{}</ul></div>", sidebar);
2325     }
2326 }
2327
2328 fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
2329     let mut sidebar = Buffer::new();
2330     sidebar_assoc_items(cx, &mut sidebar, it);
2331
2332     if !sidebar.is_empty() {
2333         write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
2334     }
2335 }
2336
2337 crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang";
2338
2339 /// Returns a list of all paths used in the type.
2340 /// This is used to help deduplicate imported impls
2341 /// for reexported types. If any of the contained
2342 /// types are re-exported, we don't use the corresponding
2343 /// entry from the js file, as inlining will have already
2344 /// picked up the impl
2345 fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
2346     let mut out = Vec::new();
2347     let mut visited = FxHashSet::default();
2348     let mut work = VecDeque::new();
2349
2350     work.push_back(first_ty);
2351
2352     while let Some(ty) = work.pop_front() {
2353         if !visited.insert(ty.clone()) {
2354             continue;
2355         }
2356
2357         match ty {
2358             clean::Type::ResolvedPath { did, .. } => {
2359                 let get_extern = || cache.external_paths.get(&did).map(|s| s.0.clone());
2360                 let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
2361
2362                 if let Some(path) = fqp {
2363                     out.push(path.join("::"));
2364                 }
2365             }
2366             clean::Type::Tuple(tys) => {
2367                 work.extend(tys.into_iter());
2368             }
2369             clean::Type::Slice(ty) => {
2370                 work.push_back(*ty);
2371             }
2372             clean::Type::Array(ty, _) => {
2373                 work.push_back(*ty);
2374             }
2375             clean::Type::RawPointer(_, ty) => {
2376                 work.push_back(*ty);
2377             }
2378             clean::Type::BorrowedRef { type_, .. } => {
2379                 work.push_back(*type_);
2380             }
2381             clean::Type::QPath { self_type, trait_, .. } => {
2382                 work.push_back(*self_type);
2383                 work.push_back(*trait_);
2384             }
2385             _ => {}
2386         }
2387     }
2388     out
2389 }