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