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