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, NotableTraitColor, RustcVersion,
56    StabilityLevel, 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, ItemKind, 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        if let ItemKind::Function(..)
832        | ItemKind::AssocFunction(clean::AssocFunction { body: Some(_), .. }) =
833            item.kind.unstripped()
834        {
835            render_call_locations(f, cx, item)?;
836        }
837        Ok(())
838    })
839}
840
841#[derive(Template)]
842#[template(path = "item_info.html")]
843struct ItemInfo {
844    items: Vec<ShortItemInfo>,
845}
846/// Add extra information about an item such as:
847///
848/// * Stability
849/// * Deprecated
850/// * Required features (through the `doc_cfg` feature)
851fn document_item_info(
852    cx: &Context<'_>,
853    item: &clean::Item,
854    parent: Option<&clean::Item>,
855) -> ItemInfo {
856    let items = short_item_info(item, cx, parent);
857    ItemInfo { items }
858}
859
860fn portability(item: &clean::Item, parent: Option<&clean::Item>) -> Option<String> {
861    let cfg = match (&item.cfg, parent.and_then(|p| p.cfg.as_ref())) {
862        (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg),
863        (cfg, _) => cfg.as_deref().cloned(),
864    };
865
866    debug!(
867        "Portability {name:?} {item_cfg:?} (parent: {parent:?}) - {parent_cfg:?} = {cfg:?}",
868        name = item.name,
869        item_cfg = item.cfg,
870        parent_cfg = parent.and_then(|p| p.cfg.as_ref()),
871    );
872
873    Some(cfg?.render_long_html())
874}
875
876#[derive(Template)]
877#[template(path = "short_item_info.html")]
878enum ShortItemInfo {
879    /// A message describing the deprecation of this item
880    Deprecation {
881        message: String,
882    },
883    /// The feature corresponding to an unstable item, and optionally
884    /// a tracking issue URL and number.
885    Unstable {
886        feature: String,
887        tracking: Option<(String, u32)>,
888    },
889    Portability {
890        message: String,
891    },
892}
893
894/// Render the stability, deprecation and portability information that is displayed at the top of
895/// the item's documentation.
896fn short_item_info(
897    item: &clean::Item,
898    cx: &Context<'_>,
899    parent: Option<&clean::Item>,
900) -> Vec<ShortItemInfo> {
901    let mut extra_info = vec![];
902
903    if let Some(depr @ Deprecation { note, since, suggestion: _ }) = item.deprecation(cx.tcx()) {
904        // We display deprecation messages for #[deprecated], but only display
905        // the future-deprecation messages for rustc versions.
906        let mut message = match since {
907            DeprecatedSince::RustcVersion(version) => {
908                if depr.is_in_effect() {
909                    format!("Deprecated since {version}")
910                } else {
911                    format!("Deprecating in {version}")
912                }
913            }
914            DeprecatedSince::Future => String::from("Deprecating in a future version"),
915            DeprecatedSince::NonStandard(since) => {
916                format!("Deprecated since {}", Escape(since.as_str()))
917            }
918            DeprecatedSince::Unspecified | DeprecatedSince::Err => String::from("Deprecated"),
919        };
920
921        if let Some(note) = note {
922            let note = note.as_str();
923            let mut id_map = cx.id_map.borrow_mut();
924            let links = item.links(cx);
925            let html = MarkdownItemInfo::new(note, &links, &mut id_map);
926            message.push_str(": ");
927            html.write_into(&mut message).unwrap();
928        }
929        extra_info.push(ShortItemInfo::Deprecation { message });
930    }
931
932    // Render unstable items. But don't render "rustc_private" crates (internal compiler crates).
933    // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere.
934    if let Some((StabilityLevel::Unstable { reason: _, issue, .. }, feature)) = item
935        .stability(cx.tcx())
936        .as_ref()
937        .filter(|stab| stab.feature != sym::rustc_private)
938        .map(|stab| (stab.level, stab.feature))
939    {
940        let tracking = if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue)
941        {
942            Some((url.clone(), issue.get()))
943        } else {
944            None
945        };
946        extra_info.push(ShortItemInfo::Unstable { feature: feature.to_string(), tracking });
947    }
948
949    if let Some(message) = portability(item, parent) {
950        extra_info.push(ShortItemInfo::Portability { message });
951    }
952
953    extra_info
954}
955
956// Prints the polarity and path of an impl's trait, if it has one, e.g. `Send`, `!Sync`.
957fn impl_trait_key(cx: &Context<'_>, i: &Impl) -> Option<String> {
958    let trait_ = i.inner_impl().trait_.as_ref()?;
959    let prefix = match i.inner_impl().polarity {
960        ty::ImplPolarity::Positive => "",
961        ty::ImplPolarity::Negative => "!",
962    };
963    Some(format!("{prefix}{:#}", print_path(trait_, cx)))
964}
965
966// Render the list of items inside one of the sections "Trait Implementations",
967// "Auto Trait Implementations," "Blanket Trait Implementations" (on struct/enum pages).
968fn render_impls<'a, 'cx>(
969    cx: &'a Context<'cx>,
970    mut impls: Vec<&'a Impl>,
971    containing_item: &'a clean::Item,
972    toggle_open_by_default: bool,
973) -> impl fmt::Display + use<'a, 'cx> {
974    impls.sort_by_cached_key(|imp| {
975        let prefix = match imp.inner_impl().polarity {
976            ty::ImplPolarity::Positive => Ordering::Greater,
977            ty::ImplPolarity::Negative => Ordering::Less,
978        };
979        (prefix, ImplString::new_path(imp, cx))
980    });
981    // Render each impl alongside its `impl_trait_key`, which is used as the primary sorting key
982    // to match the impl order in the sidebar.
983
984    fmt::from_fn(move |f| {
985        impls
986            .iter()
987            .map(|i| {
988                fmt::from_fn(|f| {
989                    let did = i.trait_did().unwrap();
990                    let provided_trait_methods = i.inner_impl().provided_trait_methods(cx.tcx());
991                    let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_trait_methods);
992                    render_impl(
993                        cx,
994                        i,
995                        containing_item,
996                        assoc_link,
997                        RenderMode::Normal,
998                        None,
999                        &[],
1000                        ImplRenderingParameters {
1001                            show_def_docs: true,
1002                            show_default_items: true,
1003                            show_non_assoc_items: true,
1004                            toggle_open_by_default,
1005                        },
1006                    )
1007                    .fmt(f)
1008                })
1009            })
1010            .joined("", f)
1011    })
1012}
1013
1014/// Build a (possibly empty) `href` attribute (a key-value pair) for the given associated item.
1015fn assoc_href_attr(
1016    it: &clean::Item,
1017    link: AssocItemLink<'_>,
1018    cx: &Context<'_>,
1019) -> Option<impl fmt::Display> {
1020    let name = it.name.unwrap();
1021    let item_type = it.type_();
1022
1023    enum Href<'a> {
1024        AnchorId(&'a str),
1025        Anchor(ItemType),
1026        Url(String, ItemType),
1027    }
1028
1029    let href = match link {
1030        AssocItemLink::Anchor(Some(id)) => Href::AnchorId(id),
1031        AssocItemLink::Anchor(None) => Href::Anchor(item_type),
1032        AssocItemLink::GotoSource(did, provided_methods) => {
1033            // We're creating a link from the implementation of an associated item to its
1034            // declaration in the trait declaration.
1035            let item_type = match item_type {
1036                ItemType::AssocFnWithBody | ItemType::AssocFnWithoutBody => {
1037                    if provided_methods.contains(&name) {
1038                        ItemType::AssocFnWithBody
1039                    } else {
1040                        ItemType::AssocFnWithoutBody
1041                    }
1042                }
1043                item_type => item_type,
1044            };
1045
1046            match href(did.expect_def_id(), cx) {
1047                Ok(HrefInfo { url, .. }) => Href::Url(url, item_type),
1048                // The link is broken since it points to an external crate that wasn't documented.
1049                // Do not create any link in such case. This is better than falling back to a
1050                // dummy anchor like `#{item_type}.{name}` representing the `id` of *this* impl item
1051                // (that used to happen in older versions). Indeed, in most cases this dummy would
1052                // coincide with the `id`. However, it would not always do so.
1053                // In general, this dummy would be incorrect:
1054                // If the type with the trait impl also had an inherent impl with an assoc. item of
1055                // the *same* name as this impl item, the dummy would link to that one even though
1056                // those two items are distinct!
1057                // In this scenario, the actual `id` of this impl item would be
1058                // `#{item_type}.{name}-{n}` for some number `n` (a disambiguator).
1059                Err(HrefError::DocumentationNotBuilt) => return None,
1060                Err(_) => Href::Anchor(item_type),
1061            }
1062        }
1063    };
1064
1065    let href = fmt::from_fn(move |f| match &href {
1066        Href::AnchorId(id) => write!(f, "#{id}"),
1067        Href::Url(url, item_type) => {
1068            write!(f, "{url}#{item_type}.{name}")
1069        }
1070        Href::Anchor(item_type) => {
1071            write!(f, "#{item_type}.{name}")
1072        }
1073    });
1074
1075    // If there is no `href` for the reason explained above, simply do not render it which is valid:
1076    // https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements
1077    Some(fmt::from_fn(move |f| write!(f, " href=\"{href}\"")))
1078}
1079
1080fn assoc_const(
1081    it: &clean::Item,
1082    ct: &clean::AssocConstant,
1083    parent: ItemType,
1084    link: AssocItemLink<'_>,
1085    indent: usize,
1086    ending: Ending,
1087    cx: &Context<'_>,
1088) -> impl fmt::Display {
1089    let tcx = cx.tcx();
1090    fmt::from_fn(move |w| {
1091        render_attributes_in_code(w, it, &" ".repeat(indent), cx)?;
1092        write!(
1093            w,
1094            "{indent}{vis}const <a{href} class=\"constant\">{name}</a>{generics}: {ty}",
1095            indent = " ".repeat(indent),
1096            vis = visibility_print_with_space(it, cx),
1097            href = assoc_href_attr(it, link, cx).maybe_display(),
1098            name = it.name.as_ref().unwrap(),
1099            generics = print_generics(&ct.generics, cx),
1100            ty = print_type(&ct.type_, cx),
1101        )?;
1102        if let Some(body) = &ct.body {
1103            let body = body.rendered(tcx);
1104            // In trait definitions, it is relevant for the public API whether an assoc const comes
1105            // with a default value, so even if we cannot render its value, the presence of a value
1106            // must be shown using `= _`. In impls, there is no need to show `= _`.
1107            //
1108            // FIXME: Comparing against the special string "_" (which denotes overly complex const
1109            //        exprs) is rather hacky; `ConstantKind::expr` should have a richer return type.
1110            if parent == ItemType::Trait || body != "_" {
1111                write!(w, " = {}", Escape(&body))?;
1112            }
1113        }
1114        let where_clause = print_where_clause(&ct.generics, cx, indent, ending).maybe_display();
1115        write!(w, "{where_clause}")
1116    })
1117}
1118
1119fn assoc_ty(
1120    it: &clean::Item,
1121    ty: &clean::AssocType,
1122    link: AssocItemLink<'_>,
1123    indent: usize,
1124    ending: Ending,
1125    cx: &Context<'_>,
1126) -> impl fmt::Display {
1127    fmt::from_fn(move |w| {
1128        render_attributes_in_code(w, it, &" ".repeat(indent), cx)?;
1129        write!(
1130            w,
1131            "{indent}{vis}type <a{href} class=\"associatedtype\">{name}</a>{generics}",
1132            indent = " ".repeat(indent),
1133            vis = visibility_print_with_space(it, cx),
1134            href = assoc_href_attr(it, link, cx).maybe_display(),
1135            name = it.name.as_ref().unwrap(),
1136            generics = print_generics(&ty.generics, cx),
1137        )?;
1138        if !ty.bounds.is_empty() {
1139            write!(w, ": {}", print_generic_bounds(&ty.bounds, cx))?;
1140        }
1141        // Render the aliased type before the where-clause which aligns with the new recommended style. See #89122.
1142        if let Some(type_) = &ty.type_ {
1143            let type_ = type_.middle_type.as_ref().unwrap_or(&type_.type_);
1144            write!(w, " = {}", print_type(type_, cx))?;
1145        }
1146        write!(w, "{}", print_where_clause(&ty.generics, cx, indent, ending).maybe_display())
1147    })
1148}
1149
1150fn assoc_fn(
1151    it: &clean::Item,
1152    fn_: &clean::AssocFunction,
1153    link: AssocItemLink<'_>,
1154    indent: usize,
1155    ending: Ending,
1156    render_mode: RenderMode,
1157    cx: &Context<'_>,
1158) -> impl fmt::Display {
1159    let tcx = cx.tcx();
1160    let header = it.fn_header(tcx).expect("Trying to get header from a non-function item");
1161    let name = it.name.as_ref().unwrap();
1162    let vis = visibility_print_with_space(it, cx).to_string();
1163    let defaultness = match fn_.body {
1164        Some(Defaultness::Implicit) | None => "",
1165        Some(Defaultness::Final) => "final ",
1166        Some(Defaultness::Default) => "default ",
1167    };
1168    // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
1169    // this condition.
1170    let constness = match render_mode {
1171        RenderMode::Normal => print_constness_with_space(
1172            &header.constness,
1173            it.stable_since(tcx),
1174            it.const_stability(tcx),
1175        ),
1176        RenderMode::ForDeref { .. } => "",
1177    };
1178
1179    fmt::from_fn(move |w| {
1180        let indent_str = " ".repeat(indent);
1181        render_attributes_in_code(w, it, &indent_str, cx)?;
1182
1183        let asyncness = header.asyncness.print_with_space();
1184        let safety = header.safety.print_with_space();
1185        let abi = print_abi_with_space(header.abi).to_string();
1186        let href = assoc_href_attr(it, link, cx).maybe_display();
1187
1188        // NOTE: `{:#}` does not print HTML formatting, `{}` does. So `g.print` can't be reused between the length calculation and `write!`.
1189        let generics_len = format!("{:#}", print_generics(&fn_.generics, cx)).len();
1190        let header_len = indent
1191            + "fn ".len()
1192            + vis.len()
1193            + defaultness.len()
1194            + constness.len()
1195            + asyncness.len()
1196            + safety.len()
1197            + abi.len()
1198            + name.as_str().len()
1199            + generics_len;
1200
1201        let notable_traits = notable_traits_button(&fn_.decl.output, cx).maybe_display();
1202
1203        write!(
1204            w,
1205            "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
1206            <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
1207            indent = indent_str,
1208            generics = print_generics(&fn_.generics, cx),
1209            decl = full_print_fn_decl(&fn_.decl, header_len, indent, cx),
1210            where_clause = print_where_clause(&fn_.generics, cx, indent, ending).maybe_display(),
1211        )
1212    })
1213}
1214
1215/// Writes a span containing the versions at which an item became stable and/or const-stable. For
1216/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
1217/// write a span containing "1.0.0 (const: 1.45.0)".
1218///
1219/// Returns `None` if there is no stability annotation to be rendered.
1220///
1221/// Stability and const-stability are considered separately. If the item is unstable, no version
1222/// will be written. If the item is const-unstable, "const: unstable" will be appended to the
1223/// span, with a link to the tracking issue if present. If an item's stability or const-stability
1224/// version matches the version of its enclosing item, that version will be omitted.
1225///
1226/// Note that it is possible for an unstable function to be const-stable. In that case, the span
1227/// will include the const-stable version, but no stable version will be emitted, as a natural
1228/// consequence of the above rules.
1229fn render_stability_since_raw_with_extra(
1230    stable_version: Option<StableSince>,
1231    const_stability: Option<ConstStability>,
1232    extra_class: &str,
1233) -> Option<impl fmt::Display> {
1234    let mut title = String::new();
1235    let mut stability = String::new();
1236
1237    if let Some(version) = stable_version.and_then(|version| since_to_string(&version)) {
1238        stability.push_str(&version);
1239        title.push_str(&format!("Stable since Rust version {version}"));
1240    }
1241
1242    let const_title_and_stability = match const_stability {
1243        Some(ConstStability { level: StabilityLevel::Stable { since, .. }, .. }) => {
1244            since_to_string(&since)
1245                .map(|since| (format!("const since {since}"), format!("const: {since}")))
1246        }
1247        Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
1248            if stable_version.is_none() {
1249                // don't display const unstable if entirely unstable
1250                None
1251            } else {
1252                let unstable = if let Some(n) = issue {
1253                    format!(
1254                        "<a \
1255                        href=\"https://github.com/rust-lang/rust/issues/{n}\" \
1256                        title=\"Tracking issue for {feature}\"\
1257                       >unstable</a>"
1258                    )
1259                } else {
1260                    String::from("unstable")
1261                };
1262
1263                Some((String::from("const unstable"), format!("const: {unstable}")))
1264            }
1265        }
1266        _ => None,
1267    };
1268
1269    if let Some((const_title, const_stability)) = const_title_and_stability {
1270        if !title.is_empty() {
1271            title.push_str(&format!(", {const_title}"));
1272        } else {
1273            title.push_str(&const_title);
1274        }
1275
1276        if !stability.is_empty() {
1277            stability.push_str(&format!(" ({const_stability})"));
1278        } else {
1279            stability.push_str(&const_stability);
1280        }
1281    }
1282
1283    (!stability.is_empty()).then_some(fmt::from_fn(move |w| {
1284        write!(w, r#"<span class="since{extra_class}" title="{title}">{stability}</span>"#)
1285    }))
1286}
1287
1288fn since_to_string(since: &StableSince) -> Option<String> {
1289    match since {
1290        StableSince::Version(since) => Some(since.to_string()),
1291        StableSince::Current => Some(RustcVersion::CURRENT.to_string()),
1292        StableSince::Err(_) => None,
1293    }
1294}
1295
1296#[inline]
1297fn render_stability_since_raw(
1298    ver: Option<StableSince>,
1299    const_stability: Option<ConstStability>,
1300) -> Option<impl fmt::Display> {
1301    render_stability_since_raw_with_extra(ver, const_stability, "")
1302}
1303
1304fn render_assoc_item(
1305    item: &clean::Item,
1306    link: AssocItemLink<'_>,
1307    parent: ItemType,
1308    indent: usize,
1309    ending: Ending,
1310    render_mode: RenderMode,
1311    cx: &Context<'_>,
1312) -> impl fmt::Display {
1313    fmt::from_fn(move |f| match &item.kind {
1314        ItemKind::Stripped(..) => Ok(()),
1315        ItemKind::AssocFunction(fn_) => {
1316            assoc_fn(item, fn_, link, indent, ending, render_mode, cx).fmt(f)
1317        }
1318        ItemKind::AssocConstant(ct) => {
1319            assoc_const(item, ct, parent, link, indent, ending, cx).fmt(f)
1320        }
1321        ItemKind::AssocType(ty) => assoc_ty(item, ty, link, indent, ending, cx).fmt(f),
1322        _ => panic!("render_assoc_item called on non-associated-item"),
1323    })
1324}
1325
1326#[derive(Copy, Clone)]
1327enum AssocItemLink<'a> {
1328    Anchor(Option<&'a str>),
1329    GotoSource(ItemId, &'a FxIndexSet<Symbol>),
1330}
1331
1332impl<'a> AssocItemLink<'a> {
1333    fn anchor(&self, id: &'a str) -> Self {
1334        match *self {
1335            AssocItemLink::Anchor(_) => AssocItemLink::Anchor(Some(id)),
1336            ref other => *other,
1337        }
1338    }
1339}
1340
1341fn write_section_heading(
1342    title: impl fmt::Display,
1343    id: &str,
1344    extra_class: Option<&str>,
1345    extra: impl fmt::Display,
1346) -> impl fmt::Display {
1347    fmt::from_fn(move |w| {
1348        let (extra_class, whitespace) = match extra_class {
1349            Some(extra) => (extra, " "),
1350            None => ("", ""),
1351        };
1352        write!(
1353            w,
1354            "<h2 id=\"{id}\" class=\"{extra_class}{whitespace}section-header\">\
1355            {title}\
1356            <a href=\"#{id}\" class=\"anchor\">§</a>\
1357         </h2>{extra}",
1358        )
1359    })
1360}
1361
1362fn write_impl_section_heading(title: impl fmt::Display, id: &str) -> impl fmt::Display {
1363    write_section_heading(title, id, None, "")
1364}
1365
1366fn render_all_impls(
1367    mut w: impl Write,
1368    cx: &Context<'_>,
1369    containing_item: &clean::Item,
1370    concrete_impls: Vec<&Impl>,
1371    auto_trait_impls: Vec<&Impl>,
1372    blanket_impls: Vec<&Impl>,
1373) -> fmt::Result {
1374    if !concrete_impls.is_empty() {
1375        let impls = render_impls(cx, concrete_impls, containing_item, true);
1376        write!(
1377            w,
1378            "{}<div id=\"trait-implementations-list\">{impls}</div>",
1379            write_impl_section_heading("Trait Implementations", "trait-implementations")
1380        )?;
1381    }
1382
1383    if !auto_trait_impls.is_empty() {
1384        let impls = render_impls(cx, auto_trait_impls, containing_item, false);
1385        // FIXME: Change the ID to `auto-trait-implementations-list`!
1386        write!(
1387            w,
1388            "{}<div id=\"synthetic-implementations-list\">{impls}</div>",
1389            write_impl_section_heading("Auto Trait Implementations", "synthetic-implementations",)
1390        )?;
1391    }
1392
1393    if !blanket_impls.is_empty() {
1394        let impls = render_impls(cx, blanket_impls, containing_item, false);
1395        write!(
1396            w,
1397            "{}<div id=\"blanket-implementations-list\">{impls}</div>",
1398            write_impl_section_heading("Blanket Implementations", "blanket-implementations")
1399        )?;
1400    }
1401
1402    Ok(())
1403}
1404
1405fn render_assoc_items(
1406    cx: &Context<'_>,
1407    containing_item: &clean::Item,
1408    it: DefId,
1409    what: AssocItemRender<'_>,
1410) -> impl fmt::Display {
1411    fmt::from_fn(move |f| {
1412        let mut derefs = DefIdSet::default();
1413        derefs.insert(it);
1414        render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs)
1415    })
1416}
1417
1418fn render_assoc_items_inner(
1419    mut w: &mut dyn fmt::Write,
1420    cx: &Context<'_>,
1421    containing_item: &clean::Item,
1422    it: DefId,
1423    what: AssocItemRender<'_>,
1424    derefs: &mut DefIdSet,
1425) -> fmt::Result {
1426    info!("Documenting associated items of {:?}", containing_item.name);
1427    let cache = &cx.shared.cache;
1428    let Some(impls) = cache.impls.get(&it) else { return Ok(()) };
1429    let (mut inherent_impls, trait_impls): (Vec<_>, _) =
1430        impls.iter().partition(|i| i.inner_impl().trait_.is_none());
1431    if !inherent_impls.is_empty() {
1432        let render_mode = what.render_mode(cx.tcx());
1433        let class_html = what
1434            .class()
1435            .map(|class| fmt::from_fn(move |f| write!(f, r#" class="{class}""#)))
1436            .maybe_display();
1437        let (section_heading, id) = match what {
1438            AssocItemRender::All => (
1439                Either::Left(write_impl_section_heading("Implementations", "implementations")),
1440                Cow::Borrowed("implementations-list"),
1441            ),
1442            AssocItemRender::DerefFor { trait_, type_, .. } => {
1443                let id = cx.derive_id(small_url_encode(format!(
1444                    "deref-methods-{:#}",
1445                    print_type(type_, cx)
1446                )));
1447                // the `impls.get` above only looks at the outermost type,
1448                // and the Deref impl may only be implemented for certain
1449                // values of generic parameters.
1450                // for example, if an item impls `Deref<[u8]>`,
1451                // we should not show methods from `[MaybeUninit<u8>]`.
1452                // this `retain` filters out any instances where
1453                // the types do not line up perfectly.
1454                inherent_impls.retain(|impl_| {
1455                    type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache)
1456                });
1457                let derived_id = cx.derive_id(&id);
1458                if let Some(def_id) = type_.def_id(cx.cache()) {
1459                    cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
1460                }
1461                (
1462                    Either::Right(fmt::from_fn(move |f| {
1463                        write!(
1464                            f,
1465                            "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
1466                            write_impl_section_heading(
1467                                fmt::from_fn(|f| write!(
1468                                    f,
1469                                    "<span>Methods from {trait_}&lt;Target = {type_}&gt;</span>",
1470                                    trait_ = print_path(trait_, cx),
1471                                    type_ = print_type(type_, cx),
1472                                )),
1473                                &id,
1474                            )
1475                        )
1476                    })),
1477                    Cow::Owned(derived_id),
1478                )
1479            }
1480        };
1481        let inherent_impls_buf = fmt::from_fn(|f| {
1482            inherent_impls
1483                .iter()
1484                .map(|i| {
1485                    render_impl(
1486                        cx,
1487                        i,
1488                        containing_item,
1489                        AssocItemLink::Anchor(None),
1490                        render_mode,
1491                        None,
1492                        &[],
1493                        ImplRenderingParameters {
1494                            show_def_docs: true,
1495                            show_default_items: true,
1496                            show_non_assoc_items: true,
1497                            toggle_open_by_default: true,
1498                        },
1499                    )
1500                })
1501                .joined("", f)
1502        })
1503        .to_string();
1504
1505        if !inherent_impls_buf.is_empty() {
1506            write!(
1507                w,
1508                "{section_heading}<div id=\"{id}\"{class_html}>{inherent_impls_buf}</div>{}",
1509                matches!(what, AssocItemRender::DerefFor { .. })
1510                    .then_some("</details>")
1511                    .maybe_display(),
1512            )?;
1513        }
1514    }
1515
1516    if !trait_impls.is_empty() {
1517        let deref_impl = trait_impls.iter().find(|t| {
1518            t.trait_did() == cx.tcx().lang_items().deref_trait() && !t.is_negative_trait_impl()
1519        });
1520        if let Some(impl_) = deref_impl {
1521            let has_deref_mut = trait_impls
1522                .iter()
1523                .any(|t| t.trait_did() == cx.tcx().lang_items().deref_mut_trait());
1524            render_deref_methods(&mut w, cx, impl_, containing_item, has_deref_mut, derefs)?;
1525        }
1526
1527        // If we were already one level into rendering deref methods, we don't want to render
1528        // anything after recursing into any further deref methods above.
1529        if let AssocItemRender::DerefFor { .. } = what {
1530            return Ok(());
1531        }
1532
1533        let (auto_trait_impls, trait_impls): (Vec<&Impl>, Vec<&Impl>) =
1534            trait_impls.into_iter().partition(|t| t.inner_impl().kind.is_auto());
1535        let (blanket_impls, concrete_impls): (Vec<&Impl>, _) =
1536            trait_impls.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
1537
1538        render_all_impls(w, cx, containing_item, concrete_impls, auto_trait_impls, blanket_impls)?;
1539    }
1540    Ok(())
1541}
1542
1543/// `derefs` is the set of all deref targets that have already been handled.
1544fn render_deref_methods(
1545    mut w: impl Write,
1546    cx: &Context<'_>,
1547    impl_: &Impl,
1548    container_item: &clean::Item,
1549    deref_mut: bool,
1550    derefs: &mut DefIdSet,
1551) -> fmt::Result {
1552    let cache = cx.cache();
1553    let deref_type = impl_.inner_impl().trait_.as_ref().unwrap();
1554    let (target, real_target) = impl_
1555        .inner_impl()
1556        .items
1557        .iter()
1558        .find_map(|item| match &item.kind {
1559            ItemKind::AssocType(clean::AssocType { type_: Some(type_), .. }) => {
1560                Some((type_.middle_type.as_ref().unwrap_or(&type_.type_), &type_.type_))
1561            }
1562            _ => None,
1563        })
1564        .expect("Expected associated type binding");
1565    debug!(
1566        "Render deref methods for {for_:#?}, target {target:#?}",
1567        for_ = impl_.inner_impl().for_
1568    );
1569    let what = AssocItemRender::DerefFor {
1570        trait_: deref_type,
1571        type_: real_target,
1572        deref_mut_: deref_mut,
1573        deref_impl_def_id: impl_.def_id(),
1574    };
1575    if let Some(did) = target.def_id(cache) {
1576        if let Some(type_did) = impl_.inner_impl().for_.def_id(cache) {
1577            // `impl Deref<Target = S> for S`
1578            if did == type_did || !derefs.insert(did) {
1579                // Avoid infinite cycles
1580                return Ok(());
1581            }
1582        }
1583        render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs)?;
1584    } else if let Some(prim) = target.primitive_type()
1585        && let Some(&did) = cache.primitive_locations.get(&prim)
1586    {
1587        render_assoc_items_inner(&mut w, cx, container_item, did, what, derefs)?;
1588    }
1589    Ok(())
1590}
1591
1592fn should_render_item_for_deref(
1593    item: &clean::Item,
1594    deref_mut_: bool,
1595    tcx: TyCtxt<'_>,
1596    target_is_copy: bool,
1597) -> bool {
1598    let ItemKind::AssocFunction(fn_) = &item.kind else { return false };
1599    let Some(self_ty) = fn_.decl.receiver_type() else { return false };
1600
1601    let (by_mut_ref, by_box, by_value) = match *self_ty {
1602        clean::Type::BorrowedRef { mutability, .. } => {
1603            (mutability == Mutability::Mut, false, false)
1604        }
1605        clean::Type::Path { ref path } => {
1606            (false, Some(path.def_id()) == tcx.lang_items().owned_box(), false)
1607        }
1608        clean::Type::SelfTy => (false, false, true),
1609        _ => (false, false, false),
1610    };
1611
1612    (deref_mut_ || !by_mut_ref) && !by_box && (!by_value || target_is_copy)
1613}
1614
1615/// `Box` has pass-through impls for `Read`, `Write`, `Iterator`, and `Future` when the
1616/// boxed type implements one of those. We don't want to treat every `Box` return
1617/// as being notably an `Iterator` (etc), though, so we exempt it. `Pin` has the same
1618/// issue, with a pass-through impl for `Future`.
1619fn is_notable_trait_passthrough(did: DefId, cx: &Context<'_>) -> bool {
1620    let lang_items = cx.tcx().lang_items();
1621    Some(did) == lang_items.owned_box() || Some(did) == lang_items.pin_type()
1622}
1623
1624fn notable_traits_button(ty: &clean::Type, cx: &Context<'_>) -> Option<impl fmt::Display> {
1625    if ty.is_unit() {
1626        // Very common fast path.
1627        return None;
1628    }
1629
1630    let did = ty.def_id(cx.cache())?;
1631
1632    if is_notable_trait_passthrough(did, cx) {
1633        return None;
1634    }
1635
1636    let impls = cx.cache().impls.get(&did)?;
1637    let has_notable_trait = impls
1638        .iter()
1639        .map(Impl::inner_impl)
1640        .filter(|impl_| {
1641            impl_.polarity == ty::ImplPolarity::Positive
1642                // Two different types might have the same did,
1643                // without actually being the same.
1644                && ty.is_doc_subtype_of(&impl_.for_, cx.cache())
1645        })
1646        .filter_map(|impl_| impl_.trait_.as_ref())
1647        .filter_map(|trait_| cx.cache().traits.get(&trait_.def_id()))
1648        .any(|t| t.is_notable_trait(cx.tcx()));
1649
1650    has_notable_trait.then(|| {
1651        cx.types_with_notable_traits.borrow_mut().insert(ty.clone());
1652        fmt::from_fn(|f| {
1653            write!(
1654                f,
1655                " <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
1656                ty = Escape(&format!("{:#}", print_type(ty, cx))),
1657            )
1658        })
1659    })
1660}
1661
1662fn notable_traits_decl_write_html<'cx>(
1663    notable_impls: impl Iterator<Item = (&'cx clean::Impl, DefId)>,
1664    f: &mut fmt::Formatter<'_>,
1665    cx: &Context<'_>,
1666) -> Result<(), fmt::Error> {
1667    let mut notable_impls = notable_impls.peekable();
1668    let code_tags_closing = if let Some((impl_, _)) = notable_impls.peek() {
1669        write!(
1670            f,
1671            "<h3>Notable traits for <code>{}</code></h3>\
1672            <pre><code>",
1673            print_type(&impl_.for_, cx),
1674        )?;
1675        "</code></pre>"
1676    } else {
1677        ""
1678    };
1679
1680    for (impl_, trait_did) in notable_impls {
1681        write!(f, "<div class=\"where\">{}</div>", print_impl(impl_, false, cx))?;
1682        for it in &impl_.items {
1683            let ItemKind::AssocType(ty @ clean::AssocType { type_: Some(_), .. }) = &it.kind else {
1684                continue;
1685            };
1686
1687            let empty_set = FxIndexSet::default();
1688            let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
1689
1690            write!(
1691                f,
1692                "<div class=\"where\">    {};</div>",
1693                assoc_ty(it, ty, src_link, 0, Ending::Newline, cx)
1694            )?;
1695        }
1696    }
1697
1698    f.write_str(code_tags_closing)
1699}
1700
1701fn notable_traits_decl_for_type(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
1702    let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");
1703
1704    let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");
1705
1706    let out = fmt::from_fn(|f| {
1707        let notable_impls = impls
1708            .iter()
1709            .map(|impl_| impl_.inner_impl())
1710            .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
1711            .filter(|impl_| {
1712                // Two different types might have the same did, without actually being the same.
1713                ty.is_doc_subtype_of(&impl_.for_, cx.cache())
1714            })
1715            .filter_map(|impl_| {
1716                if let Some(trait_) = &impl_.trait_
1717                    && let trait_did = trait_.def_id()
1718                    && let Some(trait_) = cx.cache().traits.get(&trait_did)
1719                    && trait_.is_notable_trait(cx.tcx())
1720                {
1721                    Some((impl_, trait_did))
1722                } else {
1723                    None
1724                }
1725            });
1726
1727        notable_traits_decl_write_html(notable_impls, f, cx)
1728    })
1729    .to_string();
1730
1731    (format!("{:#}", print_type(ty, cx)), out)
1732}
1733
1734fn notable_traits_decl_for_item(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
1735    let out = fmt::from_fn(|f| {
1736        let notable_impls = if let Some(def_id) = item.def_id()
1737            && !is_notable_trait_passthrough(def_id, cx)
1738            && let Some(impls) = cx.cache().impls.get(&def_id)
1739        {
1740            impls
1741                .iter()
1742                .map(Impl::inner_impl)
1743                .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
1744                .filter_map(|impl_| {
1745                    if let Some(trait_) = &impl_.trait_
1746                        && let trait_did = trait_.def_id()
1747                        && let Some(trait_) = cx.cache().traits.get(&trait_did)
1748                        && trait_.is_notable_trait(cx.tcx())
1749                    {
1750                        Some((impl_, trait_did))
1751                    } else {
1752                        None
1753                    }
1754                })
1755        } else {
1756            return Ok(());
1757        };
1758        notable_traits_decl_write_html(notable_impls, f, cx)
1759    })
1760    .to_string();
1761
1762    Some((item.name?.to_string(), out))
1763}
1764
1765fn notable_traits_json<'a>(
1766    tys: impl Iterator<Item = &'a clean::Type>,
1767    item: &clean::Item,
1768    cx: &Context<'_>,
1769) -> String {
1770    let mut mp = tys.map(|ty| notable_traits_decl_for_type(ty, cx)).collect::<IndexMap<_, _>>();
1771    if let Some((item_name, item_decl)) = notable_traits_decl_for_item(item, cx)
1772        && !item_decl.is_empty()
1773    {
1774        mp.insert(item_name, item_decl);
1775    }
1776    mp.sort_unstable_keys();
1777    serde_json::to_string(&mp).expect("serialize (string, string) -> json object cannot fail")
1778}
1779
1780pub(crate) struct NotableTraitBadge {
1781    pub name: String,
1782    pub full_path: String,
1783    /// Relative URL to the trait page, or `None` if it cannot be linked.
1784    pub href: Option<String>,
1785    /// One of the color names.
1786    pub color: NotableTraitColor,
1787}
1788
1789/// Returns all `#[doc(notable_trait)]` traits that `item` implements, to be
1790/// rendered as badges at the top of the item's page.
1791pub(crate) fn notable_trait_badges(item: &clean::Item, cx: &Context<'_>) -> Vec<NotableTraitBadge> {
1792    let tcx = cx.tcx();
1793    if let Some(def_id) = item.def_id()
1794        && !is_notable_trait_passthrough(def_id, cx)
1795        && let Some(impls) = cx.cache().impls.get(&def_id)
1796    {
1797        impls
1798            .iter()
1799            .map(Impl::inner_impl)
1800            .filter(|impl_| impl_.polarity == ty::ImplPolarity::Positive)
1801            .filter_map(|impl_| {
1802                if let Some(trait_) = &impl_.trait_
1803                    && let trait_did = trait_.def_id()
1804                    && cx.cache().traits.contains_key(&trait_did)
1805                    && let Some(&color) = tcx.doc_notable_trait(trait_did)
1806                {
1807                    let name = tcx.item_name(trait_did).to_string();
1808                    let (full_path, href) = match href(trait_did, cx) {
1809                        Ok(info) => (join_path_syms(&info.rust_path), Some(info.url)),
1810                        Err(_) => (tcx.def_path_str(trait_did), None),
1811                    };
1812                    Some((name.clone(), NotableTraitBadge { name, full_path, href, color }))
1813                } else {
1814                    None
1815                }
1816            })
1817            .collect::<BTreeMap<String, NotableTraitBadge>>()
1818            .into_values()
1819            .collect()
1820    } else {
1821        Vec::new()
1822    }
1823}
1824
1825#[derive(Clone, Copy, Debug)]
1826struct ImplRenderingParameters {
1827    show_def_docs: bool,
1828    show_default_items: bool,
1829    /// Whether or not to show methods.
1830    show_non_assoc_items: bool,
1831    toggle_open_by_default: bool,
1832}
1833
1834fn render_impl(
1835    cx: &Context<'_>,
1836    i: &Impl,
1837    parent: &clean::Item,
1838    link: AssocItemLink<'_>,
1839    render_mode: RenderMode,
1840    use_absolute: Option<bool>,
1841    aliases: &[String],
1842    rendering_params: ImplRenderingParameters,
1843) -> impl fmt::Display {
1844    fmt::from_fn(move |w| {
1845        let cache = &cx.shared.cache;
1846        let traits = &cache.traits;
1847        let trait_ = i.trait_did().map(|did| &traits[&did]);
1848        let mut close_tags = <Vec<&str>>::with_capacity(2);
1849
1850        // For trait implementations, the `interesting` output contains all methods that have doc
1851        // comments, and the `boring` output contains all methods that do not. The distinction is
1852        // used to allow hiding the boring methods.
1853        // `containing_item` is used for rendering stability info. If the parent is a trait impl,
1854        // `containing_item` will the grandparent, since trait impls can't have stability attached.
1855        fn doc_impl_item(
1856            boring: impl fmt::Write,
1857            interesting: impl fmt::Write,
1858            cx: &Context<'_>,
1859            item: &clean::Item,
1860            parent: &clean::Item,
1861            link: AssocItemLink<'_>,
1862            render_mode: RenderMode,
1863            is_default_item: bool,
1864            trait_: Option<&clean::Trait>,
1865            rendering_params: ImplRenderingParameters,
1866        ) -> fmt::Result {
1867            let item_type = item.type_();
1868            let name = item.name.as_ref().unwrap();
1869
1870            let render_assoc_fn = rendering_params.show_non_assoc_items
1871                && match render_mode {
1872                    RenderMode::Normal => true,
1873                    RenderMode::ForDeref { mut_: deref_mut_, is_deref_target_copy } => {
1874                        should_render_item_for_deref(
1875                            item,
1876                            deref_mut_,
1877                            cx.tcx(),
1878                            is_deref_target_copy,
1879                        )
1880                    }
1881                };
1882
1883            let in_trait_class = if trait_.is_some() { " trait-impl" } else { "" };
1884
1885            let mut doc_buffer = String::new();
1886            let mut info_buffer = String::new();
1887            let mut short_documented = true;
1888
1889            let mut trait_item_deprecated = false;
1890            if render_assoc_fn {
1891                if !is_default_item {
1892                    if let Some(t) = trait_ {
1893                        // The trait item may have been stripped so we might not
1894                        // find any documentation or stability for it.
1895                        if let Some(it) = t.items.iter().find(|i| i.name == item.name) {
1896                            trait_item_deprecated = it.is_deprecated(cx.tcx());
1897                            // We need the stability of the item from the trait
1898                            // because impls can't have a stability.
1899                            if !item.doc_value().is_empty() {
1900                                document_item_info(cx, it, Some(parent))
1901                                    .render_into(&mut info_buffer)?;
1902                                doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
1903                                short_documented = false;
1904                            } else {
1905                                // In case the item isn't documented,
1906                                // provide short documentation from the trait.
1907                                doc_buffer = document_short(
1908                                    it,
1909                                    cx,
1910                                    link,
1911                                    parent,
1912                                    rendering_params.show_def_docs,
1913                                )
1914                                .to_string();
1915                            }
1916                        }
1917                    } else {
1918                        document_item_info(cx, item, Some(parent)).render_into(&mut info_buffer)?;
1919                        if rendering_params.show_def_docs {
1920                            doc_buffer = document_full(item, cx, HeadingOffset::H5).to_string();
1921                            short_documented = false;
1922                        }
1923                    }
1924                } else {
1925                    doc_buffer =
1926                        document_short(item, cx, link, parent, rendering_params.show_def_docs)
1927                            .to_string();
1928                }
1929            }
1930            let mut w = if short_documented && trait_.is_some() {
1931                Either::Left(interesting)
1932            } else {
1933                Either::Right(boring)
1934            };
1935
1936            let mut deprecation_class = if trait_item_deprecated || item.is_deprecated(cx.tcx()) {
1937                " deprecated"
1938            } else {
1939                ""
1940            };
1941
1942            let toggled = !doc_buffer.is_empty();
1943            if toggled {
1944                let method_toggle_class =
1945                    if item_type.is_assoc_fn() { " method-toggle" } else { "" };
1946                write!(
1947                    w,
1948                    "<details class=\"toggle{method_toggle_class}{deprecation_class}\" open><summary>"
1949                )?;
1950                deprecation_class = "";
1951            }
1952            match &item.kind {
1953                ItemKind::AssocFunction(_) if !render_assoc_fn => {}
1954                ItemKind::AssocConstant(_) | ItemKind::AssocType(_)
1955                    if let RenderMode::ForDeref { .. } = render_mode => {}
1956
1957                ItemKind::AssocFunction(_) => {
1958                    let id = cx.derive_id(format!("{item_type}.{name}"));
1959                    let source_id = trait_
1960                        .and_then(|trait_| {
1961                            trait_
1962                                .items
1963                                .iter()
1964                                .find(|item| item.name.map(|n| n == *name).unwrap_or(false))
1965                        })
1966                        .map(|item| format!("{}.{name}", item.type_()));
1967                    write!(
1968                        w,
1969                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
1970                        {}",
1971                        render_rightside(cx, item, render_mode)
1972                    )?;
1973                    if trait_.is_some() {
1974                        // Anchors are only used on trait impls.
1975                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
1976                    }
1977                    write!(
1978                        w,
1979                        "<h4 class=\"code-header\">{}</h4></section>",
1980                        render_assoc_item(
1981                            item,
1982                            link.anchor(source_id.as_ref().unwrap_or(&id)),
1983                            ItemType::Impl,
1984                            0,
1985                            Ending::Newline,
1986                            render_mode,
1987                            cx,
1988                        ),
1989                    )?;
1990                }
1991                ItemKind::AssocConstant(ct) => {
1992                    let source_id = format!("{item_type}.{name}");
1993                    let id = cx.derive_id(&source_id);
1994                    write!(
1995                        w,
1996                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
1997                        {}",
1998                        render_rightside(cx, item, render_mode),
1999                    )?;
2000                    if trait_.is_some() {
2001                        // Anchors are only used on trait impls.
2002                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
2003                    }
2004                    write!(
2005                        w,
2006                        "<h4 class=\"code-header\">{}</h4></section>",
2007                        assoc_const(
2008                            item,
2009                            ct,
2010                            ItemType::Impl,
2011                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
2012                            0,
2013                            Ending::Newline,
2014                            cx,
2015                        ),
2016                    )?;
2017                }
2018                ItemKind::AssocType(ty) => {
2019                    let source_id = format!("{item_type}.{name}");
2020                    let id = cx.derive_id(&source_id);
2021                    write!(
2022                        w,
2023                        "<section id=\"{id}\" class=\"{item_type}{in_trait_class}{deprecation_class}\">\
2024                            {}",
2025                        render_rightside(cx, item, render_mode),
2026                    )?;
2027                    if trait_.is_some() {
2028                        // Anchors are only used on trait impls.
2029                        write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
2030                    }
2031                    write!(
2032                        w,
2033                        "<h4 class=\"code-header\">{}</h4></section>",
2034                        assoc_ty(
2035                            item,
2036                            ty,
2037                            link.anchor(if trait_.is_some() { &source_id } else { &id }),
2038                            0,
2039                            Ending::Newline,
2040                            cx,
2041                        ),
2042                    )?;
2043                }
2044                ItemKind::Stripped(..) => return Ok(()),
2045                _ => panic!("can't make docs for trait item with name {:?}", item.name),
2046            }
2047
2048            w.write_str(&info_buffer)?;
2049            if toggled {
2050                write!(w, "</summary>{doc_buffer}</details>")?;
2051            }
2052            Ok(())
2053        }
2054
2055        let mut impl_items = String::new();
2056        let mut default_impl_items = String::new();
2057        let impl_ = i.inner_impl();
2058
2059        // Impl items are grouped by kinds:
2060        //
2061        // 1. Constants
2062        // 2. Types
2063        // 3. Functions
2064        //
2065        // This order is because you can have associated constants used in associated types (like array
2066        // length), and both in associated functions. So with this order, when reading from top to
2067        // bottom, you should see items definitions before they're actually used most of the time.
2068        let mut assoc_tys = Vec::new();
2069        let mut assoc_fns = Vec::new();
2070
2071        if !impl_.is_negative_trait_impl() {
2072            for impl_item in &impl_.items {
2073                match impl_item.kind {
2074                    ItemKind::AssocFunction(..) => assoc_fns.push(impl_item),
2075                    ItemKind::AssocType(..) => assoc_tys.push(impl_item),
2076                    ItemKind::AssocConstant(_) => {
2077                        // We render it directly since they're supposed to come first.
2078                        doc_impl_item(
2079                            &mut default_impl_items,
2080                            &mut impl_items,
2081                            cx,
2082                            impl_item,
2083                            if trait_.is_some() { &i.impl_item } else { parent },
2084                            link,
2085                            render_mode,
2086                            false,
2087                            trait_,
2088                            rendering_params,
2089                        )?;
2090                    }
2091                    _ => {}
2092                }
2093            }
2094
2095            for assoc_ty in assoc_tys {
2096                doc_impl_item(
2097                    &mut default_impl_items,
2098                    &mut impl_items,
2099                    cx,
2100                    assoc_ty,
2101                    if trait_.is_some() { &i.impl_item } else { parent },
2102                    link,
2103                    render_mode,
2104                    false,
2105                    trait_,
2106                    rendering_params,
2107                )?;
2108            }
2109            for assoc_fn in assoc_fns {
2110                doc_impl_item(
2111                    &mut default_impl_items,
2112                    &mut impl_items,
2113                    cx,
2114                    assoc_fn,
2115                    if trait_.is_some() { &i.impl_item } else { parent },
2116                    link,
2117                    render_mode,
2118                    false,
2119                    trait_,
2120                    rendering_params,
2121                )?;
2122            }
2123        }
2124
2125        fn render_default_items(
2126            mut boring: impl fmt::Write,
2127            mut interesting: impl fmt::Write,
2128            cx: &Context<'_>,
2129            t: &clean::Trait,
2130            i: &clean::Impl,
2131            parent: &clean::Item,
2132            render_mode: RenderMode,
2133            rendering_params: ImplRenderingParameters,
2134        ) -> fmt::Result {
2135            for trait_item in &t.items {
2136                // Skip over any default trait items that are impossible to reference
2137                // (e.g. if it has a `Self: Sized` bound on an unsized type).
2138                if let Some(impl_def_id) = parent.item_id.as_def_id()
2139                    && let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
2140                    && cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
2141                {
2142                    continue;
2143                }
2144
2145                let n = trait_item.name;
2146                if i.items.iter().any(|m| m.name == n) {
2147                    continue;
2148                }
2149                let did = i.trait_.as_ref().unwrap().def_id();
2150                let provided_methods = i.provided_trait_methods(cx.tcx());
2151                let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
2152
2153                doc_impl_item(
2154                    &mut boring,
2155                    &mut interesting,
2156                    cx,
2157                    trait_item,
2158                    parent,
2159                    assoc_link,
2160                    render_mode,
2161                    true,
2162                    Some(t),
2163                    rendering_params,
2164                )?;
2165            }
2166            Ok(())
2167        }
2168
2169        // If we've implemented a trait, then also emit documentation for all
2170        // default items which weren't overridden in the implementation block.
2171        // We don't emit documentation for default items if they appear in the
2172        // Implementations on Foreign Types or Implementors sections.
2173        if rendering_params.show_default_items
2174            && let Some(t) = trait_
2175            && !impl_.is_negative_trait_impl()
2176        {
2177            render_default_items(
2178                &mut default_impl_items,
2179                &mut impl_items,
2180                cx,
2181                t,
2182                impl_,
2183                &i.impl_item,
2184                render_mode,
2185                rendering_params,
2186            )?;
2187        }
2188        if render_mode == RenderMode::Normal {
2189            let toggled = !(impl_items.is_empty() && default_impl_items.is_empty());
2190            let deprecation_attr = if impl_.is_deprecated
2191                || trait_.is_some_and(|trait_| trait_.is_deprecated(cx.tcx()))
2192            {
2193                " deprecated"
2194            } else {
2195                ""
2196            };
2197            if toggled {
2198                close_tags.push("</details>");
2199                write!(
2200                    w,
2201                    "<details class=\"toggle implementors-toggle{deprecation_attr}\"{}>\
2202                        <summary>",
2203                    if rendering_params.toggle_open_by_default { " open" } else { "" }
2204                )?;
2205            }
2206
2207            let (before_dox, after_dox) = i
2208                .impl_item
2209                .opt_doc_value()
2210                .map(|dox| {
2211                    Markdown {
2212                        content: &dox,
2213                        links: &i.impl_item.links(cx),
2214                        ids: &mut cx.id_map.borrow_mut(),
2215                        error_codes: cx.shared.codes,
2216                        edition: cx.shared.edition(),
2217                        playground: &cx.shared.playground,
2218                        heading_offset: HeadingOffset::H4,
2219                    }
2220                    .split_summary_and_content()
2221                })
2222                .unwrap_or((None, None));
2223
2224            write!(
2225                w,
2226                "{}",
2227                render_impl_summary(
2228                    cx,
2229                    i,
2230                    parent,
2231                    rendering_params.show_def_docs,
2232                    use_absolute,
2233                    aliases,
2234                    before_dox.as_deref(),
2235                    trait_.is_none() && impl_.items.is_empty(),
2236                )
2237            )?;
2238            if toggled {
2239                w.write_str("</summary>")?;
2240            }
2241
2242            if before_dox.is_some()
2243                && let Some(after_dox) = after_dox
2244            {
2245                write!(w, "<div class=\"docblock\">{after_dox}</div>")?;
2246            }
2247
2248            if !default_impl_items.is_empty() || !impl_items.is_empty() {
2249                w.write_str("<div class=\"impl-items\">")?;
2250                close_tags.push("</div>");
2251            }
2252        }
2253        if !default_impl_items.is_empty() || !impl_items.is_empty() {
2254            w.write_str(&default_impl_items)?;
2255            w.write_str(&impl_items)?;
2256        }
2257        for tag in close_tags.into_iter().rev() {
2258            w.write_str(tag)?;
2259        }
2260        Ok(())
2261    })
2262}
2263
2264// Render the items that appear on the right side of methods, impls, and
2265// associated types. For example "1.0.0 (const: 1.39.0) · source".
2266fn render_rightside(
2267    cx: &Context<'_>,
2268    item: &clean::Item,
2269    render_mode: RenderMode,
2270) -> impl fmt::Display {
2271    let tcx = cx.tcx();
2272
2273    fmt::from_fn(move |w| {
2274        // FIXME: Once https://github.com/rust-lang/rust/issues/143874 is implemented, we can remove
2275        // this condition.
2276        let const_stability = match render_mode {
2277            RenderMode::Normal => item.const_stability(tcx),
2278            RenderMode::ForDeref { .. } => None,
2279        };
2280        let src_href = cx.src_href(item);
2281        let stability = render_stability_since_raw_with_extra(
2282            item.stable_since(tcx),
2283            const_stability,
2284            if src_href.is_some() { "" } else { " rightside" },
2285        );
2286
2287        match (stability, src_href) {
2288            (Some(stability), Some(link)) => {
2289                write!(
2290                    w,
2291                    "<span class=\"rightside\">{stability} · <a class=\"src\" href=\"{link}\">Source</a></span>",
2292                )
2293            }
2294            (Some(stability), None) => {
2295                write!(w, "{stability}")
2296            }
2297            (None, Some(link)) => {
2298                write!(w, "<a class=\"src rightside\" href=\"{link}\">Source</a>")
2299            }
2300            (None, None) => Ok(()),
2301        }
2302    })
2303}
2304
2305fn render_impl_summary(
2306    cx: &Context<'_>,
2307    i: &Impl,
2308    parent: &clean::Item,
2309    show_def_docs: bool,
2310    use_absolute: Option<bool>,
2311    // This argument is used to reference same type with different paths to avoid duplication
2312    // in documentation pages for trait with automatic implementations like "Send" and "Sync".
2313    aliases: &[String],
2314    doc: Option<&str>,
2315    impl_is_empty: bool,
2316) -> impl fmt::Display {
2317    fmt::from_fn(move |w| {
2318        let inner_impl = i.inner_impl();
2319        let id = cx.derive_id(get_id_for_impl(cx.tcx(), i.impl_item.item_id));
2320        let aliases = (!aliases.is_empty())
2321            .then_some(fmt::from_fn(|f| {
2322                write!(f, " data-aliases=\"{}\"", fmt::from_fn(|f| aliases.iter().joined(",", f)))
2323            }))
2324            .maybe_display();
2325        write!(
2326            w,
2327            "<section id=\"{id}\" class=\"impl\"{aliases}>\
2328                {}\
2329                <a href=\"#{id}\" class=\"anchor\">§</a>\
2330                <h3 class=\"code-header\">",
2331            render_rightside(cx, &i.impl_item, RenderMode::Normal)
2332        )?;
2333
2334        if let Some(use_absolute) = use_absolute {
2335            write!(w, "{}", print_impl(inner_impl, use_absolute, cx))?;
2336            if show_def_docs {
2337                for it in &inner_impl.items {
2338                    if let ItemKind::AssocType(ty) = &it.kind {
2339                        write!(
2340                            w,
2341                            "<div class=\"where\">  {};</div>",
2342                            assoc_ty(it, ty, AssocItemLink::Anchor(None), 0, Ending::Newline, cx,)
2343                        )?;
2344                    }
2345                }
2346            }
2347        } else {
2348            write!(w, "{}", print_impl(inner_impl, false, cx))?;
2349        }
2350        w.write_str("</h3>")?;
2351
2352        let is_trait = inner_impl.trait_.is_some();
2353        if is_trait && let Some(portability) = portability(&i.impl_item, Some(parent)) {
2354            write!(
2355                w,
2356                "<span class=\"item-info\">\
2357                    <div class=\"stab portability\">{portability}</div>\
2358                </span>",
2359            )?;
2360        }
2361
2362        if let Some(doc) = doc {
2363            if impl_is_empty {
2364                w.write_str(
2365                    "\
2366<div class=\"item-info\">\
2367    <div class=\"stab empty-impl\">This impl block contains no public items.</div>\
2368</div>",
2369                )?;
2370            }
2371            write!(w, "<div class=\"docblock\">{doc}</div>")?;
2372        }
2373
2374        w.write_str("</section>")
2375    })
2376}
2377
2378pub(crate) fn small_url_encode(s: String) -> String {
2379    // These characters don't need to be escaped in a URI.
2380    // See https://url.spec.whatwg.org/#query-percent-encode-set
2381    // and https://url.spec.whatwg.org/#urlencoded-parsing
2382    // and https://url.spec.whatwg.org/#url-code-points
2383    fn dont_escape(c: u8) -> bool {
2384        c.is_ascii_alphanumeric()
2385            || c == b'-'
2386            || c == b'_'
2387            || c == b'.'
2388            || c == b','
2389            || c == b'~'
2390            || c == b'!'
2391            || c == b'\''
2392            || c == b'('
2393            || c == b')'
2394            || c == b'*'
2395            || c == b'/'
2396            || c == b';'
2397            || c == b':'
2398            || c == b'?'
2399            // As described in urlencoded-parsing, the
2400            // first `=` is the one that separates key from
2401            // value. Following `=`s are part of the value.
2402            || c == b'='
2403    }
2404    let mut st = String::new();
2405    let mut last_match = 0;
2406    for (idx, b) in s.bytes().enumerate() {
2407        if dont_escape(b) {
2408            continue;
2409        }
2410
2411        if last_match != idx {
2412            // Invariant: `idx` must be the first byte in a character at this point.
2413            st += &s[last_match..idx];
2414        }
2415        if b == b' ' {
2416            // URL queries are decoded with + replaced with SP.
2417            // While the same is not true for hashes, rustdoc only needs to be
2418            // consistent with itself when encoding them.
2419            st += "+";
2420        } else {
2421            write!(st, "%{b:02X}").unwrap();
2422        }
2423        // Invariant: if the current byte is not at the start of a multi-byte character,
2424        // we need to get down here so that when the next turn of the loop comes around,
2425        // last_match winds up equalling idx.
2426        //
2427        // In other words, dont_escape must always return `false` in multi-byte character.
2428        last_match = idx + 1;
2429    }
2430
2431    if last_match != 0 {
2432        st += &s[last_match..];
2433        st
2434    } else {
2435        s
2436    }
2437}
2438
2439fn get_id_for_impl(tcx: TyCtxt<'_>, impl_id: ItemId) -> String {
2440    use rustc_middle::ty::print::with_forced_trimmed_paths;
2441    let (type_, trait_) = match impl_id {
2442        ItemId::Auto { trait_, for_ } => {
2443            let ty = tcx.type_of(for_).skip_binder();
2444            (ty, Some(ty::TraitRef::new(tcx, trait_, [ty])))
2445        }
2446        ItemId::Blanket { impl_id, .. } | ItemId::DefId(impl_id) => {
2447            if let Some(trait_ref) = tcx.impl_opt_trait_ref(impl_id) {
2448                let trait_ref = trait_ref.skip_binder();
2449                (trait_ref.self_ty(), Some(trait_ref))
2450            } else {
2451                (tcx.type_of(impl_id).skip_binder(), None)
2452            }
2453        }
2454    };
2455    with_forced_trimmed_paths!(small_url_encode(if let Some(trait_) = trait_ {
2456        format!("impl-{trait_}-for-{type_}", trait_ = trait_.print_only_trait_path())
2457    } else {
2458        format!("impl-{type_}")
2459    }))
2460}
2461
2462fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String, String)> {
2463    match item.kind {
2464        clean::ItemKind::Impl(ref i) if i.trait_.is_some() => {
2465            // Alternative format produces no URLs,
2466            // so this parameter does nothing.
2467            Some((
2468                format!("{:#}", print_type(&i.for_, cx)),
2469                get_id_for_impl(cx.tcx(), item.item_id),
2470            ))
2471        }
2472        _ => None,
2473    }
2474}
2475
2476/// Returns the list of implementations for the primitive reference type, filtering out any
2477/// implementations that are on concrete or partially generic types, only keeping implementations
2478/// of the form `impl<T> Trait for &T`.
2479pub(crate) fn get_filtered_impls_for_reference<'a>(
2480    shared: &'a SharedContext<'_>,
2481    it: &clean::Item,
2482) -> (Vec<&'a Impl>, Vec<&'a Impl>, Vec<&'a Impl>) {
2483    let def_id = it.item_id.expect_def_id();
2484    // If the reference primitive is somehow not defined, exit early.
2485    let Some(v) = shared.cache.impls.get(&def_id) else {
2486        return (Vec::new(), Vec::new(), Vec::new());
2487    };
2488    // Since there is no "direct implementation" on the reference primitive type, we filter out
2489    // every implementation which isn't a trait implementation.
2490    let traits = v.iter().filter(|i| i.inner_impl().trait_.is_some());
2491    let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
2492        traits.partition(|t| t.inner_impl().kind.is_auto());
2493
2494    let (blanket_impl, concrete): (Vec<&Impl>, _) =
2495        concrete.into_iter().partition(|t| t.inner_impl().kind.is_blanket());
2496    // Now we keep only references over full generic types.
2497    let concrete: Vec<_> = concrete
2498        .into_iter()
2499        .filter(|t| match t.inner_impl().for_ {
2500            clean::Type::BorrowedRef { ref type_, .. } => type_.is_full_generic(),
2501            _ => false,
2502        })
2503        .collect();
2504
2505    (concrete, synthetic, blanket_impl)
2506}
2507
2508#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
2509pub(crate) enum ItemSection {
2510    Reexports,
2511    PrimitiveTypes,
2512    Modules,
2513    Macros,
2514    Structs,
2515    Enums,
2516    Constants,
2517    Statics,
2518    Traits,
2519    Functions,
2520    TypeAliases,
2521    Unions,
2522    Implementations,
2523    AssocFnsWithoutBody,
2524    AssocFnsWithBody,
2525    StructFields,
2526    Variants,
2527    AssociatedTypes,
2528    AssociatedConstants,
2529    ForeignTypes,
2530    Keywords,
2531    Attributes,
2532    AttributeMacros,
2533    DeriveMacros,
2534    TraitAliases,
2535}
2536
2537impl ItemSection {
2538    const ALL: &'static [Self] = {
2539        use ItemSection::*;
2540        // NOTE: The order here affects the order in the UI.
2541        // Keep this synchronized with addSidebarItems in main.js
2542        &[
2543            Reexports,
2544            PrimitiveTypes,
2545            Modules,
2546            Macros,
2547            Structs,
2548            Enums,
2549            Constants,
2550            Statics,
2551            Traits,
2552            Functions,
2553            TypeAliases,
2554            Unions,
2555            Implementations,
2556            AssocFnsWithoutBody,
2557            AssocFnsWithBody,
2558            StructFields,
2559            Variants,
2560            AssociatedTypes,
2561            AssociatedConstants,
2562            ForeignTypes,
2563            Keywords,
2564            Attributes,
2565            AttributeMacros,
2566            DeriveMacros,
2567            TraitAliases,
2568        ]
2569    };
2570
2571    fn id(self) -> &'static str {
2572        match self {
2573            Self::Reexports => "reexports",
2574            Self::Modules => "modules",
2575            Self::Structs => "structs",
2576            Self::Unions => "unions",
2577            Self::Enums => "enums",
2578            Self::Functions => "functions",
2579            Self::TypeAliases => "types",
2580            Self::Statics => "statics",
2581            Self::Constants => "constants",
2582            Self::Traits => "traits",
2583            Self::Implementations => "impls",
2584            Self::AssocFnsWithoutBody => "tymethods",
2585            Self::AssocFnsWithBody => "methods",
2586            Self::StructFields => "fields",
2587            Self::Variants => "variants",
2588            Self::Macros => "macros",
2589            Self::PrimitiveTypes => "primitives",
2590            Self::AssociatedTypes => "associated-types",
2591            Self::AssociatedConstants => "associated-consts",
2592            Self::ForeignTypes => "foreign-types",
2593            Self::Keywords => "keywords",
2594            Self::Attributes => "attribute-docs",
2595            Self::AttributeMacros => "attributes",
2596            Self::DeriveMacros => "derives",
2597            Self::TraitAliases => "trait-aliases",
2598        }
2599    }
2600
2601    fn name(self) -> &'static str {
2602        match self {
2603            Self::Reexports => "Re-exports",
2604            Self::Modules => "Modules",
2605            Self::Structs => "Structs",
2606            Self::Unions => "Unions",
2607            Self::Enums => "Enums",
2608            Self::Functions => "Functions",
2609            Self::TypeAliases => "Type Aliases",
2610            Self::Statics => "Statics",
2611            Self::Constants => "Constants",
2612            Self::Traits => "Traits",
2613            Self::Implementations => "Implementations",
2614            Self::AssocFnsWithoutBody => "Type Methods",
2615            Self::AssocFnsWithBody => "Methods",
2616            Self::StructFields => "Struct Fields",
2617            Self::Variants => "Variants",
2618            Self::Macros => "Macros",
2619            Self::PrimitiveTypes => "Primitive Types",
2620            Self::AssociatedTypes => "Associated Types",
2621            Self::AssociatedConstants => "Associated Constants",
2622            Self::ForeignTypes => "Foreign Types",
2623            Self::Keywords => "Keywords",
2624            Self::Attributes => "Attributes",
2625            Self::AttributeMacros => "Attribute Macros",
2626            Self::DeriveMacros => "Derive Macros",
2627            Self::TraitAliases => "Trait Aliases",
2628        }
2629    }
2630}
2631
2632fn item_ty_to_section(ty: ItemType) -> ItemSection {
2633    match ty {
2634        ItemType::ExternCrate | ItemType::Import => ItemSection::Reexports,
2635        ItemType::Module => ItemSection::Modules,
2636        ItemType::Struct => ItemSection::Structs,
2637        ItemType::Union => ItemSection::Unions,
2638        ItemType::Enum => ItemSection::Enums,
2639        ItemType::Function => ItemSection::Functions,
2640        ItemType::TypeAlias => ItemSection::TypeAliases,
2641        ItemType::Static => ItemSection::Statics,
2642        ItemType::Constant => ItemSection::Constants,
2643        ItemType::Trait => ItemSection::Traits,
2644        ItemType::Impl => ItemSection::Implementations,
2645        ItemType::AssocFnWithoutBody => ItemSection::AssocFnsWithoutBody,
2646        ItemType::AssocFnWithBody => ItemSection::AssocFnsWithBody,
2647        ItemType::StructField => ItemSection::StructFields,
2648        ItemType::Variant => ItemSection::Variants,
2649        ItemType::Macro => ItemSection::Macros,
2650        ItemType::Primitive => ItemSection::PrimitiveTypes,
2651        ItemType::AssocType => ItemSection::AssociatedTypes,
2652        ItemType::AssocConst => ItemSection::AssociatedConstants,
2653        ItemType::ForeignType => ItemSection::ForeignTypes,
2654        ItemType::Keyword => ItemSection::Keywords,
2655        ItemType::Attribute => ItemSection::Attributes,
2656        ItemType::ProcAttribute | ItemType::DeclMacroAttribute => ItemSection::AttributeMacros,
2657        ItemType::ProcDerive | ItemType::DeclMacroDerive => ItemSection::DeriveMacros,
2658        ItemType::TraitAlias => ItemSection::TraitAliases,
2659    }
2660}
2661
2662/// Returns a list of all paths used in the type.
2663/// This is used to help deduplicate imported impls
2664/// for reexported types. If any of the contained
2665/// types are re-exported, we don't use the corresponding
2666/// entry from the js file, as inlining will have already
2667/// picked up the impl
2668fn collect_paths_for_type(first_ty: &clean::Type, cache: &Cache) -> Vec<String> {
2669    let mut out = Vec::new();
2670    let mut visited = FxHashSet::default();
2671    let mut work = VecDeque::new();
2672
2673    let mut process_path = |did: DefId| {
2674        let get_extern = || cache.external_paths.get(&did).map(|s| &s.0);
2675        let fqp = cache.exact_paths.get(&did).or_else(get_extern);
2676
2677        if let Some(path) = fqp {
2678            out.push(join_path_syms(path));
2679        }
2680    };
2681
2682    work.push_back(first_ty);
2683
2684    while let Some(ty) = work.pop_front() {
2685        if !visited.insert(ty) {
2686            continue;
2687        }
2688
2689        match ty {
2690            clean::Type::Path { path } => process_path(path.def_id()),
2691            clean::Type::Tuple(tys) => {
2692                work.extend(tys.iter());
2693            }
2694            clean::Type::Slice(ty) => {
2695                work.push_back(ty);
2696            }
2697            clean::Type::Array(ty, _) => {
2698                work.push_back(ty);
2699            }
2700            clean::Type::RawPointer(_, ty) => {
2701                work.push_back(ty);
2702            }
2703            clean::Type::BorrowedRef { type_, .. } => {
2704                work.push_back(type_);
2705            }
2706            clean::Type::QPath(clean::QPathData { self_type, trait_, .. }) => {
2707                work.push_back(self_type);
2708                if let Some(trait_) = trait_ {
2709                    process_path(trait_.def_id());
2710                }
2711            }
2712            _ => {}
2713        }
2714    }
2715    out
2716}
2717
2718const MAX_FULL_EXAMPLES: usize = 5;
2719const NUM_VISIBLE_LINES: usize = 10;
2720
2721/// Generates the HTML for example call locations generated via the --scrape-examples flag.
2722fn render_call_locations<W: fmt::Write>(
2723    mut w: W,
2724    cx: &Context<'_>,
2725    item: &clean::Item,
2726) -> fmt::Result {
2727    let tcx = cx.tcx();
2728    let def_id = item.item_id.expect_def_id();
2729    let key = tcx.def_path_hash(def_id);
2730    let Some(call_locations) = cx.shared.call_locations.get(&key) else { return Ok(()) };
2731
2732    // Generate a unique ID so users can link to this section for a given method
2733    let id = cx.derive_id("scraped-examples");
2734    write!(
2735        &mut w,
2736        "<div class=\"docblock scraped-example-list\">\
2737          <span></span>\
2738          <h5 id=\"{id}\">\
2739             <a href=\"#{id}\">Examples found in repository</a>\
2740             <a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
2741          </h5>",
2742        root_path = cx.root_path(),
2743        id = id
2744    )?;
2745
2746    // Create a URL to a particular location in a reverse-dependency's source file
2747    let link_to_loc = |call_data: &CallData, loc: &CallLocation| -> (String, String) {
2748        let (line_lo, line_hi) = loc.call_expr.line_span;
2749        let (anchor, title) = if line_lo == line_hi {
2750            ((line_lo + 1).to_string(), format!("line {}", line_lo + 1))
2751        } else {
2752            (
2753                format!("{}-{}", line_lo + 1, line_hi + 1),
2754                format!("lines {}-{}", line_lo + 1, line_hi + 1),
2755            )
2756        };
2757        let url = format!("{}{}#{anchor}", cx.root_path(), call_data.url);
2758        (url, title)
2759    };
2760
2761    // Generate the HTML for a single example, being the title and code block
2762    let write_example = |w: &mut W, (path, call_data): (&PathBuf, &CallData)| -> bool {
2763        let contents = match fs::read_to_string(path) {
2764            Ok(contents) => contents,
2765            Err(err) => {
2766                let span = item.span(tcx).map_or(DUMMY_SP, |span| span.inner());
2767                tcx.dcx().span_err(span, format!("failed to read file {}: {err}", path.display()));
2768                return false;
2769            }
2770        };
2771
2772        // To reduce file sizes, we only want to embed the source code needed to understand the example, not
2773        // the entire file. So we find the smallest byte range that covers all items enclosing examples.
2774        assert!(!call_data.locations.is_empty());
2775        let min_loc =
2776            call_data.locations.iter().min_by_key(|loc| loc.enclosing_item.byte_span.0).unwrap();
2777        let byte_min = min_loc.enclosing_item.byte_span.0;
2778        let line_min = min_loc.enclosing_item.line_span.0;
2779        let max_loc =
2780            call_data.locations.iter().max_by_key(|loc| loc.enclosing_item.byte_span.1).unwrap();
2781        let byte_max = max_loc.enclosing_item.byte_span.1;
2782        let line_max = max_loc.enclosing_item.line_span.1;
2783
2784        // The output code is limited to that byte range.
2785        let contents_subset = &contents[(byte_min as usize)..(byte_max as usize)];
2786
2787        // The call locations need to be updated to reflect that the size of the program has changed.
2788        // Specifically, the ranges are all subtracted by `byte_min` since that's the new zero point.
2789        let (mut byte_ranges, line_ranges): (Vec<_>, Vec<_>) = call_data
2790            .locations
2791            .iter()
2792            .map(|loc| {
2793                let (byte_lo, byte_hi) = loc.call_ident.byte_span;
2794                let (line_lo, line_hi) = loc.call_expr.line_span;
2795                let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
2796
2797                let line_range = (line_lo - line_min, line_hi - line_min);
2798                let (line_url, line_title) = link_to_loc(call_data, loc);
2799
2800                (byte_range, (line_range, line_url, line_title))
2801            })
2802            .unzip();
2803
2804        let (_, init_url, init_title) = &line_ranges[0];
2805        let needs_expansion = line_max - line_min > NUM_VISIBLE_LINES;
2806        let locations_encoded = serde_json::to_string(&line_ranges).unwrap();
2807
2808        // For scraped examples, we don't need a real span from the SourceMap.
2809        // The URL is already provided in ScrapedInfo, and sources::print_src
2810        // will use that directly. We use DUMMY_SP as a placeholder.
2811        // Note: DUMMY_SP is safe here because href_from_span won't be called
2812        // for scraped examples.
2813        let file_span = rustc_span::DUMMY_SP;
2814
2815        let mut decoration_info = FxIndexMap::default();
2816        decoration_info.insert("highlight focus", vec![byte_ranges.remove(0)]);
2817        decoration_info.insert("highlight", byte_ranges);
2818
2819        sources::print_src(
2820            w,
2821            contents_subset,
2822            file_span,
2823            cx,
2824            cx.current.len(),
2825            &highlight::DecorationInfo(decoration_info),
2826            &sources::SourceContext::Embedded(sources::ScrapedInfo {
2827                needs_expansion,
2828                offset: line_min,
2829                name: &call_data.display_name,
2830                url: init_url,
2831                title: init_title,
2832                locations: locations_encoded,
2833            }),
2834        )
2835        .unwrap();
2836
2837        true
2838    };
2839
2840    // The call locations are output in sequence, so that sequence needs to be determined.
2841    // Ideally the most "relevant" examples would be shown first, but there's no general algorithm
2842    // for determining relevance. We instead proxy relevance with the following heuristics:
2843    //   1. Code written to be an example is better than code not written to be an example, e.g.
2844    //      a snippet from examples/foo.rs is better than src/lib.rs. We don't know the Cargo
2845    //      directory structure in Rustdoc, so we proxy this by prioritizing code that comes from
2846    //      a --crate-type bin.
2847    //   2. Smaller examples are better than large examples. So we prioritize snippets that have
2848    //      the smallest number of lines in their enclosing item.
2849    //   3. Finally we sort by the displayed file name, which is arbitrary but prevents the
2850    //      ordering of examples from randomly changing between Rustdoc invocations.
2851    let ordered_locations = {
2852        fn sort_criterion<'a>(
2853            (_, call_data): &(&PathBuf, &'a CallData),
2854        ) -> (bool, u32, &'a String) {
2855            // Use the first location because that's what the user will see initially
2856            let (lo, hi) = call_data.locations[0].enclosing_item.byte_span;
2857            (!call_data.is_bin, hi - lo, &call_data.display_name)
2858        }
2859
2860        let mut locs = call_locations.iter().collect::<Vec<_>>();
2861        locs.sort_by_key(sort_criterion);
2862        locs
2863    };
2864
2865    let mut it = ordered_locations.into_iter().peekable();
2866
2867    // An example may fail to write if its source can't be read for some reason, so this method
2868    // continues iterating until a write succeeds
2869    let write_and_skip_failure = |w: &mut W, it: &mut Peekable<_>| {
2870        for example in it.by_ref() {
2871            if write_example(&mut *w, example) {
2872                break;
2873            }
2874        }
2875    };
2876
2877    // Write just one example that's visible by default in the method's description.
2878    write_and_skip_failure(&mut w, &mut it);
2879
2880    // Then add the remaining examples in a hidden section.
2881    if it.peek().is_some() {
2882        write!(
2883            w,
2884            "<details class=\"toggle more-examples-toggle\">\
2885                  <summary class=\"hideme\">\
2886                     <span>More examples</span>\
2887                  </summary>\
2888                  <div class=\"hide-more\">Hide additional examples</div>\
2889                  <div class=\"more-scraped-examples\">\
2890                    <div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>"
2891        )?;
2892
2893        // Only generate inline code for MAX_FULL_EXAMPLES number of examples. Otherwise we could
2894        // make the page arbitrarily huge!
2895        for _ in 0..MAX_FULL_EXAMPLES {
2896            write_and_skip_failure(&mut w, &mut it);
2897        }
2898
2899        // For the remaining examples, generate a <ul> containing links to the source files.
2900        if it.peek().is_some() {
2901            w.write_str(
2902                r#"<div class="example-links">Additional examples can be found in:<br><ul>"#,
2903            )?;
2904            it.try_for_each(|(_, call_data)| {
2905                let (url, _) = link_to_loc(call_data, &call_data.locations[0]);
2906                write!(
2907                    w,
2908                    r#"<li><a href="{url}">{name}</a></li>"#,
2909                    url = url,
2910                    name = call_data.display_name
2911                )
2912            })?;
2913            w.write_str("</ul></div>")?;
2914        }
2915
2916        w.write_str("</div></details>")?;
2917    }
2918
2919    w.write_str("</div>")
2920}
2921
2922fn render_attributes_in_code(
2923    w: &mut impl fmt::Write,
2924    item: &clean::Item,
2925    prefix: impl fmt::Display,
2926    cx: &Context<'_>,
2927) -> fmt::Result {
2928    render_attributes_in_code_with_options(w, item, prefix, cx, true, "")
2929}
2930
2931pub(super) fn render_attributes_in_code_with_options(
2932    w: &mut impl fmt::Write,
2933    item: &clean::Item,
2934    prefix: impl fmt::Display,
2935    cx: &Context<'_>,
2936    render_doc_hidden: bool,
2937    open_tag: &str,
2938) -> fmt::Result {
2939    w.write_str(open_tag)?;
2940    if render_doc_hidden && item.is_doc_hidden() {
2941        render_code_attribute(&prefix, "#[doc(hidden)]", w)?;
2942    }
2943    for attr in &item.attrs.other_attrs {
2944        let rustc_attr_ir::Attribute::Parsed(kind) = attr else { continue };
2945        let attr = match kind {
2946            AttributeKind::LinkSection { name, .. } => {
2947                Cow::Owned(format!("#[unsafe(link_section = {})]", Escape(&format!("{name:?}"))))
2948            }
2949            AttributeKind::NoMangle(..) => Cow::Borrowed("#[unsafe(no_mangle)]"),
2950            AttributeKind::ExportName { name, .. } => {
2951                Cow::Owned(format!("#[unsafe(export_name = {})]", Escape(&format!("{name:?}"))))
2952            }
2953            AttributeKind::NonExhaustive(..) => Cow::Borrowed("#[non_exhaustive]"),
2954            _ => continue,
2955        };
2956        render_code_attribute(&prefix, attr.as_ref(), w)?;
2957    }
2958
2959    if let Some(def_id) = item.def_id()
2960        && let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id)
2961    {
2962        render_code_attribute(prefix, &repr, w)?;
2963    }
2964    Ok(())
2965}
2966
2967fn render_repr_attribute_in_code(
2968    w: &mut impl fmt::Write,
2969    cx: &Context<'_>,
2970    def_id: DefId,
2971) -> fmt::Result {
2972    if let Some(repr) = repr_attribute(cx.tcx(), cx.cache(), def_id) {
2973        render_code_attribute("", &repr, w)?;
2974    }
2975    Ok(())
2976}
2977
2978fn render_code_attribute(
2979    prefix: impl fmt::Display,
2980    attr: impl fmt::Display,
2981    w: &mut impl fmt::Write,
2982) -> fmt::Result {
2983    write!(w, "<div class=\"code-attribute\">{prefix}{attr}</div>")
2984}
2985
2986/// Compute the *public* `#[repr]` of the item given by `DefId`.
2987///
2988/// Read more about it here:
2989/// <https://doc.rust-lang.org/nightly/rustdoc/advanced-features.html#repr-documenting-the-representation-of-a-type>.
2990fn repr_attribute<'tcx>(
2991    tcx: TyCtxt<'tcx>,
2992    cache: &Cache,
2993    def_id: DefId,
2994) -> Option<Cow<'static, str>> {
2995    let adt = match tcx.def_kind(def_id) {
2996        DefKind::Struct | DefKind::Enum | DefKind::Union => tcx.adt_def(def_id),
2997        _ => return None,
2998    };
2999    let repr = adt.repr();
3000
3001    let is_visible = |def_id| cache.document_hidden || !tcx.is_doc_hidden(def_id);
3002    let is_public_field = |field: &ty::FieldDef| {
3003        (cache.document_private || field.vis.is_public()) && is_visible(field.did)
3004    };
3005
3006    // The transparent repr is public if
3007    // - the non-1-ZST field is public and visible or
3008    // - at least one field is public and visible if *all* fields are 1-ZSTs or
3009    // - the item is annotated with internal attribute `#[rustc_pub_transparent]`
3010    if repr.transparent() {
3011        let is_public = 'is_public: {
3012            if find_attr!(tcx, def_id, RustcPubTransparent(_)) {
3013                break 'is_public true;
3014            }
3015
3016            // `#[repr(transparent)]` can only be applied to structs and single-variant enums.
3017            let var = adt.variant(rustc_abi::FIRST_VARIANT); // the first and only variant
3018
3019            if !is_visible(var.def_id) {
3020                break 'is_public false;
3021            }
3022
3023            // Side note: There can only ever be one or zero non-1-ZST fields.
3024            let non_1zst_field = var.fields.iter().find(|field| {
3025                let ty = ty::TypingEnv::post_analysis(tcx, field.did)
3026                    .as_query_input(tcx.type_of(field.did).instantiate_identity().skip_norm_wip());
3027                tcx.layout_of(ty).is_ok_and(|layout| !layout.is_1zst())
3028            });
3029
3030            match non_1zst_field {
3031                Some(field) => is_public_field(field),
3032                None => var.fields.is_empty() || var.fields.iter().any(is_public_field),
3033            }
3034        };
3035
3036        // Since the transparent repr can't have any other reprs or
3037        // repr modifiers beside it, we can safely return early here.
3038        return is_public.then(|| "#[repr(transparent)]".into());
3039    }
3040
3041    // The repr is public iff all components are public and visible.
3042    let is_public = adt
3043        .variants()
3044        .iter()
3045        .all(|variant| is_visible(variant.def_id) && variant.fields.iter().all(is_public_field));
3046    if !is_public {
3047        return None;
3048    }
3049
3050    let mut result = Vec::<Cow<'_, _>>::new();
3051
3052    if repr.c() {
3053        result.push("C".into());
3054    }
3055    if repr.simd() {
3056        result.push("simd".into());
3057    }
3058    if let Some(int) = repr.int {
3059        let prefix = if int.is_signed() { 'i' } else { 'u' };
3060        let int = match int {
3061            rustc_abi::IntegerType::Pointer(_) => format!("{prefix}size"),
3062            rustc_abi::IntegerType::Fixed(int, _) => {
3063                format!("{prefix}{}", int.size().bytes() * 8)
3064            }
3065        };
3066        result.push(int.into());
3067    }
3068
3069    // Render modifiers last.
3070    if let Some(pack) = repr.pack {
3071        result.push(format!("packed({})", pack.bytes()).into());
3072    }
3073    if let Some(align) = repr.align {
3074        result.push(format!("align({})", align.bytes()).into());
3075    }
3076
3077    (!result.is_empty()).then(|| format!("#[repr({})]", result.join(", ")).into())
3078}
3079
3080pub(crate) fn compute_if_deref_target_implements_copy(tcx: TyCtxt<'_>, impl_def_id: DefId) -> bool {
3081    if let Some(impl_def_id) = impl_def_id.as_local()
3082        && let item = tcx.hir_expect_item(impl_def_id)
3083        && let rustc_hir::ItemKind::Impl(impl_item) = item.kind
3084    {
3085        for item in impl_item.items {
3086            let item = tcx.hir_impl_item(*item);
3087            if matches!(item.kind, rustc_hir::ImplItemKind::Type(_)) {
3088                let item_def_id = item.owner_id.to_def_id();
3089                let ty = tcx.type_of(item_def_id).instantiate_identity().skip_norm_wip();
3090                let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);
3091                return tcx.type_is_copy_modulo_regions(typing_env, ty);
3092            }
3093        }
3094    }
3095    false
3096}