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