Skip to main content

rustdoc/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//! The main entry point to the rendering system is the implementation of
17//! `FormatRenderer` on `Context`.
18//!
19//! In order to speed up rendering (mostly because of markdown rendering), the
20//! rendering process has been parallelized. This parallelization is only
21//! exposed through the `crate` method on the context, and then also from the
22//! fact that the shared cache is stored in TLS (and must be accessed as such).
23//!
24//! In addition to rendering the crate itself, this module is also responsible
25//! for creating the corresponding search index and source file renderings.
26//! These threads are not parallelized (they haven't been a bottleneck yet), and
27//! both occur before the crate is rendered.
28
29pub(crate) mod search_index;
30
31#[cfg(test)]
32mod tests;
33
34mod context;
35mod ordered_json;
36mod print_item;
37pub(crate) mod sidebar;
38mod sorted_template;
39mod type_layout;
40mod write_shared;
41
42use std::borrow::Cow;
43use std::cmp::Ordering;
44use std::collections::{BTreeMap, VecDeque};
45use std::fmt::{self, Display as _, Write};
46use std::iter::Peekable;
47use std::path::PathBuf;
48use std::{fs, str};
49
50use askama::Template;
51use indexmap::IndexMap;
52use itertools::Either;
53use rustc_ast::join_path_syms;
54use rustc_attr_ir::{
55    AttributeKind, ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel,
56    StableSince, find_attr,
57};
58use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
59use rustc_hir::Mutability;
60use rustc_hir::def::DefKind;
61use rustc_hir::def_id::{DefId, DefIdSet};
62use rustc_middle::ty::print::PrintTraitRefExt;
63use rustc_middle::ty::{self, TyCtxt};
64use rustc_span::DUMMY_SP;
65use rustc_span::symbol::{Symbol, sym};
66use tracing::{debug, info};
67
68pub(crate) use self::context::*;
69pub(crate) use self::write_shared::*;
70use crate::clean::{self, Defaultness, Item, ItemId, RenderedLink};
71use crate::display::{Joined as _, MaybeDisplay as _};
72use crate::error::Error;
73use crate::formats::Impl;
74use crate::formats::cache::Cache;
75use crate::formats::item_type::ItemType;
76use crate::html::escape::Escape;
77use crate::html::format::{
78    Ending, HrefError, HrefInfo, PrintWithSpace, full_print_fn_decl, href, print_abi_with_space,
79    print_constness_with_space, print_generic_bounds, print_generics, print_impl, print_path,
80    print_type, print_where_clause, visibility_print_with_space,
81};
82use crate::html::markdown::{
83    HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, short_markdown_summary,
84};
85use crate::html::render::print_item::ImplString;
86use crate::html::render::search_index::get_function_type_for_search;
87use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
88use crate::html::{highlight, sources};
89use crate::scrape_examples::{CallData, CallLocation};
90use crate::{DOC_RUST_LANG_ORG_VERSION, try_none};
91
92pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display {
93    fmt::from_fn(move |f| {
94        if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) }
95    })
96}
97
98/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
99/// impl.
100#[derive(Copy, Clone, Debug)]
101enum AssocItemRender<'a> {
102    All,
103    DerefFor {
104        trait_: &'a clean::Path,
105        type_: &'a clean::Type,
106        deref_mut_: bool,
107        deref_impl_def_id: DefId,
108    },
109}
110
111impl AssocItemRender<'_> {
112    fn render_mode(&self, tcx: TyCtxt<'_>) -> RenderMode {
113        match self {
114            Self::All => RenderMode::Normal,
115            &Self::DerefFor { deref_mut_, deref_impl_def_id, .. } => {
116                let is_deref_target_copy =
117                    compute_if_deref_target_implements_copy(tcx, deref_impl_def_id);
118                RenderMode::ForDeref { mut_: deref_mut_, is_deref_target_copy }
119            }
120        }
121    }
122
123    fn class(&self) -> Option<&'static str> {
124        if let Self::DerefFor { .. } = self { Some("impl-items") } else { None }
125    }
126}
127
128/// For different handling of associated items from the Deref target of a type rather than the type
129/// itself.
130#[derive(Copy, Clone, PartialEq)]
131enum RenderMode {
132    Normal,
133    ForDeref { mut_: bool, is_deref_target_copy: bool },
134}
135
136// Helper structs for rendering items/sidebars and carrying along contextual
137// information
138
139#[derive(Debug, Clone)]
140pub(crate) struct IndexItemInfo {
141    pub(crate) ty: ItemType,
142    pub(crate) desc: String,
143    pub(crate) search_type: Option<IndexItemFunctionType>,
144    pub(crate) aliases: Box<[Symbol]>,
145    pub(crate) deprecation: Option<Deprecation>,
146    pub(crate) is_unstable: bool,
147}
148
149impl IndexItemInfo {
150    pub(crate) fn new(
151        tcx: TyCtxt<'_>,
152        cache: &Cache,
153        item: &Item,
154        parent_did: Option<DefId>,
155        impl_generics: Option<&(clean::Type, clean::Generics)>,
156        ty: ItemType,
157    ) -> Self {
158        let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
159        let search_type = get_function_type_for_search(item, tcx, impl_generics, parent_did, cache);
160        let aliases = item.attrs.get_doc_aliases();
161        let deprecation = item.deprecation(tcx);
162        let is_unstable = item.is_unstable();
163        Self { ty, desc, search_type, aliases, deprecation, is_unstable }
164    }
165}
166
167/// Struct representing one entry in the JS search index. These are all emitted
168/// by hand to a large JS file at the end of cache-creation.
169#[derive(Debug, Clone)]
170pub(crate) struct IndexItem {
171    pub(crate) defid: Option<DefId>,
172    pub(crate) name: Symbol,
173    pub(crate) module_path: Vec<Symbol>,
174    pub(crate) parent: Option<DefId>,
175    pub(crate) parent_idx: Option<usize>,
176    pub(crate) trait_parent: Option<DefId>,
177    pub(crate) trait_parent_idx: Option<usize>,
178    pub(crate) exact_module_path: Option<Vec<Symbol>>,
179    pub(crate) impl_id: Option<DefId>,
180    pub(crate) info: IndexItemInfo,
181}
182
183/// A type used for the search index.
184#[derive(Clone, Debug, Eq, PartialEq)]
185struct RenderType {
186    id: Option<RenderTypeId>,
187    generics: Option<Vec<RenderType>>,
188    bindings: Option<Vec<(RenderTypeId, Vec<RenderType>)>>,
189}
190
191impl RenderType {
192    fn size(&self) -> usize {
193        let mut size = 1;
194        if let Some(generics) = &self.generics {
195            size += generics.iter().map(RenderType::size).sum::<usize>();
196        }
197        if let Some(bindings) = &self.bindings {
198            for (_, constraints) in bindings.iter() {
199                size += 1;
200                size += constraints.iter().map(RenderType::size).sum::<usize>();
201            }
202        }
203        size
204    }
205    // Types are rendered as lists of lists, because that's pretty compact.
206    // The contents of the lists are always integers in self-terminating hex
207    // form, handled by `RenderTypeId::write_to_string`, so no commas are
208    // needed to separate the items.
209    fn write_to_string(&self, string: &mut String) {
210        fn write_optional_id(id: Option<RenderTypeId>, string: &mut String) {
211            // 0 is a sentinel, everything else is one-indexed
212            match id {
213                Some(id) => id.write_to_string(string),
214                None => string.push('`'),
215            }
216        }
217        // Either just the type id, or `{type, generics, bindings?}`
218        // where generics is a list of types,
219        // and bindings is a list of `{id, typelist}` pairs.
220        if self.generics.is_some() || self.bindings.is_some() {
221            string.push('{');
222            write_optional_id(self.id, string);
223            string.push('{');
224            for generic in self.generics.as_deref().unwrap_or_default() {
225                generic.write_to_string(string);
226            }
227            string.push('}');
228            if self.bindings.is_some() {
229                string.push('{');
230                for binding in self.bindings.as_deref().unwrap_or_default() {
231                    string.push('{');
232                    binding.0.write_to_string(string);
233                    string.push('{');
234                    for constraint in &binding.1[..] {
235                        constraint.write_to_string(string);
236                    }
237                    string.push_str("}}");
238                }
239                string.push('}');
240            }
241            string.push('}');
242        } else {
243            write_optional_id(self.id, string);
244        }
245    }
246    fn read_from_bytes(string: &[u8]) -> (RenderType, usize) {
247        let mut i = 0;
248        if string[i] == b'{' {
249            i += 1;
250            let (id, offset) = RenderTypeId::read_from_bytes(&string[i..]);
251            i += offset;
252            let generics = if string[i] == b'{' {
253                i += 1;
254                let mut generics = Vec::new();
255                while string[i] != b'}' {
256                    let (ty, offset) = RenderType::read_from_bytes(&string[i..]);
257                    i += offset;
258                    generics.push(ty);
259                }
260                assert!(string[i] == b'}');
261                i += 1;
262                Some(generics)
263            } else {
264                None
265            };
266            let bindings = if string[i] == b'{' {
267                i += 1;
268                let mut bindings = Vec::new();
269                while string[i] == b'{' {
270                    i += 1;
271                    let (binding, boffset) = RenderTypeId::read_from_bytes(&string[i..]);
272                    i += boffset;
273                    let mut bconstraints = Vec::new();
274                    assert!(string[i] == b'{');
275                    i += 1;
276                    while string[i] != b'}' {
277                        let (constraint, coffset) = RenderType::read_from_bytes(&string[i..]);
278                        i += coffset;
279                        bconstraints.push(constraint);
280                    }
281                    assert!(string[i] == b'}');
282                    i += 1;
283                    bindings.push((binding.unwrap(), bconstraints));
284                    assert!(string[i] == b'}');
285                    i += 1;
286                }
287                assert!(string[i] == b'}');
288                i += 1;
289                Some(bindings)
290            } else {
291                None
292            };
293            assert!(string[i] == b'}');
294            i += 1;
295            (RenderType { id, generics, bindings }, i)
296        } else {
297            let (id, offset) = RenderTypeId::read_from_bytes(string);
298            i += offset;
299            (RenderType { id, generics: None, bindings: None }, i)
300        }
301    }
302}
303
304#[derive(Clone, Copy, Debug, Eq, PartialEq)]
305enum RenderTypeId {
306    DefId(DefId),
307    Primitive(clean::PrimitiveType),
308    AssociatedType(Symbol),
309    Index(isize),
310    Mut,
311}
312
313impl RenderTypeId {
314    fn write_to_string(&self, string: &mut String) {
315        let id: i32 = match &self {
316            // 0 is a sentinel, everything else is one-indexed
317            // concrete type
318            RenderTypeId::Index(idx) if *idx >= 0 => (idx + 1isize).try_into().unwrap(),
319            // generic type parameter
320            RenderTypeId::Index(idx) => (*idx).try_into().unwrap(),
321            _ => panic!("must convert render types to indexes before serializing"),
322        };
323        search_index::encode::write_signed_vlqhex_to_string(id, string);
324    }
325    fn read_from_bytes(string: &[u8]) -> (Option<RenderTypeId>, usize) {
326        let Some((value, offset)) = search_index::encode::read_signed_vlqhex_from_string(string)
327        else {
328            return (None, 0);
329        };
330        let value = isize::try_from(value).unwrap();
331        let ty = match value {
332            ..0 => Some(RenderTypeId::Index(value)),
333            0 => None,
334            1.. => Some(RenderTypeId::Index(value - 1)),
335        };
336        (ty, offset)
337    }
338}
339
340/// Full type of functions/methods in the search index.
341#[derive(Clone, Debug, Eq, PartialEq)]
342pub(crate) struct IndexItemFunctionType {
343    inputs: Vec<RenderType>,
344    output: Vec<RenderType>,
345    where_clause: Vec<Vec<RenderType>>,
346    param_names: Vec<Option<Symbol>>,
347}
348
349impl IndexItemFunctionType {
350    fn size(&self) -> usize {
351        self.inputs.iter().map(RenderType::size).sum::<usize>()
352            + self.output.iter().map(RenderType::size).sum::<usize>()
353            + self
354                .where_clause
355                .iter()
356                .map(|constraints| constraints.iter().map(RenderType::size).sum::<usize>())
357                .sum::<usize>()
358    }
359    fn read_from_string_without_param_names(string: &[u8]) -> (IndexItemFunctionType, usize) {
360        let mut i = 0;
361        if string[i] == b'`' {
362            return (
363                IndexItemFunctionType {
364                    inputs: Vec::new(),
365                    output: Vec::new(),
366                    where_clause: Vec::new(),
367                    param_names: Vec::new(),
368                },
369                1,
370            );
371        }
372        assert_eq!(b'{', string[i]);
373        i += 1;
374        fn read_args_from_string(string: &[u8]) -> (Vec<RenderType>, usize) {
375            let mut i = 0;
376            let mut params = Vec::new();
377            if string[i] == b'{' {
378                // multiple params
379                i += 1;
380                while string[i] != b'}' {
381                    let (ty, offset) = RenderType::read_from_bytes(&string[i..]);
382                    i += offset;
383                    params.push(ty);
384                }
385                i += 1;
386            } else if string[i] != b'}' {
387                let (tyid, offset) = RenderTypeId::read_from_bytes(&string[i..]);
388                params.push(RenderType { id: tyid, generics: None, bindings: None });
389                i += offset;
390            }
391            (params, i)
392        }
393        let (inputs, offset) = read_args_from_string(&string[i..]);
394        i += offset;
395        let (output, offset) = read_args_from_string(&string[i..]);
396        i += offset;
397        let mut where_clause = Vec::new();
398        while string[i] != b'}' {
399            let (constraint, offset) = read_args_from_string(&string[i..]);
400            i += offset;
401            where_clause.push(constraint);
402        }
403        assert_eq!(b'}', string[i], "{} {}", String::from_utf8_lossy(&string), i);
404        i += 1;
405        (IndexItemFunctionType { inputs, output, where_clause, param_names: Vec::new() }, i)
406    }
407    fn write_to_string_without_param_names<'a>(&'a self, string: &mut String) {
408        // If we couldn't figure out a type, just write 0,
409        // which is encoded as `` ` `` (see RenderTypeId::write_to_string).
410        let has_missing = self
411            .inputs
412            .iter()
413            .chain(self.output.iter())
414            .any(|i| i.id.is_none() && i.generics.is_none());
415        if has_missing {
416            string.push('`');
417        } else {
418            string.push('{');
419            match &self.inputs[..] {
420                [one] if one.generics.is_none() && one.bindings.is_none() => {
421                    one.write_to_string(string);
422                }
423                _ => {
424                    string.push('{');
425                    for item in &self.inputs[..] {
426                        item.write_to_string(string);
427                    }
428                    string.push('}');
429                }
430            }
431            match &self.output[..] {
432                [] if self.where_clause.is_empty() => {}
433                [one] if one.generics.is_none() && one.bindings.is_none() => {
434                    one.write_to_string(string);
435                }
436                _ => {
437                    string.push('{');
438                    for item in &self.output[..] {
439                        item.write_to_string(string);
440                    }
441                    string.push('}');
442                }
443            }
444            for constraint in &self.where_clause {
445                if let [one] = &constraint[..]
446                    && one.generics.is_none()
447                    && one.bindings.is_none()
448                {
449                    one.write_to_string(string);
450                } else {
451                    string.push('{');
452                    for item in &constraint[..] {
453                        item.write_to_string(string);
454                    }
455                    string.push('}');
456                }
457            }
458            string.push('}');
459        }
460    }
461}
462
463#[derive(Debug, Clone)]
464pub(crate) struct StylePath {
465    /// The path to the theme
466    pub(crate) path: PathBuf,
467}
468
469impl StylePath {
470    pub(crate) fn basename(&self) -> Result<String, Error> {
471        Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
472    }
473}
474
475#[derive(Debug, Eq, PartialEq, Hash)]
476struct ItemEntry {
477    url: String,
478    name: String,
479}
480
481impl ItemEntry {
482    fn new(mut url: String, name: String) -> ItemEntry {
483        while url.starts_with('/') {
484            url.remove(0);
485        }
486        ItemEntry { url, name }
487    }
488}
489
490impl ItemEntry {
491    fn print(&self) -> impl fmt::Display {
492        fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)))
493    }
494}
495
496impl PartialOrd for ItemEntry {
497    fn partial_cmp(&self, other: &ItemEntry) -> Option<::std::cmp::Ordering> {
498        Some(self.cmp(other))
499    }
500}
501
502impl Ord for ItemEntry {
503    fn cmp(&self, other: &ItemEntry) -> ::std::cmp::Ordering {
504        self.name.cmp(&other.name)
505    }
506}
507
508#[derive(Debug)]
509struct AllTypes {
510    structs: FxIndexSet<ItemEntry>,
511    enums: FxIndexSet<ItemEntry>,
512    unions: FxIndexSet<ItemEntry>,
513    primitives: FxIndexSet<ItemEntry>,
514    traits: FxIndexSet<ItemEntry>,
515    macros: FxIndexSet<ItemEntry>,
516    functions: FxIndexSet<ItemEntry>,
517    type_aliases: FxIndexSet<ItemEntry>,
518    statics: FxIndexSet<ItemEntry>,
519    constants: FxIndexSet<ItemEntry>,
520    attribute_macros: FxIndexSet<ItemEntry>,
521    derive_macros: FxIndexSet<ItemEntry>,
522    trait_aliases: FxIndexSet<ItemEntry>,
523}
524
525impl AllTypes {
526    fn new() -> AllTypes {
527        let new_set = |cap| FxIndexSet::with_capacity_and_hasher(cap, Default::default());
528        AllTypes {
529            structs: new_set(100),
530            enums: new_set(100),
531            unions: new_set(100),
532            primitives: new_set(26),
533            traits: new_set(100),
534            macros: new_set(100),
535            functions: new_set(100),
536            type_aliases: new_set(100),
537            statics: new_set(100),
538            constants: new_set(100),
539            attribute_macros: new_set(100),
540            derive_macros: new_set(100),
541            trait_aliases: new_set(100),
542        }
543    }
544
545    fn add_item_entry(&mut self, item_type: ItemType, new_url: String, name: String) {
546        match item_type {
547            ItemType::Struct => self.structs.insert(ItemEntry::new(new_url, name)),
548            ItemType::Enum => self.enums.insert(ItemEntry::new(new_url, name)),
549            ItemType::Union => self.unions.insert(ItemEntry::new(new_url, name)),
550            ItemType::Primitive => self.primitives.insert(ItemEntry::new(new_url, name)),
551            ItemType::Trait => self.traits.insert(ItemEntry::new(new_url, name)),
552            ItemType::Macro => self.macros.insert(ItemEntry::new(new_url, name)),
553            ItemType::Function => self.functions.insert(ItemEntry::new(new_url, name)),
554            ItemType::TypeAlias => self.type_aliases.insert(ItemEntry::new(new_url, name)),
555            ItemType::Static => self.statics.insert(ItemEntry::new(new_url, name)),
556            ItemType::Constant => self.constants.insert(ItemEntry::new(new_url, name)),
557            ItemType::ProcAttribute | ItemType::DeclMacroAttribute => {
558                self.attribute_macros.insert(ItemEntry::new(new_url, name))
559            }
560            ItemType::ProcDerive | ItemType::DeclMacroDerive => {
561                self.derive_macros.insert(ItemEntry::new(new_url, name))
562            }
563            ItemType::TraitAlias => self.trait_aliases.insert(ItemEntry::new(new_url, name)),
564            _ => true,
565        };
566    }
567
568    fn append(&mut self, item_name: String, item: &clean::Item) {
569        let mut url: Vec<_> = item_name.split("::").skip(1).collect();
570        if let Some(name) = url.pop() {
571            let new_url = format!("{}/{}", url.join("/"), item.html_filename());
572            url.push(name);
573            let name = url.join("::");
574            for type_ in item.types() {
575                self.add_item_entry(type_, new_url.clone(), name.clone());
576            }
577        }
578    }
579
580    fn item_sections(&self) -> FxHashSet<ItemSection> {
581        let mut sections = FxHashSet::default();
582
583        if !self.structs.is_empty() {
584            sections.insert(ItemSection::Structs);
585        }
586        if !self.enums.is_empty() {
587            sections.insert(ItemSection::Enums);
588        }
589        if !self.unions.is_empty() {
590            sections.insert(ItemSection::Unions);
591        }
592        if !self.primitives.is_empty() {
593            sections.insert(ItemSection::PrimitiveTypes);
594        }
595        if !self.traits.is_empty() {
596            sections.insert(ItemSection::Traits);
597        }
598        if !self.macros.is_empty() {
599            sections.insert(ItemSection::Macros);
600        }
601        if !self.functions.is_empty() {
602            sections.insert(ItemSection::Functions);
603        }
604        if !self.type_aliases.is_empty() {
605            sections.insert(ItemSection::TypeAliases);
606        }
607        if !self.statics.is_empty() {
608            sections.insert(ItemSection::Statics);
609        }
610        if !self.constants.is_empty() {
611            sections.insert(ItemSection::Constants);
612        }
613        if !self.attribute_macros.is_empty() {
614            sections.insert(ItemSection::AttributeMacros);
615        }
616        if !self.derive_macros.is_empty() {
617            sections.insert(ItemSection::DeriveMacros);
618        }
619        if !self.trait_aliases.is_empty() {
620            sections.insert(ItemSection::TraitAliases);
621        }
622
623        sections
624    }
625
626    fn print(&self) -> impl fmt::Display {
627        fn print_entries(e: &FxIndexSet<ItemEntry>, kind: ItemSection) -> impl fmt::Display {
628            fmt::from_fn(move |f| {
629                if e.is_empty() {
630                    return Ok(());
631                }
632
633                let mut e: Vec<&ItemEntry> = e.iter().collect();
634                e.sort();
635                write!(
636                    f,
637                    "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
638                    id = kind.id(),
639                    title = kind.name(),
640                )?;
641
642                for s in e.iter() {
643                    write!(f, "<li>{}</li>", s.print())?;
644                }
645
646                f.write_str("</ul>")
647            })
648        }
649
650        fmt::from_fn(|f| {
651            f.write_str(
652                "<div class=\"main-heading\">\
653                    <h1>List of all items</h1>\
654                    <rustdoc-toolbar></rustdoc-toolbar>\
655                </div>",
656            )?;
657            // Note: print_entries does not escape the title, because we know the current set of titles
658            // doesn't require escaping.
659            print_entries(&self.structs, ItemSection::Structs).fmt(f)?;
660            print_entries(&self.enums, ItemSection::Enums).fmt(f)?;
661            print_entries(&self.unions, ItemSection::Unions).fmt(f)?;
662            print_entries(&self.primitives, ItemSection::PrimitiveTypes).fmt(f)?;
663            print_entries(&self.traits, ItemSection::Traits).fmt(f)?;
664            print_entries(&self.macros, ItemSection::Macros).fmt(f)?;
665            print_entries(&self.attribute_macros, ItemSection::AttributeMacros).fmt(f)?;
666            print_entries(&self.derive_macros, ItemSection::DeriveMacros).fmt(f)?;
667            print_entries(&self.functions, ItemSection::Functions).fmt(f)?;
668            print_entries(&self.type_aliases, ItemSection::TypeAliases).fmt(f)?;
669            print_entries(&self.trait_aliases, ItemSection::TraitAliases).fmt(f)?;
670            print_entries(&self.statics, ItemSection::Statics).fmt(f)?;
671            print_entries(&self.constants, ItemSection::Constants).fmt(f)?;
672            Ok(())
673        })
674    }
675}
676
677fn scrape_examples_help() -> String {
678    let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
679    content.push_str(&format!(
680        "## More information\n\n\
681      If you want more information about this feature, please read the [corresponding chapter in \
682      the Rustdoc book]({DOC_RUST_LANG_ORG_VERSION}/rustdoc/scraped-examples.html)."
683    ));
684
685    format!(
686        "<div class=\"main-heading\">\
687             <h1>About scraped examples</h1>\
688         </div>\
689         <div>{}</div>",
690        fmt::from_fn(|f| Markdown {
691            content: &content,
692            links: &[],
693            ids: &mut IdMap::default(),
694            // code snippets come from Rust itself, not the crate
695            error_codes: crate::html::markdown::ErrorCodes::No,
696            edition: rustc_span::edition::LATEST_STABLE_EDITION,
697            playground: &Default::default(),
698            heading_offset: HeadingOffset::H1,
699        }
700        .write_into(f))
701    )
702}
703
704fn document(
705    cx: &Context<'_>,
706    item: &clean::Item,
707    parent: Option<&clean::Item>,
708    heading_offset: HeadingOffset,
709) -> impl fmt::Display {
710    if let Some(ref name) = item.name {
711        info!("Documenting {name}");
712    }
713
714    fmt::from_fn(move |f| {
715        document_item_info(cx, item, parent).render_into(f)?;
716        if parent.is_none() {
717            write!(f, "{}", document_full_collapsible(item, cx, heading_offset))
718        } else {
719            write!(f, "{}", document_full(item, cx, heading_offset))
720        }
721    })
722}
723
724/// Render md_text as markdown.
725fn render_markdown(
726    cx: &Context<'_>,
727    md_text: &str,
728    links: Vec<RenderedLink>,
729    heading_offset: HeadingOffset,
730) -> impl fmt::Display {
731    fmt::from_fn(move |f| {
732        f.write_str("<div class=\"docblock\">")?;
733        Markdown {
734            content: md_text,
735            links: &links,
736            ids: &mut cx.id_map.borrow_mut(),
737            error_codes: cx.shared.codes,
738            edition: cx.shared.edition(),
739            playground: &cx.shared.playground,
740            heading_offset,
741        }
742        .write_into(&mut *f)?;
743        f.write_str("</div>")
744    })
745}
746
747/// Writes a documentation block containing only the first paragraph of the documentation. If the
748/// docs are longer, a "Read more" link is appended to the end.
749fn document_short(
750    item: &clean::Item,
751    cx: &Context<'_>,
752    link: AssocItemLink<'_>,
753    parent: &clean::Item,
754    show_def_docs: bool,
755) -> impl fmt::Display {
756    fmt::from_fn(move |f| {
757        document_item_info(cx, item, Some(parent)).render_into(f)?;
758        if !show_def_docs {
759            return Ok(());
760        }
761        let s = item.doc_value();
762        if !s.is_empty() {
763            let (mut summary_html, has_more_content) =
764                MarkdownSummaryLine(&s, &item.links(cx)).into_string_with_has_more_content();
765
766            let link = if has_more_content {
767                let link = fmt::from_fn(|f| {
768                    write!(
769                        f,
770                        " <a{}>Read more</a>",
771                        assoc_href_attr(item, link, cx).maybe_display()
772                    )
773                });
774
775                if let Some(idx) = summary_html.rfind("</p>") {
776                    summary_html.insert_str(idx, &link.to_string());
777                    None
778                } else {
779                    Some(link)
780                }
781            } else {
782                None
783            }
784            .maybe_display();
785
786            write!(f, "<div class='docblock'>{summary_html}{link}</div>")?;
787        }
788        Ok(())
789    })
790}
791
792fn document_full_collapsible(
793    item: &clean::Item,
794    cx: &Context<'_>,
795    heading_offset: HeadingOffset,
796) -> impl fmt::Display {
797    document_full_inner(item, cx, true, heading_offset)
798}
799
800fn document_full(
801    item: &clean::Item,
802    cx: &Context<'_>,
803    heading_offset: HeadingOffset,
804) -> impl fmt::Display {
805    document_full_inner(item, cx, false, heading_offset)
806}
807
808fn document_full_inner(
809    item: &clean::Item,
810    cx: &Context<'_>,
811    is_collapsible: bool,
812    heading_offset: HeadingOffset,
813) -> impl fmt::Display {
814    fmt::from_fn(move |f| {
815        if let Some(s) = item.opt_doc_value() {
816            debug!("Doc block: =====\n{s}\n=====");
817            if is_collapsible {
818                write!(
819                    f,
820                    "<details class=\"toggle top-doc\" open>\
821                     <summary class=\"hideme\">\
822                        <span>Expand description</span>\
823                     </summary>{}</details>",
824                    render_markdown(cx, &s, item.links(cx), heading_offset)
825                )?;
826            } else {
827                write!(f, "{}", render_markdown(cx, &s, item.links(cx), heading_offset))?;
828            }
829        }
830
831        let kind = match &item.kind {
832            clean::ItemKind::StrippedItem(kind) => kind,
833            kind => kind,
834        };
835
836        if let clean::ItemKind::FunctionItem(..) | clean::ItemKind::MethodItem(..) = kind {
837            render_call_locations(f, cx, item)?;
838        }
839        Ok(())
840    })
841}
842
843#[derive(Template)]
844#[template(path = "item_info.html")]
845struct ItemInfo {
846    items: Vec<ShortItemInfo>,
847}
848/// Add extra information about an item such as:
849///
850/// * Stability
851/// * Deprecated
852/// * Required features (through the `doc_cfg` feature)
853fn document_item_info(
854    cx: &Context<'_>,
855    item: &clean::Item,
856    parent: Option<&clean::Item>,
857) -> ItemInfo {
858    let items = short_item_info(item, cx, parent);
859    ItemInfo { items }
860}
861
862fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
863    let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) {
864        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
865        (cfg, _) => cfg.as_deref().cloned(),
866    };
867
868    debug!(
869        "Portability {name:?} {item_cfg:?} (parent: {parent:?}) - {parent_cfg:?} = {cfg:?}",
870        name = item.name,
871        item_cfg = item.cfg,
872        parent_cfg = parent.and_then(|p| p.cfg.as_ref()),
873    );
874
875    Some(cfg?.render_long_html())
876}
877
878#[derive(Template)]
879#[template(path = "short_item_info.html")]
880enum ShortItemInfo {
881    /// A message describing the deprecation of this item
882    Deprecation {
883        message: String,
884    },
885    /// The feature corresponding to an unstable item, and optionally
886    /// a tracking issue URL and number.
887    Unstable {
888        feature: String,
889        tracking: Option<(String, u32)>,
890    },
891    Portability {
892        message: String,
893    },
894}
895
896/// Render the stability, deprecation and portability information that is displayed at the top of
897/// the item's documentation.
898fn short_item_info(
899    item: &clean::Item,
900    cx: &Context<'_>,
901    parent: Option<&clean::Item>,
902) -> Vec<ShortItemInfo> {
903    let mut extra_info = vec![];
904
905    if let Some(depr @ Deprecation { note, since, suggestion: _ }) = item.deprecation(cx.tcx()) {
906        // We display deprecation messages for #[deprecated], but only display
907        // the future-deprecation messages for rustc versions.
908        let mut message = match since {
909            DeprecatedSince::RustcVersion(version) => {
910                if depr.is_in_effect() {
911                    format!("Deprecated since {version}")
912                } else {
913                    format!("Deprecating in {version}")
914                }
915            }
916            DeprecatedSince::Future => String::from("Deprecating in a future version"),
917            DeprecatedSince::NonStandard(since) => {
918                format!("Deprecated since {}", Escape(since.as_str()))
919            }
920            DeprecatedSince::Unspecified | DeprecatedSince::Err => String::from("Deprecated"),
921        };
922
923        if let Some(note) = note {
924            let note = note.as_str();
925            let mut id_map = cx.id_map.borrow_mut();
926            let links = item.links(cx);
927            let html = MarkdownItemInfo::new(note, &links, &mut id_map);
928            message.push_str(": ");
929            html.write_into(&mut message).unwrap();
930        }
931        extra_info.push(ShortItemInfo::Deprecation { message });
932    }
933
934    // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
935    // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
936    if let Some((StabilityLevel::Unstable { reason: _, issue, .. }, feature)) = item
937        .stability(cx.tcx())
938        .as_ref()
939        .filter(|stab| stab.feature != sym::rustc_private)
940        .map(|stab| (stab.level, stab.feature))
941    {
942        let tracking = if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue)
943        {
944            Some((url.clone(), issue.get()))
945        } else {
946            None
947        };
948        extra_info.push(ShortItemInfo::Unstable { feature: feature.to_string(), tracking });
949    }
950
951    if let Some(message) = portability(item, parent) {
952        extra_info.push(ShortItemInfo::Portability { message });
953    }
954
955    extra_info
956}
957
958// Prints the polarity and path of an impl's trait, if it has one, e.g. `Send`, `!Sync`.
959fn impl_trait_key(cx: &Context<'_>, i: &Impl) -> Option<String> {
960    let trait_ = i.inner_impl().trait_.as_ref()?;
961    let prefix = match i.inner_impl().polarity {
962        ty::ImplPolarity::Positive => "",
963        ty::ImplPolarity::Negative => "!",
964    };
965    Some(format!("{prefix}{:#}", print_path(trait_, cx)))
966}
967
968// Render the list of items inside one of the sections "Trait Implementations",
969// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
970fn render_impls<'a, 'cx>(
971    cx: &'a Context<'cx>,
972    mut impls: Vec<&'a Impl>,
973    containing_item: &'a clean::Item,
974    toggle_open_by_default: bool,
975) -> impl fmt::Display + use<'a, 'cx> {
976    impls.sort_by_cached_key(|imp| {
977        let prefix = match imp.inner_impl().polarity {
978            ty::ImplPolarity::Positive => Ordering::Greater,
979            ty::ImplPolarity::Negative => Ordering::Less,
980        };
981        (prefix, ImplString::new_path(imp, cx))
982    });
983    // Render each impl alongside its `impl_trait_key`, which is used as the primary sorting key
984    // to match the impl order in the sidebar.
985
986    fmt::from_fn(move |f| {
987        impls
988            .iter()
989            .map(|i| {
990                fmt::from_fn(|f| {
991                    let did = i.trait_did().unwrap();
992                    let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx());
993                    let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
994                    render_impl(
995                        cx,
996                        i,
997                        containing_item,
998                        assoc_link,
999                        RenderMode::Normal,
1000                        None,
1001                        &[],
1002                        ImplRenderingParameters {
1003                            show_def_docs: true,
1004                            show_default_items: true,
1005                            show_non_assoc_items: true,
1006                            toggle_open_by_default,
1007                        },
1008                    )
1009                    .fmt(f)
1010                })
1011            })
1012            .joined("", f)
1013    })
1014}
1015
1016/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
1017fn assoc_href_attr(
1018    it: &clean::Item,
1019    link: AssocItemLink<'_>,
1020    cx: &Context<'_>,
1021) -> Option<impl fmt::Display> {
1022    let name = it.name.unwrap();
1023    let item_type = it.type_();
1024
1025    enum Href<'a> {
1026        AnchorId(&'a str),
1027        Anchor(ItemType),
1028        Url(String, ItemType),
1029    }
1030
1031    let href = match link {
1032        AssocItemLink::Anchor(Some(id)) => Href::AnchorId(id),
1033        AssocItemLink::Anchor(None) => Href::Anchor(item_type),
1034        AssocItemLink::GotoSource(did, provided_methods) => {
1035            // We're creating a link from the implementation of an associated item to its
1036            // declaration in the trait declaration.
1037            let item_type = match item_type {
1038                // For historical but not technical reasons, the item type of methods in
1039                // trait declarations depends on whether the method is required (`TyMethod`) or
1040                // provided (`Method`).
1041                ItemType::Method | ItemType::TyMethod => {
1042                    if provided_methods.contains(&name) {
1043                        ItemType::Method
1044                    } else {
1045                        ItemType::TyMethod
1046                    }
1047                }
1048                // For associated types and constants, no such distinction exists.
1049                item_type => item_type,
1050            };
1051
1052            match href(did.expect_def_id(), cx) {
1053                Ok(HrefInfo { url, .. }) => Href::Url(url, item_type),
1054                // The link is broken since it points to an external crate that wasn't documented.
1055                // Do not create any link in such case. This is better than falling back to a
1056                // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
1057                // (that used to happen in older versions). Indeed, in most cases this dummy would
1058                // coincide with the `id`. However, it would not always do so.
1059                // In general, this dummy would be incorrect:
1060                // If the type with the trait impl also had an inherent impl with an assoc. item of
1061                // the *same* name as this impl item, the dummy would link to that one even though
1062                // those two items are distinct!
1063                // In this scenario, the actual `id` of this impl item would be
1064                // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
1065                Err(HrefError::DocumentationNotBuilt) => return None,
1066                Err(_) => Href::Anchor(item_type),
1067            }
1068        }
1069    };
1070
1071    let href = fmt::from_fn(move |f| match &href {
1072        Href::AnchorId(id) => write!(f, "#{id}"),
1073        Href::Url(url, item_type) => {
1074            write!(f, "{url}#{item_type}.{name}")
1075        }
1076        Href::Anchor(item_type) => {
1077            write!(f, "#{item_type}.{name}")
1078        }
1079    });
1080
1081    // If there is no `href` for the reason explained above, simply do not render it which is valid:
1082    // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
1083    Some(fmt::from_fn(move |f| write!(f, " href=\"{href}\"")))
1084}
1085
1086#[derive(Debug)]
1087enum AssocConstValue<'a> {
1088    // In trait definitions, it is relevant for the public API whether an
1089    // associated constant comes with a default value, so even if we cannot
1090    // render its value, the presence of a value must be shown using `= _`.
1091    TraitDefault(&'a clean::ConstantKind),
1092    // In impls, there is no need to show `= _`.
1093    Impl(&'a clean::ConstantKind),
1094    None,
1095}
1096
1097fn assoc_const(
1098    it: &clean::Item,
1099    generics: &clean::Generics,
1100    ty: &clean::Type,
1101    value: AssocConstValue<'_>,
1102    link: AssocItemLink<'_>,
1103    indent: usize,
1104    cx: &Context<'_>,
1105) -> impl fmt::Display {
1106    let tcx = cx.tcx();
1107    fmt::from_fn(move |w| {
1108        render_attributes_in_code(w, it, &" ".repeat(indent), cx)?;
1109        write!(
1110            w,
1111            "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
1112            indent = " ".repeat(indent),
1113            vis = visibility_print_with_space(it, cx),
1114            href = assoc_href_attr(it, link, cx).maybe_display(),
1115            name = it.name.as_ref().unwrap(),
1116            generics = print_generics(generics, cx),
1117            ty = print_type(ty, cx),
1118        )?;
1119        if let AssocConstValue::TraitDefault(konst) | AssocConstValue::Impl(konst) = value {
1120            let repr = konst.expr(tcx);
1121            if match value {
1122                AssocConstValue::TraitDefault(_) => true, // always show
1123                // FIXME: Comparing against the special string "_" denoting overly complex const exprs
1124                //        is rather hacky; `ConstKind::expr` should have a richer return type.
1125                AssocConstValue::Impl(_) => repr != "_", // show if there is a meaningful value to show
1126                AssocConstValue::None => unreachable!(),
1127            } {
1128                write!(w, " = {}", Escape(&repr))?;
1129            }
1130        }
1131        write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display())
1132    })
1133}
1134
1135fn assoc_type(
1136    it: &clean::Item,
1137    generics: &clean::Generics,
1138    bounds: &[clean::GenericBound],
1139    default: Option<&clean::Type>,
1140    link: AssocItemLink<'_>,
1141    indent: usize,
1142    cx: &Context<'_>,
1143) -> impl fmt::Display {
1144    fmt::from_fn(move |w| {
1145        render_attributes_in_code(w, it, &" ".repeat(indent), cx)?;
1146        write!(
1147            w,
1148            "{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
1149            indent = " ".repeat(indent),
1150            vis = visibility_print_with_space(it, cx),
1151            href = assoc_href_attr(it, link, cx).maybe_display(),
1152            name = it.name.as_ref().unwrap(),
1153            generics = print_generics(generics, cx),
1154        )?;
1155        if !bounds.is_empty() {
1156            write!(w, ": {}", print_generic_bounds(bounds, cx))?;
1157        }
1158        // Render the default before the where-clause which aligns with the new recommended style. See #89122.
1159        if let Some(default) = default {
1160            write!(w, " = {}", print_type(default, cx))?;
1161        }
1162        write!(w, "{}", print_where_clause(generics, cx, indent, Ending::NoNewline).maybe_display())
1163    })
1164}
1165
1166fn assoc_method(
1167    meth: &clean::Item,
1168    g: &clean::Generics,
1169    d: &clean::FnDecl,
1170    link: AssocItemLink<'_>,
1171    parent: ItemType,
1172    cx: &Context<'_>,
1173    render_mode: RenderMode,
1174) -> impl fmt::Display {
1175    let tcx = cx.tcx();
1176    let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
1177    let name = meth.name.as_ref().unwrap();
1178    let vis = visibility_print_with_space(meth, cx).to_string();
1179    let defaultness = match meth.defaultness().expect("Expected assoc method to have defaultness") {
1180        Defaultness::Implicit => "",
1181        Defaultness::Final => "final ",
1182        Defaultness::Default => "default ",
1183    };
1184    // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
1185    // this condition.
1186    let constness = match render_mode {
1187        RenderMode::Normal => print_constness_with_space(
1188            &header.constness,
1189            meth.stable_since(tcx),
1190            meth.const_stability(tcx),
1191        ),
1192        RenderMode::ForDeref { .. } => "",
1193    };
1194
1195    fmt::from_fn(move |w| {
1196        let asyncness = header.asyncness.print_with_space();
1197        let safety = header.safety.print_with_space();
1198        let abi = print_abi_with_space(header.abi).to_string();
1199        let href = assoc_href_attr(meth, link, cx).maybe_display();
1200
1201        // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
1202        let generics_len = format!("{:#}", print_generics(g, cx)).len();
1203        let mut header_len = "fn ".len()
1204            + vis.len()
1205            + defaultness.len()
1206            + constness.len()
1207            + asyncness.len()
1208            + safety.len()
1209            + abi.len()
1210            + name.as_str().len()
1211            + generics_len;
1212
1213        let notable_traits = notable_traits_button(&d.output, cx).maybe_display();
1214
1215        let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
1216            header_len += 4;
1217            let indent_str = "    ";
1218            render_attributes_in_code(w, meth, indent_str, cx)?;
1219            (4, indent_str, Ending::NoNewline)
1220        } else {
1221            render_attributes_in_code(w, meth, "", cx)?;
1222            (0, "", Ending::Newline)
1223        };
1224        write!(
1225            w,
1226            "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
1227            <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
1228            indent = indent_str,
1229            generics = print_generics(g, cx),
1230            decl = full_print_fn_decl(d, header_len, indent, cx),
1231            where_clause = print_where_clause(g, cx, indent, end_newline).maybe_display(),
1232        )
1233    })
1234}
1235
1236/// Writes a span containing the versions at which an item became stable and/or const-stable. For
1237/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
1238/// write a span containing "1.0.0 (const: 1.45.0)".
1239///
1240/// Returns `None` if there is no stability annotation to be rendered.
1241///
1242/// Stability and const-stability are considered separately. If the item is unstable, no version
1243/// will be written. If the item is const-unstable, "const: unstable" will be appended to the
1244/// span, with a link to the tracking issue if present. If an item's stability or const-stability
1245/// version matches the version of its enclosing item, that version will be omitted.
1246///
1247/// Note that it is possible for an unstable function to be const-stable. In that case, the span
1248/// will include the const-stable version, but no stable version will be emitted, as a natural
1249/// consequence of the above rules.
1250fn render_stability_since_raw_with_extra(
1251    stable_version: Option<StableSince>,
1252    const_stability: Option<ConstStability>,
1253    extra_class: &str,
1254) -> Option<impl fmt::Display> {
1255    let mut title = String::new();
1256    let mut stability = String::new();
1257
1258    if let Some(version) = stable_version.and_then(|version| since_to_string(&version)) {
1259        stability.push_str(&version);
1260        title.push_str(&format!("Stable since Rust version {version}"));
1261    }
1262
1263    let const_title_and_stability = match const_stability {
1264        Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. }) => {
1265            since_to_string(&since)
1266                .map(|since| (format!("const since {since}"), format!("const: {since}")))
1267        }
1268        Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
1269            if stable_version.is_none() {
1270                // don't display const unstable if entirely unstable
1271                None
1272            } else {
1273                let unstable = if let Some(n) = issue {
1274                    format!(
1275                        "<a \
1276                        href=\"https://github.com/rust-lang/rust/issues/{n}\" \
1277                        title=\"Tracking issue for {feature}\"\
1278                       >unstable</a>"
1279                    )
1280                } else {
1281                    String::from("unstable")
1282                };
1283
1284                Some((String::from("const unstable"), format!("const: {unstable}")))
1285            }
1286        }
1287        _ => None,
1288    };
1289
1290    if let Some((const_title, const_stability)) = const_title_and_stability {
1291        if !title.is_empty() {
1292            title.push_str(&format!(", {const_title}"));
1293        } else {
1294            title.push_str(&const_title);
1295        }
1296
1297        if !stability.is_empty() {
1298            stability.push_str(&format!(" ({const_stability})"));
1299        } else {
1300            stability.push_str(&const_stability);
1301        }
1302    }
1303
1304    (!stability.is_empty()).then_some(fmt::from_fn(move |w| {
1305        write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#)
1306    }))
1307}
1308
1309fn since_to_string(since: &StableSince) -> Option<String> {
1310    match since {
1311        StableSince::Version(since) => Some(since.to_string()),
1312        StableSince::Current => Some(RustcVersion::CURRENT.to_string()),
1313        StableSince::Err(_) => None,
1314    }
1315}
1316
1317#[inline]
1318fn render_stability_since_raw(
1319    ver: Option<StableSince>,
1320    const_stability: Option<ConstStability>,
1321) -> Option<impl fmt::Display> {
1322    render_stability_since_raw_with_extra(ver, const_stability, "")
1323}
1324
1325fn render_assoc_item(
1326    item: &clean::Item,
1327    link: AssocItemLink<'_>,
1328    parent: ItemType,
1329    cx: &Context<'_>,
1330    render_mode: RenderMode,
1331) -> impl fmt::Display {
1332    fmt::from_fn(move |f| match &item.kind {
1333        clean::StrippedItem(..) => Ok(()),
1334        clean::RequiredMethodItem(m, _) | clean::MethodItem(m, _) => {
1335            assoc_method(item, &m.generics, &m.decl, link, parent, cx, render_mode).fmt(f)
1336        }
1337        clean::RequiredAssocConstItem(generics, ty) => assoc_const(
1338            item,
1339            generics,
1340            ty,
1341            AssocConstValue::None,
1342            link,
1343            if parent == ItemType::Trait { 4 } else { 0 },
1344            cx,
1345        )
1346        .fmt(f),
1347        clean::ProvidedAssocConstItem(ci) => assoc_const(
1348            item,
1349            &ci.generics,
1350            &ci.type_,
1351            AssocConstValue::TraitDefault(&ci.kind),
1352            link,
1353            if parent == ItemType::Trait { 4 } else { 0 },
1354            cx,
1355        )
1356        .fmt(f),
1357        clean::ImplAssocConstItem(ci) => assoc_const(
1358            item,
1359            &ci.generics,
1360            &ci.type_,
1361            AssocConstValue::Impl(&ci.kind),
1362            link,
1363            if parent == ItemType::Trait { 4 } else { 0 },
1364            cx,
1365        )
1366        .fmt(f),
1367        clean::RequiredAssocTypeItem(generics, bounds) => assoc_type(
1368            item,
1369            generics,
1370            bounds,
1371            None,
1372            link,
1373            if parent == ItemType::Trait { 4 } else { 0 },
1374            cx,
1375        )
1376        .fmt(f),
1377        clean::AssocTypeItem(ty, bounds) => assoc_type(
1378            item,
1379            &ty.generics,
1380            bounds,
1381            Some(ty.item_type.as_ref().unwrap_or(&ty.type_)),
1382            link,
1383            if parent == ItemType::Trait { 4 } else { 0 },
1384            cx,
1385        )
1386        .fmt(f),
1387        _ => panic!("render_assoc_item called on non-associated-item"),
1388    })
1389}
1390
1391#[derive(Copy, Clone)]
1392enum AssocItemLink<'a> {
1393    Anchor(Option<&'a str>),
1394    GotoSource(ItemId, &'a FxIndexSet<Symbol>),
1395}
1396
1397impl<'a> AssocItemLink<'a> {
1398    fn anchor(&self, id: &'a str) -> Self {
1399        match *self {
1400            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
1401            ref other => *other,
1402        }
1403    }
1404}
1405
1406fn write_section_heading(
1407    title: impl fmt::Display,
1408    id: &str,
1409    extra_class: Option<&str>,
1410    extra: impl fmt::Display,
1411) -> impl fmt::Display {
1412    fmt::from_fn(move |w| {
1413        let (extra_class, whitespace) = match extra_class {
1414            Some(extra) => (extra, " "),
1415            None => ("", ""),
1416        };
1417        write!(
1418            w,
1419            "<h2 id=\"{id}\" class=\"{extra_class}{whitespace}section-header\">\
1420            {title}\
1421            <a href=\"#{id}\" class=\"anchor\">§</a>\
1422         </h2>{extra}",
1423        )
1424    })
1425}
1426
1427fn write_impl_section_heading(title: impl fmt::Display, id: &str) -> impl fmt::Display {
1428    write_section_heading(title, id, None, "")
1429}
1430
1431fn render_all_impls(
1432    mut w: impl Write,
1433    cx: &Context<'_>,
1434    containing_item: &clean::Item,
1435    concrete_impls: Vec<&Impl>,
1436    auto_trait_impls: Vec<&Impl>,
1437    blanket_impls: Vec<&Impl>,
1438) -> fmt::Result {
1439    if !concrete_impls.is_empty() {
1440        let impls = render_impls(cx, concrete_impls, containing_item, true);
1441        write!(
1442            w,
1443            "{}<div id=\"trait-implementations-list\">{impls}</div>",
1444            write_impl_section_heading("Trait Implementations", "trait-implementations")
1445        )?;
1446    }
1447
1448    if !auto_trait_impls.is_empty() {
1449        let impls = render_impls(cx, auto_trait_impls, containing_item, false);
1450        // FIXME: Change the ID to `auto-trait-implementations-list`!
1451        write!(
1452            w,
1453            "{}<div id=\"synthetic-implementations-list\">{impls}</div>",
1454            write_impl_section_heading("Auto Trait Implementations", "synthetic-implementations",)
1455        )?;
1456    }
1457
1458    if !blanket_impls.is_empty() {
1459        let impls = render_impls(cx, blanket_impls, containing_item, false);
1460        write!(
1461            w,
1462            "{}<div id=\"blanket-implementations-list\">{impls}</div>",
1463            write_impl_section_heading("Blanket Implementations", "blanket-implementations")
1464        )?;
1465    }
1466
1467    Ok(())
1468}
1469
1470fn render_assoc_items(
1471    cx: &Context<'_>,
1472    containing_item: &clean::Item,
1473    it: DefId,
1474    what: AssocItemRender<'_>,
1475) -> impl fmt::Display {
1476    fmt::from_fn(move |f| {
1477        let mut derefs = DefIdSet::default();
1478        derefs.insert(it);
1479        render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs)
1480    })
1481}
1482
1483fn render_assoc_items_inner(
1484    mut w: &mut dyn fmt::Write,
1485    cx: &Context<'_>,
1486    containing_item: &clean::Item,
1487    it: DefId,
1488    what: AssocItemRender<'_>,
1489    derefs: &mut DefIdSet,
1490) -> fmt::Result {
1491    info!("Documenting associated items of {:?}", containing_item.name);
1492    let cache = &cx.shared.cache;
1493    let Some(impls) = cache.impls.get(&it) else { return Ok(()) };
1494    let (mut inherent_impls, trait_impls): (Vec<_>, _) =
1495        impls.iter().partition(|i| i.inner_impl().trait_.is_none());
1496    if !inherent_impls.is_empty() {
1497        let render_mode = what.render_mode(cx.tcx());
1498        let class_html = what
1499            .class()
1500            .map(|class| fmt::from_fn(move |f| write!(f, r#" class="{class}""#)))
1501            .maybe_display();
1502        let (section_heading, id) = match what {
1503            AssocItemRender::All => (
1504                Either::Left(write_impl_section_heading("Implementations", "implementations")),
1505                Cow::Borrowed("implementations-list"),
1506            ),
1507            AssocItemRender::DerefFor { trait_, type_, .. } => {
1508                let id = cx.derive_id(small_url_encode(format!(
1509                    "deref-methods-{:#}",
1510                    print_type(type_, cx)
1511                )));
1512                // the `impls.get` above only looks at the outermost type,
1513                // and the Deref impl may only be implemented for certain
1514                // values of generic parameters.
1515                // for example, if an item impls `Deref<[u8]>`,
1516                // we should not show methods from `[MaybeUninit<u8>]`.
1517                // this `retain` filters out any instances where
1518                // the types do not line up perfectly.
1519                inherent_impls.retain(|impl_| {
1520                    type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache)
1521                });
1522                let derived_id = cx.derive_id(&id);
1523                if let Some(def_id) = type_.def_id(cx.cache()) {
1524                    cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
1525                }
1526                (
1527                    Either::Right(fmt::from_fn(move |f| {
1528                        write!(
1529                            f,
1530                            "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
1531                            write_impl_section_heading(
1532                                fmt::from_fn(|f| write!(
1533                                    f,
1534                                    "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
1535                                    trait_ = print_path(trait_, cx),
1536                                    type_ = print_type(type_, cx),
1537                                )),
1538                                &id,
1539                            )
1540                        )
1541                    })),
1542                    Cow::Owned(derived_id),
1543                )
1544            }
1545        };
1546        let inherent_impls_buf = fmt::from_fn(|f| {
1547            inherent_impls
1548                .iter()
1549                .map(|i| {
1550                    render_impl(
1551                        cx,
1552                        i,
1553                        containing_item,
1554                        AssocItemLink::Anchor(None),
1555                        render_mode,
1556                        None,
1557                        &[],
1558                        ImplRenderingParameters {
1559                            show_def_docs: true,
1560                            show_default_items: true,
1561                            show_non_assoc_items: true,
1562                            toggle_open_by_default: true,
1563                        },
1564                    )
1565                })
1566                .joined("", f)
1567        })
1568        .to_string();
1569
1570        if !inherent_impls_buf.is_empty() {
1571            write!(
1572                w,
1573                "{section_heading}<div id=\"{id}\"{class_html}>{inherent_impls_buf}</div>{}",
1574                matches!(what, AssocItemRender::DerefFor { .. })
1575                    .then_some("</details>")
1576                    .maybe_display(),
1577            )?;
1578        }
1579    }
1580
1581    if !trait_impls.is_empty() {
1582        let deref_impl = trait_impls.iter().find(|t| {
1583            t.trait_did() == cx.tcx().lang_items().deref_trait() && !t.is_negative_trait_impl()
1584        });
1585        if let Some(impl_) = deref_impl {
1586            let has_deref_mut = trait_impls
1587                .iter()
1588                .any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
1589            render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs)?;
1590        }
1591
1592        // If we were already one level into rendering deref methods, we don't want to render
1593        // anything after recursing into any further deref methods above.
1594        if let AssocItemRender::DerefFor { .. } = what {
1595            return Ok(());
1596        }
1597
1598        let (auto_trait_impls, trait_impls): (Vec<&Impl>, Vec<&Impl>) =
1599            trait_impls.into_iter().partition(|t| t.inner_impl().kind.is_auto());
1600        let (blanket_impls, concrete_impls): (Vec<&Impl>, _) =
1601            trait_impls.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
1602
1603        render_all_impls(w, cx, containing_item, concrete_impls, auto_trait_impls, blanket_impls)?;
1604    }
1605    Ok(())
1606}
1607
1608/// `derefs` is the set of all deref targets that have already been handled.
1609fn render_deref_methods(
1610    mut w: impl Write,
1611    cx: &Context<'_>,
1612    impl_: &Impl,
1613    container_item: &clean::Item,
1614    deref_mut: bool,
1615    derefs: &mut DefIdSet,
1616) -> fmt::Result {
1617    let cache = cx.cache();
1618    let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
1619    let (target, real_target) = impl_
1620        .inner_impl()
1621        .items
1622        .iter()
1623        .find_map(|item| match item.kind {
1624            clean::AssocTypeItem(ref t, _) => Some(match *t {
1625                clean::TypeAlias { item_type: Some(ref type_), .. } => (type_, &t.type_),
1626                _ => (&t.type_, &t.type_),
1627            }),
1628            _ => None,
1629        })
1630        .expect("Expected associated type binding");
1631    debug!(
1632        "Render deref methods for {for_:#?}, target {target:#?}",
1633        for_ = impl_.inner_impl().for_
1634    );
1635    let what = AssocItemRender::DerefFor {
1636        trait_: deref_type,
1637        type_: real_target,
1638        deref_mut_: deref_mut,
1639        deref_impl_def_id: impl_.def_id(),
1640    };
1641    if let Some(did) = target.def_id(cache) {
1642        if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
1643            // `impl Deref<Target = S> for S`
1644            if did == type_did || !derefs.insert(did) {
1645                // Avoid infinite cycles
1646                return Ok(());
1647            }
1648        }
1649        render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs)?;
1650    } else if let Some(prim) = target.primitive_type()
1651        && let Some(&did) = cache.primitive_locations.get(&prim)
1652    {
1653        render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs)?;
1654    }
1655    Ok(())
1656}
1657
1658fn should_render_item(
1659    item: &clean::Item,
1660    deref_mut_: bool,
1661    tcx: TyCtxt<'_>,
1662    target_is_copy: bool,
1663) -> bool {
1664    let self_type_opt = match item.kind {
1665        clean::MethodItem(ref method, _) => method.decl.receiver_type(),
1666        clean::RequiredMethodItem(ref method, _) => method.decl.receiver_type(),
1667        _ => None,
1668    };
1669
1670    let Some(self_ty) = self_type_opt else { return false };
1671    let (by_mut_ref, by_box, by_value) = match *self_ty {
1672        clean::Type::BorrowedRef { mutability, .. } => {
1673            (mutability == Mutability::Mut, false, false)
1674        }
1675        clean::Type::Path { ref path } => {
1676            (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
1677        }
1678        clean::Type::SelfTy => (false, false, true),
1679        _ => (false, false, false),
1680    };
1681
1682    (deref_mut_ || !by_mut_ref) && !by_box && (!by_value || target_is_copy)
1683}
1684
1685/// `Box` has pass-through impls for `Read`, `Write`, `Iterator`, and `Future` when the
1686/// boxed type implements one of those. We don't want to treat every `Box` return
1687/// as being notably an `Iterator` (etc), though, so we exempt it. `Pin` has the same
1688/// issue, with a pass-through impl for `Future`.
1689fn is_notable_trait_passthrough(did: DefId, cx: &Context<'_>) -> bool {
1690    let lang_items = cx.tcx().lang_items();
1691    Some(did) == lang_items.owned_box() || Some(did) == lang_items.pin_type()
1692}
1693
1694fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<impl fmt::Display> {
1695    if ty.is_unit() {
1696        // Very common fast path.
1697        return None;
1698    }
1699
1700    let did = ty.def_id(cx.cache())?;
1701
1702    if is_notable_trait_passthrough(did, cx) {
1703        return None;
1704    }
1705
1706    let impls = cx.cache().impls.get(&did)?;
1707    let has_notable_trait = impls
1708        .iter()
1709        .map(Impl::inner_impl)
1710        .filter(|impl_| {
1711            impl_.polarity == ty::ImplPolarity::Positive
1712                // Two different types might have the same did,
1713                // without actually being the same.
1714                && ty.is_doc_subtype_of(&impl_.for_, cx.cache())
1715        })
1716        .filter_map(|impl_| impl_.trait_.as_ref())
1717        .filter_map(|trait_| cx.cache().traits.get(&trait_.def_id()))
1718        .any(|t| t.is_notable_trait(cx.tcx()));
1719
1720    has_notable_trait.then(|| {
1721        cx.types_with_notable_traits.borrow_mut().insert(ty.clone());
1722        fmt::from_fn(|f| {
1723            write!(
1724                f,
1725                " <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
1726                ty = Escape(&format!("{:#}", print_type(ty, cx))),
1727            )
1728        })
1729    })
1730}
1731
1732fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
1733    let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
1734
1735    let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
1736
1737    let out = fmt::from_fn(|f| {
1738        let mut notable_impls = impls
1739            .iter()
1740            .map(|impl_| impl_.inner_impl())
1741            .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
1742            .filter(|impl_| {
1743                // Two different types might have the same did, without actually being the same.
1744                ty.is_doc_subtype_of(&impl_.for_, cx.cache())
1745            })
1746            .filter_map(|impl_| {
1747                if let Some(trait_) = &impl_.trait_
1748                    && let trait_did = trait_.def_id()
1749                    && let Some(trait_) = cx.cache().traits.get(&trait_did)
1750                    && trait_.is_notable_trait(cx.tcx())
1751                {
1752                    Some((impl_, trait_did))
1753                } else {
1754                    None
1755                }
1756            })
1757            .peekable();
1758
1759        let has_notable_impl = if let Some((impl_, _)) = notable_impls.peek() {
1760            write!(
1761                f,
1762                "<h3>Notable traits for <code>{}</code></h3>\
1763                <pre><code>",
1764                print_type(&impl_.for_, cx),
1765            )?;
1766            true
1767        } else {
1768            false
1769        };
1770
1771        for (impl_, trait_did) in notable_impls {
1772            write!(f, "<div class=\"where\">{}</div>", print_impl(impl_, false, cx))?;
1773            for it in &impl_.items {
1774                let clean::AssocTypeItem(tydef, ..) = &it.kind else {
1775                    continue;
1776                };
1777
1778                let empty_set = FxIndexSet::default();
1779                let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
1780
1781                write!(
1782                    f,
1783                    "<div class=\"where\">    {};</div>",
1784                    assoc_type(
1785                        it,
1786                        &tydef.generics,
1787                        &[], // intentionally leaving out bounds
1788                        Some(&tydef.type_),
1789                        src_link,
1790                        0,
1791                        cx,
1792                    )
1793                )?;
1794            }
1795        }
1796
1797        if !has_notable_impl {
1798            f.write_str("</code></pre>")?;
1799        }
1800
1801        Ok(())
1802    })
1803    .to_string();
1804
1805    (format!("{:#}", print_type(ty, cx)), out)
1806}
1807
1808fn notable_traits_json<'a>(tys: impl Iterator<Item = &'a clean::Type>, cx: &Context<'_>) -> String {
1809    let mut mp = tys.map(|ty| notable_traits_decl(ty, cx)).collect::<IndexMap<_, _>>();
1810    mp.sort_unstable_keys();
1811    serde_json::to_string(&mp).expect("serialize (string, string) -> json object cannot fail")
1812}
1813
1814pub(crate) struct NotableTraitBadge {
1815    pub name: String,
1816    pub full_path: String,
1817    /// Relative URL to the trait page, or `None` if it cannot be linked.
1818    pub href: Option<String>,
1819}
1820
1821/// Returns all `#[doc(notable_trait)]` traits that `item` implements, to be
1822/// rendered as badges at the top of the item's page.
1823pub(crate) fn notable_trait_badges(item: &clean::Item, cx: &Context<'_>) -> Vec<NotableTraitBadge> {
1824    let tcx = cx.tcx();
1825    if let Some(def_id) = item.def_id()
1826        && !is_notable_trait_passthrough(def_id, cx)
1827        && let Some(impls) = cx.cache().impls.get(&def_id)
1828    {
1829        impls
1830            .iter()
1831            .map(Impl::inner_impl)
1832            .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
1833            .filter_map(|impl_| {
1834                if let Some(trait_) = &impl_.trait_
1835                    && let trait_did = trait_.def_id()
1836                    && let Some(trait_) = cx.cache().traits.get(&trait_did)
1837                    && trait_.is_notable_trait(tcx)
1838                {
1839                    let name = tcx.item_name(trait_did).to_string();
1840                    let (full_path, href) = match href(trait_did, cx) {
1841                        Ok(info) => (join_path_syms(&info.rust_path), Some(info.url)),
1842                        Err(_) => (tcx.def_path_str(trait_did), None),
1843                    };
1844                    Some((name.clone(), NotableTraitBadge { name, full_path, href }))
1845                } else {
1846                    None
1847                }
1848            })
1849            .collect::<BTreeMap<String, NotableTraitBadge>>()
1850            .into_values()
1851            .collect()
1852    } else {
1853        Vec::new()
1854    }
1855}
1856
1857#[derive(Clone, Copy, Debug)]
1858struct ImplRenderingParameters {
1859    show_def_docs: bool,
1860    show_default_items: bool,
1861    /// Whether or not to show methods.
1862    show_non_assoc_items: bool,
1863    toggle_open_by_default: bool,
1864}
1865
1866fn render_impl(
1867    cx: &Context<'_>,
1868    i: &Impl,
1869    parent: &clean::Item,
1870    link: AssocItemLink<'_>,
1871    render_mode: RenderMode,
1872    use_absolute: Option<bool>,
1873    aliases: &[String],
1874    rendering_params: ImplRenderingParameters,
1875) -> impl fmt::Display {
1876    fmt::from_fn(move |w| {
1877        let cache = &cx.shared.cache;
1878        let traits = &cache.traits;
1879        let trait_ = i.trait_did().map(|did| &traits[&did]);
1880        let mut close_tags = <Vec<&str>>::with_capacity(2);
1881
1882        // For trait implementations, the `interesting` output contains all methods that have doc
1883        // comments, and the `boring` output contains all methods that do not. The distinction is
1884        // used to allow hiding the boring methods.
1885        // `containing_item` is used for rendering stability info. If the parent is a trait impl,
1886        // `containing_item` will the grandparent, since trait impls can't have stability attached.
1887        fn doc_impl_item(
1888            boring: impl fmt::Write,
1889            interesting: impl fmt::Write,
1890            cx: &Context<'_>,
1891            item: &clean::Item,
1892            parent: &clean::Item,
1893            link: AssocItemLink<'_>,
1894            render_mode: RenderMode,
1895            is_default_item: bool,
1896            trait_: Option<&clean::Trait>,
1897            rendering_params: ImplRenderingParameters,
1898        ) -> fmt::Result {
1899            let item_type = item.type_();
1900            let name = item.name.as_ref().unwrap();
1901
1902            let render_method_item = rendering_params.show_non_assoc_items
1903                && match render_mode {
1904                    RenderMode::Normal => true,
1905                    RenderMode::ForDeref { mut_: deref_mut_, is_deref_target_copy } => {
1906                        should_render_item(item, deref_mut_, cx.tcx(), is_deref_target_copy)
1907                    }
1908                };
1909
1910            let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
1911
1912            let mut doc_buffer = String::new();
1913            let mut info_buffer = String::new();
1914            let mut short_documented = true;
1915
1916            let mut trait_item_deprecated = false;
1917            if render_method_item {
1918                if !is_default_item {
1919                    if let Some(t) = trait_ {
1920                        // The trait item may have been stripped so we might not
1921                        // find any documentation or stability for it.
1922                        if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
1923                            trait_item_deprecated = it.is_deprecated(cx.tcx());
1924                            // We need the stability of the item from the trait
1925                            // because impls can't have a stability.
1926                            if !item.doc_value().is_empty() {
1927                                document_item_info(cx, it, Some(parent))
1928                                    .render_into(&mut info_buffer)?;
1929                                doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
1930                                short_documented = false;
1931                            } else {
1932                                // In case the item isn't documented,
1933                                // provide short documentation from the trait.
1934                                doc_buffer = document_short(
1935                                    it,
1936                                    cx,
1937                                    link,
1938                                    parent,
1939                                    rendering_params.show_def_docs,
1940                                )
1941                                .to_string();
1942                            }
1943                        }
1944                    } else {
1945                        document_item_info(cx, item, Some(parent)).render_into(&mut info_buffer)?;
1946                        if rendering_params.show_def_docs {
1947                            doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
1948                            short_documented = false;
1949                        }
1950                    }
1951                } else {
1952                    doc_buffer =
1953                        document_short(item, cx, link, parent, rendering_params.show_def_docs)
1954                            .to_string();
1955                }
1956            }
1957            let mut w = if short_documented && trait_.is_some() {
1958                Either::Left(interesting)
1959            } else {
1960                Either::Right(boring)
1961            };
1962
1963            let mut deprecation_class = if trait_item_deprecated || item.is_deprecated(cx.tcx()) {
1964                " deprecated"
1965            } else {
1966                ""
1967            };
1968
1969            let toggled = !doc_buffer.is_empty();
1970            if toggled {
1971                let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
1972                write!(
1973                    w,
1974                    "<details class=\"toggle{method_toggle_class}{deprecation_class}\" open><summary>"
1975                )?;
1976                deprecation_class = "";
1977            }
1978            match &item.kind {
1979                clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
1980                    // Only render when the method is not static or we allow static methods
1981                    if render_method_item {
1982                        let id = cx.derive_id(format!("{item_type}.{name}"));
1983                        let source_id = trait_
1984                            .and_then(|trait_| {
1985                                trait_
1986                                    .items
1987                                    .iter()
1988                                    .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
1989                            })
1990                            .map(|item| format!("{}.{name}", item.type_()));
1991                        write!(
1992                            w,
1993                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
1994                                {}",
1995                            render_rightside(cx, item, render_mode)
1996                        )?;
1997                        if trait_.is_some() {
1998                            // Anchors are only used on trait impls.
1999                            write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
2000                        }
2001                        write!(
2002                            w,
2003                            "<h4 class=\"code-header\">{}</h4></section>",
2004                            render_assoc_item(
2005                                item,
2006                                link.anchor(source_id.as_ref().unwrap_or(&id)),
2007                                ItemType::Impl,
2008                                cx,
2009                                render_mode,
2010                            ),
2011                        )?;
2012                    }
2013                }
2014                clean::RequiredAssocConstItem(generics, ty) => {
2015                    if !matches!(render_mode, RenderMode::ForDeref { .. }) {
2016                        let source_id = format!("{item_type}.{name}");
2017                        let id = cx.derive_id(&source_id);
2018                        write!(
2019                            w,
2020                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
2021                                {}",
2022                            render_rightside(cx, item, render_mode)
2023                        )?;
2024                        if trait_.is_some() {
2025                            // Anchors are only used on trait impls.
2026                            write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
2027                        }
2028                        write!(
2029                            w,
2030                            "<h4 class=\"code-header\">{}</h4></section>",
2031                            assoc_const(
2032                                item,
2033                                generics,
2034                                ty,
2035                                AssocConstValue::None,
2036                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
2037                                0,
2038                                cx,
2039                            ),
2040                        )?;
2041                    }
2042                }
2043                clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
2044                    if !matches!(render_mode, RenderMode::ForDeref { .. }) {
2045                        let source_id = format!("{item_type}.{name}");
2046                        let id = cx.derive_id(&source_id);
2047                        write!(
2048                            w,
2049                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
2050                                {}",
2051                            render_rightside(cx, item, render_mode),
2052                        )?;
2053                        if trait_.is_some() {
2054                            // Anchors are only used on trait impls.
2055                            write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
2056                        }
2057                        write!(
2058                            w,
2059                            "<h4 class=\"code-header\">{}</h4></section>",
2060                            assoc_const(
2061                                item,
2062                                &ci.generics,
2063                                &ci.type_,
2064                                match item.kind {
2065                                    clean::ProvidedAssocConstItem(_) =>
2066                                        AssocConstValue::TraitDefault(&ci.kind),
2067                                    clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
2068                                    _ => unreachable!(),
2069                                },
2070                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
2071                                0,
2072                                cx,
2073                            ),
2074                        )?;
2075                    }
2076                }
2077                clean::RequiredAssocTypeItem(generics, bounds) => {
2078                    if !matches!(render_mode, RenderMode::ForDeref { .. }) {
2079                        let source_id = format!("{item_type}.{name}");
2080                        let id = cx.derive_id(&source_id);
2081                        write!(
2082                            w,
2083                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
2084                                {}",
2085                            render_rightside(cx, item, render_mode),
2086                        )?;
2087                        if trait_.is_some() {
2088                            // Anchors are only used on trait impls.
2089                            write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
2090                        }
2091                        write!(
2092                            w,
2093                            "<h4 class=\"code-header\">{}</h4></section>",
2094                            assoc_type(
2095                                item,
2096                                generics,
2097                                bounds,
2098                                None,
2099                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
2100                                0,
2101                                cx,
2102                            ),
2103                        )?;
2104                    }
2105                }
2106                clean::AssocTypeItem(tydef, _bounds) => {
2107                    if !matches!(render_mode, RenderMode::ForDeref { .. }) {
2108                        let source_id = format!("{item_type}.{name}");
2109                        let id = cx.derive_id(&source_id);
2110                        write!(
2111                            w,
2112                            "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
2113                                {}",
2114                            render_rightside(cx, item, render_mode),
2115                        )?;
2116                        if trait_.is_some() {
2117                            // Anchors are only used on trait impls.
2118                            write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
2119                        }
2120                        write!(
2121                            w,
2122                            "<h4 class=\"code-header\">{}</h4></section>",
2123                            assoc_type(
2124                                item,
2125                                &tydef.generics,
2126                                &[], // intentionally leaving out bounds
2127                                Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
2128                                link.anchor(if trait_.is_some() { &source_id } else { &id }),
2129                                0,
2130                                cx,
2131                            ),
2132                        )?;
2133                    }
2134                }
2135                clean::StrippedItem(..) => return Ok(()),
2136                _ => panic!("can't make docs for trait item with name {:?}", item.name),
2137            }
2138
2139            w.write_str(&info_buffer)?;
2140            if toggled {
2141                write!(w, "</summary>{doc_buffer}</details>")?;
2142            }
2143            Ok(())
2144        }
2145
2146        let mut impl_items = String::new();
2147        let mut default_impl_items = String::new();
2148        let impl_ = i.inner_impl();
2149
2150        // Impl items are grouped by kinds:
2151        //
2152        // 1. Constants
2153        // 2. Types
2154        // 3. Functions
2155        //
2156        // This order is because you can have associated constants used in associated types (like array
2157        // length), and both in associated functions. So with this order, when reading from top to
2158        // bottom, you should see items definitions before they're actually used most of the time.
2159        let mut assoc_types = Vec::new();
2160        let mut methods = Vec::new();
2161
2162        if !impl_.is_negative_trait_impl() {
2163            for impl_item in &impl_.items {
2164                match impl_item.kind {
2165                    clean::MethodItem(..) | clean::RequiredMethodItem(..) => {
2166                        methods.push(impl_item)
2167                    }
2168                    clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => {
2169                        assoc_types.push(impl_item)
2170                    }
2171                    clean::RequiredAssocConstItem(..)
2172                    | clean::ProvidedAssocConstItem(_)
2173                    | clean::ImplAssocConstItem(_) => {
2174                        // We render it directly since they're supposed to come first.
2175                        doc_impl_item(
2176                            &mut default_impl_items,
2177                            &mut impl_items,
2178                            cx,
2179                            impl_item,
2180                            if trait_.is_some() { &i.impl_item } else { parent },
2181                            link,
2182                            render_mode,
2183                            false,
2184                            trait_,
2185                            rendering_params,
2186                        )?;
2187                    }
2188                    _ => {}
2189                }
2190            }
2191
2192            for assoc_type in assoc_types {
2193                doc_impl_item(
2194                    &mut default_impl_items,
2195                    &mut impl_items,
2196                    cx,
2197                    assoc_type,
2198                    if trait_.is_some() { &i.impl_item } else { parent },
2199                    link,
2200                    render_mode,
2201                    false,
2202                    trait_,
2203                    rendering_params,
2204                )?;
2205            }
2206            for method in methods {
2207                doc_impl_item(
2208                    &mut default_impl_items,
2209                    &mut impl_items,
2210                    cx,
2211                    method,
2212                    if trait_.is_some() { &i.impl_item } else { parent },
2213                    link,
2214                    render_mode,
2215                    false,
2216                    trait_,
2217                    rendering_params,
2218                )?;
2219            }
2220        }
2221
2222        fn render_default_items(
2223            mut boring: impl fmt::Write,
2224            mut interesting: impl fmt::Write,
2225            cx: &Context<'_>,
2226            t: &clean::Trait,
2227            i: &clean::Impl,
2228            parent: &clean::Item,
2229            render_mode: RenderMode,
2230            rendering_params: ImplRenderingParameters,
2231        ) -> fmt::Result {
2232            for trait_item in &t.items {
2233                // Skip over any default trait items that are impossible to reference
2234                // (e.g. if it has a `Self: Sized` bound on an unsized type).
2235                if let Some(impl_def_id) = parent.item_id.as_def_id()
2236                    && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
2237                    && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
2238                {
2239                    continue;
2240                }
2241
2242                let n = trait_item.name;
2243                if i.items.iter().any(|m| m.name == n) {
2244                    continue;
2245                }
2246                let did = i.trait_.as_ref().unwrap().def_id();
2247                let provided_methods = i.provided_trait_methods(cx.tcx());
2248                let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
2249
2250                doc_impl_item(
2251                    &mut boring,
2252                    &mut interesting,
2253                    cx,
2254                    trait_item,
2255                    parent,
2256                    assoc_link,
2257                    render_mode,
2258                    true,
2259                    Some(t),
2260                    rendering_params,
2261                )?;
2262            }
2263            Ok(())
2264        }
2265
2266        // If we've implemented a trait, then also emit documentation for all
2267        // default items which weren't overridden in the implementation block.
2268        // We don't emit documentation for default items if they appear in the
2269        // Implementations on Foreign Types or Implementors sections.
2270        if rendering_params.show_default_items
2271            && let Some(t) = trait_
2272            && !impl_.is_negative_trait_impl()
2273        {
2274            render_default_items(
2275                &mut default_impl_items,
2276                &mut impl_items,
2277                cx,
2278                t,
2279                impl_,
2280                &i.impl_item,
2281                render_mode,
2282                rendering_params,
2283            )?;
2284        }
2285        if render_mode == RenderMode::Normal {
2286            let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
2287            let deprecation_attr = if impl_.is_deprecated
2288                || trait_.is_some_and(|trait_| trait_.is_deprecated(cx.tcx()))
2289            {
2290                " deprecated"
2291            } else {
2292                ""
2293            };
2294            if toggled {
2295                close_tags.push("</details>");
2296                write!(
2297                    w,
2298                    "<details class=\"toggle implementors-toggle{deprecation_attr}\"{}>\
2299                        <summary>",
2300                    if rendering_params.toggle_open_by_default { " open" } else { "" }
2301                )?;
2302            }
2303
2304            let (before_dox, after_dox) = i
2305                .impl_item
2306                .opt_doc_value()
2307                .map(|dox| {
2308                    Markdown {
2309                        content: &dox,
2310                        links: &i.impl_item.links(cx),
2311                        ids: &mut cx.id_map.borrow_mut(),
2312                        error_codes: cx.shared.codes,
2313                        edition: cx.shared.edition(),
2314                        playground: &cx.shared.playground,
2315                        heading_offset: HeadingOffset::H4,
2316                    }
2317                    .split_summary_and_content()
2318                })
2319                .unwrap_or((None, None));
2320
2321            write!(
2322                w,
2323                "{}",
2324                render_impl_summary(
2325                    cx,
2326                    i,
2327                    parent,
2328                    rendering_params.show_def_docs,
2329                    use_absolute,
2330                    aliases,
2331                    before_dox.as_deref(),
2332                    trait_.is_none() && impl_.items.is_empty(),
2333                )
2334            )?;
2335            if toggled {
2336                w.write_str("</summary>")?;
2337            }
2338
2339            if before_dox.is_some()
2340                && let Some(after_dox) = after_dox
2341            {
2342                write!(w, "<div class=\"docblock\">{after_dox}</div>")?;
2343            }
2344
2345            if !default_impl_items.is_empty() || !impl_items.is_empty() {
2346                w.write_str("<div class=\"impl-items\">")?;
2347                close_tags.push("</div>");
2348            }
2349        }
2350        if !default_impl_items.is_empty() || !impl_items.is_empty() {
2351            w.write_str(&default_impl_items)?;
2352            w.write_str(&impl_items)?;
2353        }
2354        for tag in close_tags.into_iter().rev() {
2355            w.write_str(tag)?;
2356        }
2357        Ok(())
2358    })
2359}
2360
2361// Render the items that appear on the right side of methods, impls, and
2362// associated types. For example "1.0.0 (const: 1.39.0) · source".
2363fn render_rightside(
2364    cx: &Context<'_>,
2365    item: &clean::Item,
2366    render_mode: RenderMode,
2367) -> impl fmt::Display {
2368    let tcx = cx.tcx();
2369
2370    fmt::from_fn(move |w| {
2371        // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
2372        // this condition.
2373        let const_stability = match render_mode {
2374            RenderMode::Normal => item.const_stability(tcx),
2375            RenderMode::ForDeref { .. } => None,
2376        };
2377        let src_href = cx.src_href(item);
2378        let stability = render_stability_since_raw_with_extra(
2379            item.stable_since(tcx),
2380            const_stability,
2381            if src_href.is_some() { "" } else { " rightside" },
2382        );
2383
2384        match (stability, src_href) {
2385            (Some(stability), Some(link)) => {
2386                write!(
2387                    w,
2388                    "<span class=\"rightside\">{stability} · <a class=\"src\" href=\"{link}\">Source</a></span>",
2389                )
2390            }
2391            (Some(stability), None) => {
2392                write!(w, "{stability}")
2393            }
2394            (None, Some(link)) => {
2395                write!(w, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
2396            }
2397            (None, None) => Ok(()),
2398        }
2399    })
2400}
2401
2402fn render_impl_summary(
2403    cx: &Context<'_>,
2404    i: &Impl,
2405    parent: &clean::Item,
2406    show_def_docs: bool,
2407    use_absolute: Option<bool>,
2408    // This argument is used to reference same type with different paths to avoid duplication
2409    // in documentation pages for trait with automatic implementations like "Send" and "Sync".
2410    aliases: &[String],
2411    doc: Option<&str>,
2412    impl_is_empty: bool,
2413) -> impl fmt::Display {
2414    fmt::from_fn(move |w| {
2415        let inner_impl = i.inner_impl();
2416        let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));
2417        let aliases = (!aliases.is_empty())
2418            .then_some(fmt::from_fn(|f| {
2419                write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f)))
2420            }))
2421            .maybe_display();
2422        write!(
2423            w,
2424            "<section id=\"{id}\" class=\"impl\"{aliases}>\
2425                {}\
2426                <a href=\"#{id}\" class=\"anchor\">§</a>\
2427                <h3 class=\"code-header\">",
2428            render_rightside(cx, &i.impl_item, RenderMode::Normal)
2429        )?;
2430
2431        if let Some(use_absolute) = use_absolute {
2432            write!(w, "{}", print_impl(inner_impl, use_absolute, cx))?;
2433            if show_def_docs {
2434                for it in &inner_impl.items {
2435                    if let clean::AssocTypeItem(ref tydef, ref _bounds) = it.kind {
2436                        write!(
2437                            w,
2438                            "<div class=\"where\">  {};</div>",
2439                            assoc_type(
2440                                it,
2441                                &tydef.generics,
2442                                &[], // intentionally leaving out bounds
2443                                Some(&tydef.type_),
2444                                AssocItemLink::Anchor(None),
2445                                0,
2446                                cx,
2447                            )
2448                        )?;
2449                    }
2450                }
2451            }
2452        } else {
2453            write!(w, "{}", print_impl(inner_impl, false, cx))?;
2454        }
2455        w.write_str("</h3>")?;
2456
2457        let is_trait = inner_impl.trait_.is_some();
2458        if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
2459            write!(
2460                w,
2461                "<span class=\"item-info\">\
2462                    <div class=\"stab portability\">{portability}</div>\
2463                </span>",
2464            )?;
2465        }
2466
2467        if let Some(doc) = doc {
2468            if impl_is_empty {
2469                w.write_str(
2470                    "\
2471<div class=\"item-info\">\
2472    <div class=\"stab empty-impl\">This impl block contains no public items.</div>\
2473</div>",
2474                )?;
2475            }
2476            write!(w, "<div class=\"docblock\">{doc}</div>")?;
2477        }
2478
2479        w.write_str("</section>")
2480    })
2481}
2482
2483pub(crate) fn small_url_encode(s: String) -> String {
2484    // These characters don't need to be escaped in a URI.
2485    // See https://url.spec.whatwg.org/#query-percent-encode-set
2486    // and https://url.spec.whatwg.org/#urlencoded-parsing
2487    // and https://url.spec.whatwg.org/#url-code-points
2488    fn dont_escape(c: u8) -> bool {
2489        c.is_ascii_alphanumeric()
2490            || c == b'-'
2491            || c == b'_'
2492            || c == b'.'
2493            || c == b','
2494            || c == b'~'
2495            || c == b'!'
2496            || c == b'\''
2497            || c == b'('
2498            || c == b')'
2499            || c == b'*'
2500            || c == b'/'
2501            || c == b';'
2502            || c == b':'
2503            || c == b'?'
2504            // As described in urlencoded-parsing, the
2505            // first `=` is the one that separates key from
2506            // value. Following `=`s are part of the value.
2507            || c == b'='
2508    }
2509    let mut st = String::new();
2510    let mut last_match = 0;
2511    for (idx, b) in s.bytes().enumerate() {
2512        if dont_escape(b) {
2513            continue;
2514        }
2515
2516        if last_match != idx {
2517            // Invariant: `idx` must be the first byte in a character at this point.
2518            st += &s[last_match..idx];
2519        }
2520        if b == b' ' {
2521            // URL queries are decoded with + replaced with SP.
2522            // While the same is not true for hashes, rustdoc only needs to be
2523            // consistent with itself when encoding them.
2524            st += "+";
2525        } else {
2526            write!(st, "%{b:02X}").unwrap();
2527        }
2528        // Invariant: if the current byte is not at the start of a multi-byte character,
2529        // we need to get down here so that when the next turn of the loop comes around,
2530        // last_match winds up equalling idx.
2531        //
2532        // In other words, dont_escape must always return `false` in multi-byte character.
2533        last_match = idx + 1;
2534    }
2535
2536    if last_match != 0 {
2537        st += &s[last_match..];
2538        st
2539    } else {
2540        s
2541    }
2542}
2543
2544fn get_id_for_impl(tcx: TyCtxt<'_>, impl_id: ItemId) -> String {
2545    use rustc_middle::ty::print::with_forced_trimmed_paths;
2546    let (type_, trait_) = match impl_id {
2547        ItemId::Auto { trait_, for_ } => {
2548            let ty = tcx.type_of(for_).skip_binder();
2549            (ty, Some(ty::TraitRef::new(tcx, trait_, [ty])))
2550        }
2551        ItemId::Blanket { impl_id, .. } | ItemId::DefId(impl_id) => {
2552            if let Some(trait_ref) = tcx.impl_opt_trait_ref(impl_id) {
2553                let trait_ref = trait_ref.skip_binder();
2554                (trait_ref.self_ty(), Some(trait_ref))
2555            } else {
2556                (tcx.type_of(impl_id).skip_binder(), None)
2557            }
2558        }
2559    };
2560    with_forced_trimmed_paths!(small_url_encode(if let Some(trait_) = trait_ {
2561        format!("impl-{trait_}-for-{type_}", trait_ = trait_.print_only_trait_path())
2562    } else {
2563        format!("impl-{type_}")
2564    }))
2565}
2566
2567fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
2568    match item.kind {
2569        clean::ItemKind::ImplItem(ref i) if i.trait_.is_some() => {
2570            // Alternative format produces no URLs,
2571            // so this parameter does nothing.
2572            Some((
2573                format!("{:#}", print_type(&i.for_, cx)),
2574                get_id_for_impl(cx.tcx(), item.item_id),
2575            ))
2576        }
2577        _ => None,
2578    }
2579}
2580
2581/// Returns the list of implementations for the primitive reference type, filtering out any
2582/// implementations that are on concrete or partially generic types, only keeping implementations
2583/// of the form `impl<T> Trait for &T`.
2584pub(crate) fn get_filtered_impls_for_reference<'a>(
2585    shared: &'a SharedContext<'_>,
2586    it: &clean::Item,
2587) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
2588    let def_id = it.item_id.expect_def_id();
2589    // If the reference primitive is somehow not defined, exit early.
2590    let Some(v) = shared.cache.impls.get(&def_id) else {
2591        return (Vec::new(), Vec::new(), Vec::new());
2592    };
2593    // Since there is no "direct implementation" on the reference primitive type, we filter out
2594    // every implementation which isn't a trait implementation.
2595    let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
2596    let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
2597        traits.partition(|t| t.inner_impl().kind.is_auto());
2598
2599    let (blanket_impl, concrete): (Vec<&Impl>, _) =
2600        concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
2601    // Now we keep only references over full generic types.
2602    let concrete: Vec<_> = concrete
2603        .into_iter()
2604        .filter(|t| match t.inner_impl().for_ {
2605            clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
2606            _ => false,
2607        })
2608        .collect();
2609
2610    (concrete, synthetic, blanket_impl)
2611}
2612
2613#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2614pub(crate) enum ItemSection {
2615    Reexports,
2616    PrimitiveTypes,
2617    Modules,
2618    Macros,
2619    Structs,
2620    Enums,
2621    Constants,
2622    Statics,
2623    Traits,
2624    Functions,
2625    TypeAliases,
2626    Unions,
2627    Implementations,
2628    TypeMethods,
2629    Methods,
2630    StructFields,
2631    Variants,
2632    AssociatedTypes,
2633    AssociatedConstants,
2634    ForeignTypes,
2635    Keywords,
2636    Attributes,
2637    AttributeMacros,
2638    DeriveMacros,
2639    TraitAliases,
2640}
2641
2642impl ItemSection {
2643    const ALL: &'static [Self] = {
2644        use ItemSection::*;
2645        // NOTE: The order here affects the order in the UI.
2646        // Keep this synchronized with addSidebarItems in main.js
2647        &[
2648            Reexports,
2649            PrimitiveTypes,
2650            Modules,
2651            Macros,
2652            Structs,
2653            Enums,
2654            Constants,
2655            Statics,
2656            Traits,
2657            Functions,
2658            TypeAliases,
2659            Unions,
2660            Implementations,
2661            TypeMethods,
2662            Methods,
2663            StructFields,
2664            Variants,
2665            AssociatedTypes,
2666            AssociatedConstants,
2667            ForeignTypes,
2668            Keywords,
2669            Attributes,
2670            AttributeMacros,
2671            DeriveMacros,
2672            TraitAliases,
2673        ]
2674    };
2675
2676    fn id(self) -> &'static str {
2677        match self {
2678            Self::Reexports => "reexports",
2679            Self::Modules => "modules",
2680            Self::Structs => "structs",
2681            Self::Unions => "unions",
2682            Self::Enums => "enums",
2683            Self::Functions => "functions",
2684            Self::TypeAliases => "types",
2685            Self::Statics => "statics",
2686            Self::Constants => "constants",
2687            Self::Traits => "traits",
2688            Self::Implementations => "impls",
2689            Self::TypeMethods => "tymethods",
2690            Self::Methods => "methods",
2691            Self::StructFields => "fields",
2692            Self::Variants => "variants",
2693            Self::Macros => "macros",
2694            Self::PrimitiveTypes => "primitives",
2695            Self::AssociatedTypes => "associated-types",
2696            Self::AssociatedConstants => "associated-consts",
2697            Self::ForeignTypes => "foreign-types",
2698            Self::Keywords => "keywords",
2699            Self::Attributes => "attribute-docs",
2700            Self::AttributeMacros => "attributes",
2701            Self::DeriveMacros => "derives",
2702            Self::TraitAliases => "trait-aliases",
2703        }
2704    }
2705
2706    fn name(self) -> &'static str {
2707        match self {
2708            Self::Reexports => "Re-exports",
2709            Self::Modules => "Modules",
2710            Self::Structs => "Structs",
2711            Self::Unions => "Unions",
2712            Self::Enums => "Enums",
2713            Self::Functions => "Functions",
2714            Self::TypeAliases => "Type Aliases",
2715            Self::Statics => "Statics",
2716            Self::Constants => "Constants",
2717            Self::Traits => "Traits",
2718            Self::Implementations => "Implementations",
2719            Self::TypeMethods => "Type Methods",
2720            Self::Methods => "Methods",
2721            Self::StructFields => "Struct Fields",
2722            Self::Variants => "Variants",
2723            Self::Macros => "Macros",
2724            Self::PrimitiveTypes => "Primitive Types",
2725            Self::AssociatedTypes => "Associated Types",
2726            Self::AssociatedConstants => "Associated Constants",
2727            Self::ForeignTypes => "Foreign Types",
2728            Self::Keywords => "Keywords",
2729            Self::Attributes => "Attributes",
2730            Self::AttributeMacros => "Attribute Macros",
2731            Self::DeriveMacros => "Derive Macros",
2732            Self::TraitAliases => "Trait Aliases",
2733        }
2734    }
2735}
2736
2737fn item_ty_to_section(ty: ItemType) -> ItemSection {
2738    match ty {
2739        ItemType::ExternCrate | ItemType::Import => ItemSection::Reexports,
2740        ItemType::Module => ItemSection::Modules,
2741        ItemType::Struct => ItemSection::Structs,
2742        ItemType::Union => ItemSection::Unions,
2743        ItemType::Enum => ItemSection::Enums,
2744        ItemType::Function => ItemSection::Functions,
2745        ItemType::TypeAlias => ItemSection::TypeAliases,
2746        ItemType::Static => ItemSection::Statics,
2747        ItemType::Constant => ItemSection::Constants,
2748        ItemType::Trait => ItemSection::Traits,
2749        ItemType::Impl => ItemSection::Implementations,
2750        ItemType::TyMethod => ItemSection::TypeMethods,
2751        ItemType::Method => ItemSection::Methods,
2752        ItemType::StructField => ItemSection::StructFields,
2753        ItemType::Variant => ItemSection::Variants,
2754        ItemType::Macro => ItemSection::Macros,
2755        ItemType::Primitive => ItemSection::PrimitiveTypes,
2756        ItemType::AssocType => ItemSection::AssociatedTypes,
2757        ItemType::AssocConst => ItemSection::AssociatedConstants,
2758        ItemType::ForeignType => ItemSection::ForeignTypes,
2759        ItemType::Keyword => ItemSection::Keywords,
2760        ItemType::Attribute => ItemSection::Attributes,
2761        ItemType::ProcAttribute | ItemType::DeclMacroAttribute => ItemSection::AttributeMacros,
2762        ItemType::ProcDerive | ItemType::DeclMacroDerive => ItemSection::DeriveMacros,
2763        ItemType::TraitAlias => ItemSection::TraitAliases,
2764    }
2765}
2766
2767/// Returns a list of all paths used in the type.
2768/// This is used to help deduplicate imported impls
2769/// for reexported types. If any of the contained
2770/// types are re-exported, we don't use the corresponding
2771/// entry from the js file, as inlining will have already
2772/// picked up the impl
2773fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec<String> {
2774    let mut out = Vec::new();
2775    let mut visited = FxHashSet::default();
2776    let mut work = VecDeque::new();
2777
2778    let mut process_path = |did: DefId| {
2779        let get_extern = || cache.external_paths.get(&did).map(|s| &s.0);
2780        let fqp = cache.exact_paths.get(&did).or_else(get_extern);
2781
2782        if let Some(path) = fqp {
2783            out.push(join_path_syms(path));
2784        }
2785    };
2786
2787    work.push_back(first_ty);
2788
2789    while let Some(ty) = work.pop_front() {
2790        if !visited.insert(ty) {
2791            continue;
2792        }
2793
2794        match ty {
2795            clean::Type::Path { path } => process_path(path.def_id()),
2796            clean::Type::Tuple(tys) => {
2797                work.extend(tys.iter());
2798            }
2799            clean::Type::Slice(ty) => {
2800                work.push_back(ty);
2801            }
2802            clean::Type::Array(ty, _) => {
2803                work.push_back(ty);
2804            }
2805            clean::Type::RawPointer(_, ty) => {
2806                work.push_back(ty);
2807            }
2808            clean::Type::BorrowedRef { type_, .. } => {
2809                work.push_back(type_);
2810            }
2811            clean::Type::QPath(clean::QPathData { self_type, trait_, .. }) => {
2812                work.push_back(self_type);
2813                if let Some(trait_) = trait_ {
2814                    process_path(trait_.def_id());
2815                }
2816            }
2817            _ => {}
2818        }
2819    }
2820    out
2821}
2822
2823const MAX_FULL_EXAMPLES: usize = 5;
2824const NUM_VISIBLE_LINES: usize = 10;
2825
2826/// Generates the HTML for example call locations generated via the --scrape-examples flag.
2827fn render_call_locations<W: fmt::Write>(
2828    mut w: W,
2829    cx: &Context<'_>,
2830    item: &clean::Item,
2831) -> fmt::Result {
2832    let tcx = cx.tcx();
2833    let def_id = item.item_id.expect_def_id();
2834    let key = tcx.def_path_hash(def_id);
2835    let Some(call_locations) = cx.shared.call_locations.get(&key) else { return Ok(()) };
2836
2837    // Generate a unique ID so users can link to this section for a given method
2838    let id = cx.derive_id("scraped-examples");
2839    write!(
2840        &mut w,
2841        "<div class=\"docblock scraped-example-list\">\
2842          <span></span>\
2843          <h5 id=\"{id}\">\
2844             <a href=\"#{id}\">Examples found in repository</a>\
2845             <a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
2846          </h5>",
2847        root_path = cx.root_path(),
2848        id = id
2849    )?;
2850
2851    // Create a URL to a particular location in a reverse-dependency's source file
2852    let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
2853        let (line_lo, line_hi) = loc.call_expr.line_span;
2854        let (anchor, title) = if line_lo == line_hi {
2855            ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
2856        } else {
2857            (
2858                format!("{}-{}", line_lo + 1, line_hi + 1),
2859                format!("lines {}-{}", line_lo + 1, line_hi + 1),
2860            )
2861        };
2862        let url = format!("{}{}#{anchor}", cx.root_path(), call_data.url);
2863        (url, title)
2864    };
2865
2866    // Generate the HTML for a single example, being the title and code block
2867    let write_example = |w: &mut W, (path, call_data): (&PathBuf, &CallData)| -> bool {
2868        let contents = match fs::read_to_string(path) {
2869            Ok(contents) => contents,
2870            Err(err) => {
2871                let span = item.span(tcx).map_or(DUMMY_SP, |span| span.inner());
2872                tcx.dcx().span_err(span, format!("failed to read file {}: {err}", path.display()));
2873                return false;
2874            }
2875        };
2876
2877        // To reduce file sizes, we only want to embed the source code needed to understand the example, not
2878        // the entire file. So we find the smallest byte range that covers all items enclosing examples.
2879        assert!(!call_data.locations.is_empty());
2880        let min_loc =
2881            call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
2882        let byte_min = min_loc.enclosing_item.byte_span.0;
2883        let line_min = min_loc.enclosing_item.line_span.0;
2884        let max_loc =
2885            call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
2886        let byte_max = max_loc.enclosing_item.byte_span.1;
2887        let line_max = max_loc.enclosing_item.line_span.1;
2888
2889        // The output code is limited to that byte range.
2890        let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
2891
2892        // The call locations need to be updated to reflect that the size of the program has changed.
2893        // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
2894        let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
2895            .locations
2896            .iter()
2897            .map(|loc| {
2898                let (byte_lo, byte_hi) = loc.call_ident.byte_span;
2899                let (line_lo, line_hi) = loc.call_expr.line_span;
2900                let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
2901
2902                let line_range = (line_lo - line_min, line_hi - line_min);
2903                let (line_url, line_title) = link_to_loc(call_data, loc);
2904
2905                (byte_range, (line_range, line_url, line_title))
2906            })
2907            .unzip();
2908
2909        let (_, init_url, init_title) = &line_ranges[0];
2910        let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
2911        let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
2912
2913        // For scraped examples, we don't need a real span from the SourceMap.
2914        // The URL is already provided in ScrapedInfo, and sources::print_src
2915        // will use that directly. We use DUMMY_SP as a placeholder.
2916        // Note: DUMMY_SP is safe here because href_from_span won't be called
2917        // for scraped examples.
2918        let file_span = rustc_span::DUMMY_SP;
2919
2920        let mut decoration_info = FxIndexMap::default();
2921        decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
2922        decoration_info.insert("highlight", byte_ranges);
2923
2924        sources::print_src(
2925            w,
2926            contents_subset,
2927            file_span,
2928            cx,
2929            cx.current.len(),
2930            &highlight::DecorationInfo(decoration_info),
2931            &sources::SourceContext::Embedded(sources::ScrapedInfo {
2932                needs_expansion,
2933                offset: line_min,
2934                name: &call_data.display_name,
2935                url: init_url,
2936                title: init_title,
2937                locations: locations_encoded,
2938            }),
2939        )
2940        .unwrap();
2941
2942        true
2943    };
2944
2945    // The call locations are output in sequence, so that sequence needs to be determined.
2946    // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
2947    // for determining relevance. We instead proxy relevance with the following heuristics:
2948    //   1. Code written to be an example is better than code not written to be an example, e.g.
2949    //      a snippet from examples/foo.rs is better than src/lib.rs. We don't know the Cargo
2950    //      directory structure in Rustdoc, so we proxy this by prioritizing code that comes from
2951    //      a --crate-type bin.
2952    //   2. Smaller examples are better than large examples. So we prioritize snippets that have
2953    //      the smallest number of lines in their enclosing item.
2954    //   3. Finally we sort by the displayed file name, which is arbitrary but prevents the
2955    //      ordering of examples from randomly changing between Rustdoc invocations.
2956    let ordered_locations = {
2957        fn sort_criterion<'a>(
2958            (_, call_data): &(&PathBuf, &'a CallData),
2959        ) -> (bool, u32, &'a String) {
2960            // Use the first location because that's what the user will see initially
2961            let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
2962            (!call_data.is_bin, hi - lo, &call_data.display_name)
2963        }
2964
2965        let mut locs = call_locations.iter().collect::<Vec<_>>();
2966        locs.sort_by_key(sort_criterion);
2967        locs
2968    };
2969
2970    let mut it = ordered_locations.into_iter().peekable();
2971
2972    // An example may fail to write if its source can't be read for some reason, so this method
2973    // continues iterating until a write succeeds
2974    let write_and_skip_failure = |w: &mut W, it: &mut Peekable<_>| {
2975        for example in it.by_ref() {
2976            if write_example(&mut *w, example) {
2977                break;
2978            }
2979        }
2980    };
2981
2982    // Write just one example that's visible by default in the method's description.
2983    write_and_skip_failure(&mut w, &mut it);
2984
2985    // Then add the remaining examples in a hidden section.
2986    if it.peek().is_some() {
2987        write!(
2988            w,
2989            "<details class=\"toggle more-examples-toggle\">\
2990                  <summary class=\"hideme\">\
2991                     <span>More examples</span>\
2992                  </summary>\
2993                  <div class=\"hide-more\">Hide additional examples</div>\
2994                  <div class=\"more-scraped-examples\">\
2995                    <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>"
2996        )?;
2997
2998        // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
2999        // make the page arbitrarily huge!
3000        for _ in 0..MAX_FULL_EXAMPLES {
3001            write_and_skip_failure(&mut w, &mut it);
3002        }
3003
3004        // For the remaining examples, generate a <ul> containing links to the source files.
3005        if it.peek().is_some() {
3006            w.write_str(
3007                r#"<div class="example-links">Additional examples can be found in:<br><ul>"#,
3008            )?;
3009            it.try_for_each(|(_, call_data)| {
3010                let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
3011                write!(
3012                    w,
3013                    r#"<li><a href="{url}">{name}</a></li>"#,
3014                    url = url,
3015                    name = call_data.display_name
3016                )
3017            })?;
3018            w.write_str("</ul></div>")?;
3019        }
3020
3021        w.write_str("</div></details>")?;
3022    }
3023
3024    w.write_str("</div>")
3025}
3026
3027fn render_attributes_in_code(
3028    w: &mut impl fmt::Write,
3029    item: &clean::Item,
3030    prefix: impl fmt::Display,
3031    cx: &Context<'_>,
3032) -> fmt::Result {
3033    render_attributes_in_code_with_options(w, item, prefix, cx, true, "")
3034}
3035
3036pub(super) fn render_attributes_in_code_with_options(
3037    w: &mut impl fmt::Write,
3038    item: &clean::Item,
3039    prefix: impl fmt::Display,
3040    cx: &Context<'_>,
3041    render_doc_hidden: bool,
3042    open_tag: &str,
3043) -> fmt::Result {
3044    w.write_str(open_tag)?;
3045    if render_doc_hidden && item.is_doc_hidden() {
3046        render_code_attribute(&prefix, "#[doc(hidden)]", w)?;
3047    }
3048    for attr in &item.attrs.other_attrs {
3049        let rustc_attr_ir::Attribute::Parsed(kind) = attr else { continue };
3050        let attr = match kind {
3051            AttributeKind::LinkSection { name, .. } => {
3052                Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}"))))
3053            }
3054            AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"),
3055            AttributeKind::ExportName { name, .. } => {
3056                Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}"))))
3057            }
3058            AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"),
3059            _ => continue,
3060        };
3061        render_code_attribute(&prefix, attr.as_ref(), w)?;
3062    }
3063
3064    if let Some(def_id) = item.def_id()
3065        && let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id)
3066    {
3067        render_code_attribute(prefix, &repr, w)?;
3068    }
3069    Ok(())
3070}
3071
3072fn render_repr_attribute_in_code(
3073    w: &mut impl fmt::Write,
3074    cx: &Context<'_>,
3075    def_id: DefId,
3076) -> fmt::Result {
3077    if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) {
3078        render_code_attribute("", &repr, w)?;
3079    }
3080    Ok(())
3081}
3082
3083fn render_code_attribute(
3084    prefix: impl fmt::Display,
3085    attr: impl fmt::Display,
3086    w: &mut impl fmt::Write,
3087) -> fmt::Result {
3088    write!(w, "<div class=\"code-attribute\">{prefix}{attr}</div>")
3089}
3090
3091/// Compute the *public* `#[repr]` of the item given by `DefId`.
3092///
3093/// Read more about it here:
3094/// <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
3095fn repr_attribute<'tcx>(
3096    tcx: TyCtxt<'tcx>,
3097    cache: &Cache,
3098    def_id: DefId,
3099) -> Option<Cow<'static, str>> {
3100    let adt = match tcx.def_kind(def_id) {
3101        DefKind::Struct | DefKind::Enum | DefKind::Union => tcx.adt_def(def_id),
3102        _ => return None,
3103    };
3104    let repr = adt.repr();
3105
3106    let is_visible = |def_id| cache.document_hidden || !tcx.is_doc_hidden(def_id);
3107    let is_public_field = |field: &ty::FieldDef| {
3108        (cache.document_private || field.vis.is_public()) && is_visible(field.did)
3109    };
3110
3111    // The transparent repr is public if
3112    // - the non-1-ZST field is public and visible or
3113    // - at least one field is public and visible if *all* fields are 1-ZSTs or
3114    // - the item is annotated with internal attribute `#[rustc_pub_transparent]`
3115    if repr.transparent() {
3116        let is_public = 'is_public: {
3117            if find_attr!(tcx, def_id, RustcPubTransparent(_)) {
3118                break 'is_public true;
3119            }
3120
3121            // `#[repr(transparent)]` can only be applied to structs and single-variant enums.
3122            let var = adt.variant(rustc_abi::FIRST_VARIANT); // the first and only variant
3123
3124            if !is_visible(var.def_id) {
3125                break 'is_public false;
3126            }
3127
3128            // Side note: There can only ever be one or zero non-1-ZST fields.
3129            let non_1zst_field = var.fields.iter().find(|field| {
3130                let ty = ty::TypingEnv::post_analysis(tcx, field.did)
3131                    .as_query_input(tcx.type_of(field.did).instantiate_identity().skip_norm_wip());
3132                tcx.layout_of(ty).is_ok_and(|layout| !layout.is_1zst())
3133            });
3134
3135            match non_1zst_field {
3136                Some(field) => is_public_field(field),
3137                None => var.fields.is_empty() || var.fields.iter().any(is_public_field),
3138            }
3139        };
3140
3141        // Since the transparent repr can't have any other reprs or
3142        // repr modifiers beside it, we can safely return early here.
3143        return is_public.then(|| "#[repr(transparent)]".into());
3144    }
3145
3146    // The repr is public iff all components are public and visible.
3147    let is_public = adt
3148        .variants()
3149        .iter()
3150        .all(|variant| is_visible(variant.def_id) && variant.fields.iter().all(is_public_field));
3151    if !is_public {
3152        return None;
3153    }
3154
3155    let mut result = Vec::<Cow<'_, _>>::new();
3156
3157    if repr.c() {
3158        result.push("C".into());
3159    }
3160    if repr.simd() {
3161        result.push("simd".into());
3162    }
3163    if let Some(int) = repr.int {
3164        let prefix = if int.is_signed() { 'i' } else { 'u' };
3165        let int = match int {
3166            rustc_abi::IntegerType::Pointer(_) => format!("{prefix}size"),
3167            rustc_abi::IntegerType::Fixed(int, _) => {
3168                format!("{prefix}{}", int.size().bytes() * 8)
3169            }
3170        };
3171        result.push(int.into());
3172    }
3173
3174    // Render modifiers last.
3175    if let Some(pack) = repr.pack {
3176        result.push(format!("packed({})", pack.bytes()).into());
3177    }
3178    if let Some(align) = repr.align {
3179        result.push(format!("align({})", align.bytes()).into());
3180    }
3181
3182    (!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into())
3183}
3184
3185pub(crate) fn compute_if_deref_target_implements_copy(tcx: TyCtxt<'_>, impl_def_id: DefId) -> bool {
3186    if let Some(impl_def_id) = impl_def_id.as_local()
3187        && let item = tcx.hir_expect_item(impl_def_id)
3188        && let rustc_hir::ItemKind::Impl(impl_item) = item.kind
3189    {
3190        for item in impl_item.items {
3191            let item = tcx.hir_impl_item(*item);
3192            if matches!(item.kind, rustc_hir::ImplItemKind::Type(_)) {
3193                let item_def_id = item.owner_id.to_def_id();
3194                let ty = tcx.type_of(item_def_id).instantiate_identity().skip_norm_wip();
3195                let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
3196                return tcx.type_is_copy_modulo_regions(typing_env, ty);
3197            }
3198        }
3199    }
3200    false
3201}