1 // Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Rustdoc's HTML Rendering module
13 //! This modules contains the bulk of the logic necessary for rendering a
14 //! rustdoc `clean::Crate` instance to a set of static HTML pages. This
15 //! rendering process is largely driven by the `format!` syntax extension to
16 //! perform all I/O into files and streams.
18 //! The rendering process is largely driven by the `Context` and `Cache`
19 //! structures. The cache is pre-populated by crawling the crate in question,
20 //! and then it is shared among the various rendering threads. The cache is meant
21 //! to be a fairly large structure not implementing `Clone` (because it's shared
22 //! among threads). The context, however, should be a lightweight structure. This
23 //! is cloned per-thread and contains information about what is currently being
26 //! In order to speed up rendering (mostly because of markdown rendering), the
27 //! rendering process has been parallelized. This parallelization is only
28 //! exposed through the `crate` method on the context, and then also from the
29 //! fact that the shared cache is stored in TLS (and must be accessed as such).
31 //! In addition to rendering the crate itself, this module is also responsible
32 //! for creating the corresponding search index and source file renderings.
33 //! These threads are not parallelized (they haven't been a bottleneck yet), and
34 //! both occur before the crate is rendered.
35 pub use self::ExternalLocation
::*;
37 use std
::ascii
::AsciiExt
;
38 use std
::cell
::RefCell
;
39 use std
::cmp
::Ordering
;
40 use std
::collections
::BTreeMap
;
41 use std
::default::Default
;
43 use std
::fmt
::{self, Display, Formatter, Write as FmtWrite}
;
44 use std
::fs
::{self, File, OpenOptions}
;
45 use std
::io
::prelude
::*;
46 use std
::io
::{self, BufWriter, BufReader}
;
47 use std
::iter
::repeat
;
49 use std
::path
::{PathBuf, Path, Component}
;
53 use externalfiles
::ExternalHtml
;
55 use serialize
::json
::{ToJson, Json, as_json}
;
56 use syntax
::{abi, ast}
;
57 use syntax
::feature_gate
::UnstableFeatures
;
58 use rustc
::hir
::def_id
::{CrateNum, CRATE_DEF_INDEX, DefId}
;
59 use rustc
::middle
::privacy
::AccessLevels
;
60 use rustc
::middle
::stability
;
62 use rustc
::util
::nodemap
::{FxHashMap, FxHashSet}
;
63 use rustc_data_structures
::flock
;
65 use clean
::{self, AttributesExt, GetDefId, SelfTy, Mutability}
;
68 use html
::escape
::Escape
;
69 use html
::format
::{ConstnessSpace}
;
70 use html
::format
::{TyParamBounds, WhereClause, href, AbiSpace}
;
71 use html
::format
::{VisSpace, Method, UnsafetySpace, MutableSpace}
;
72 use html
::format
::fmt_impl_for_trait_page
;
73 use html
::item_type
::ItemType
;
74 use html
::markdown
::{self, Markdown, MarkdownHtml}
;
75 use html
::{highlight, layout}
;
77 /// A pair of name and its optional document.
78 pub type NameDoc
= (String
, Option
<String
>);
80 /// Major driving force in all rustdoc rendering. This contains information
81 /// about where in the tree-like hierarchy rendering is occurring and controls
82 /// how the current page is being rendered.
84 /// It is intended that this context is a lightweight object which can be fairly
85 /// easily cloned because it is cloned per work-job (about once per item in the
89 /// Current hierarchy of components leading down to what's currently being
91 pub current
: Vec
<String
>,
92 /// The current destination folder of where HTML artifacts should be placed.
93 /// This changes as the context descends into the module hierarchy.
95 /// A flag, which when `true`, will render pages which redirect to the
96 /// real location of an item. This is used to allow external links to
97 /// publicly reused items to redirect to the right location.
98 pub render_redirect_pages
: bool
,
99 pub shared
: Arc
<SharedContext
>,
102 pub struct SharedContext
{
103 /// The path to the crate root source minus the file name.
104 /// Used for simplifying paths to the highlighted source code files.
105 pub src_root
: PathBuf
,
106 /// This describes the layout of each page, and is not modified after
107 /// creation of the context (contains info like the favicon and added html).
108 pub layout
: layout
::Layout
,
109 /// This flag indicates whether [src] links should be generated or not. If
110 /// the source files are present in the html rendering, then this will be
112 pub include_sources
: bool
,
113 /// The local file sources we've emitted and their respective url-paths.
114 pub local_sources
: FxHashMap
<PathBuf
, String
>,
115 /// All the passes that were run on this crate.
116 pub passes
: FxHashSet
<String
>,
117 /// The base-URL of the issue tracker for when an item has been tagged with
119 pub issue_tracker_base_url
: Option
<String
>,
120 /// The given user css file which allow to customize the generated
121 /// documentation theme.
122 pub css_file_extension
: Option
<PathBuf
>,
125 /// Indicates where an external crate can be found.
126 pub enum ExternalLocation
{
127 /// Remote URL root of the external crate
129 /// This external crate can be found in the local doc/ folder
131 /// The external crate could not be found.
135 /// Metadata about an implementor of a trait.
136 pub struct Implementor
{
138 pub stability
: Option
<clean
::Stability
>,
139 pub impl_
: clean
::Impl
,
142 /// Metadata about implementations for a type.
145 pub impl_item
: clean
::Item
,
149 fn inner_impl(&self) -> &clean
::Impl
{
150 match self.impl_item
.inner
{
151 clean
::ImplItem(ref impl_
) => impl_
,
152 _
=> panic
!("non-impl item found in impl")
156 fn trait_did(&self) -> Option
<DefId
> {
157 self.inner_impl().trait_
.def_id()
167 impl error
::Error
for Error
{
168 fn description(&self) -> &str {
169 self.error
.description()
173 impl Display
for Error
{
174 fn fmt(&self, f
: &mut Formatter
) -> fmt
::Result
{
175 write
!(f
, "\"{}\": {}", self.file
.display(), self.error
)
180 pub fn new(e
: io
::Error
, file
: &Path
) -> Error
{
182 file
: file
.to_path_buf(),
188 macro_rules
! try_err
{
189 ($e
:expr
, $file
:expr
) => ({
192 Err(e
) => return Err(Error
::new(e
, $file
)),
197 /// This cache is used to store information about the `clean::Crate` being
198 /// rendered in order to provide more useful documentation. This contains
199 /// information like all implementors of a trait, all traits a type implements,
200 /// documentation for all known traits, etc.
202 /// This structure purposefully does not implement `Clone` because it's intended
203 /// to be a fairly large and expensive structure to clone. Instead this adheres
204 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
205 /// rendering threads.
208 /// Mapping of typaram ids to the name of the type parameter. This is used
209 /// when pretty-printing a type (so pretty printing doesn't have to
210 /// painfully maintain a context like this)
211 pub typarams
: FxHashMap
<DefId
, String
>,
213 /// Maps a type id to all known implementations for that type. This is only
214 /// recognized for intra-crate `ResolvedPath` types, and is used to print
215 /// out extra documentation on the page of an enum/struct.
217 /// The values of the map are a list of implementations and documentation
218 /// found on that implementation.
219 pub impls
: FxHashMap
<DefId
, Vec
<Impl
>>,
221 /// Maintains a mapping of local crate node ids to the fully qualified name
222 /// and "short type description" of that node. This is used when generating
223 /// URLs when a type is being linked to. External paths are not located in
224 /// this map because the `External` type itself has all the information
226 pub paths
: FxHashMap
<DefId
, (Vec
<String
>, ItemType
)>,
228 /// Similar to `paths`, but only holds external paths. This is only used for
229 /// generating explicit hyperlinks to other crates.
230 pub external_paths
: FxHashMap
<DefId
, (Vec
<String
>, ItemType
)>,
232 /// This map contains information about all known traits of this crate.
233 /// Implementations of a crate should inherit the documentation of the
234 /// parent trait if no extra documentation is specified, and default methods
235 /// should show up in documentation about trait implementations.
236 pub traits
: FxHashMap
<DefId
, clean
::Trait
>,
238 /// When rendering traits, it's often useful to be able to list all
239 /// implementors of the trait, and this mapping is exactly, that: a mapping
240 /// of trait ids to the list of known implementors of the trait
241 pub implementors
: FxHashMap
<DefId
, Vec
<Implementor
>>,
243 /// Cache of where external crate documentation can be found.
244 pub extern_locations
: FxHashMap
<CrateNum
, (String
, PathBuf
, ExternalLocation
)>,
246 /// Cache of where documentation for primitives can be found.
247 pub primitive_locations
: FxHashMap
<clean
::PrimitiveType
, DefId
>,
249 // Note that external items for which `doc(hidden)` applies to are shown as
250 // non-reachable while local items aren't. This is because we're reusing
251 // the access levels from crateanalysis.
252 pub access_levels
: Arc
<AccessLevels
<DefId
>>,
254 // Private fields only used when initially crawling a crate to build a cache
257 parent_stack
: Vec
<DefId
>,
258 parent_is_trait_impl
: bool
,
259 search_index
: Vec
<IndexItem
>,
261 deref_trait_did
: Option
<DefId
>,
262 deref_mut_trait_did
: Option
<DefId
>,
264 // In rare case where a structure is defined in one module but implemented
265 // in another, if the implementing module is parsed before defining module,
266 // then the fully qualified name of the structure isn't presented in `paths`
267 // yet when its implementation methods are being indexed. Caches such methods
268 // and their parent id here and indexes them at the end of crate parsing.
269 orphan_impl_items
: Vec
<(DefId
, clean
::Item
)>,
272 /// Temporary storage for data obtained during `RustdocVisitor::clean()`.
273 /// Later on moved into `CACHE_KEY`.
275 pub struct RenderInfo
{
276 pub inlined
: FxHashSet
<DefId
>,
277 pub external_paths
: ::core
::ExternalPaths
,
278 pub external_typarams
: FxHashMap
<DefId
, String
>,
279 pub deref_trait_did
: Option
<DefId
>,
280 pub deref_mut_trait_did
: Option
<DefId
>,
283 /// Helper struct to render all source code to HTML pages
284 struct SourceCollector
<'a
> {
285 scx
: &'a
mut SharedContext
,
287 /// Root destination to place all HTML output into
291 /// Wrapper struct to render the source code of a file. This will do things like
292 /// adding line numbers to the left-hand side.
293 struct Source
<'a
>(&'a
str);
295 // Helper structs for rendering items/sidebars and carrying along contextual
298 #[derive(Copy, Clone)]
301 item
: &'a clean
::Item
,
304 struct Sidebar
<'a
> { cx: &'a Context, item: &'a clean::Item, }
306 /// Struct representing one entry in the JS search index. These are all emitted
307 /// by hand to a large JS file at the end of cache-creation.
313 parent
: Option
<DefId
>,
314 parent_idx
: Option
<usize>,
315 search_type
: Option
<IndexItemFunctionType
>,
318 impl ToJson
for IndexItem
{
319 fn to_json(&self) -> Json
{
320 assert_eq
!(self.parent
.is_some(), self.parent_idx
.is_some());
322 let mut data
= Vec
::with_capacity(6);
323 data
.push((self.ty
as usize).to_json());
324 data
.push(self.name
.to_json());
325 data
.push(self.path
.to_json());
326 data
.push(self.desc
.to_json());
327 data
.push(self.parent_idx
.to_json());
328 data
.push(self.search_type
.to_json());
334 /// A type used for the search index.
336 name
: Option
<String
>,
339 impl ToJson
for Type
{
340 fn to_json(&self) -> Json
{
343 let mut data
= BTreeMap
::new();
344 data
.insert("name".to_owned(), name
.to_json());
352 /// Full type of functions/methods in the search index.
353 struct IndexItemFunctionType
{
358 impl ToJson
for IndexItemFunctionType
{
359 fn to_json(&self) -> Json
{
360 // If we couldn't figure out a type, just write `null`.
361 if self.inputs
.iter().chain(self.output
.iter()).any(|ref i
| i
.name
.is_none()) {
364 let mut data
= BTreeMap
::new();
365 data
.insert("inputs".to_owned(), self.inputs
.to_json());
366 data
.insert("output".to_owned(), self.output
.to_json());
372 // TLS keys used to carry information around during rendering.
374 thread_local
!(static CACHE_KEY
: RefCell
<Arc
<Cache
>> = Default
::default());
375 thread_local
!(pub static CURRENT_LOCATION_KEY
: RefCell
<Vec
<String
>> =
376 RefCell
::new(Vec
::new()));
377 thread_local
!(static USED_ID_MAP
: RefCell
<FxHashMap
<String
, usize>> =
378 RefCell
::new(init_ids()));
380 fn init_ids() -> FxHashMap
<String
, usize> {
396 ].into_iter().map(|id
| (String
::from(*id
), 1)).collect()
399 /// This method resets the local table of used ID attributes. This is typically
400 /// used at the beginning of rendering an entire HTML page to reset from the
401 /// previous state (if any).
402 pub fn reset_ids(embedded
: bool
) {
403 USED_ID_MAP
.with(|s
| {
404 *s
.borrow_mut() = if embedded
{
412 pub fn derive_id(candidate
: String
) -> String
{
413 USED_ID_MAP
.with(|map
| {
414 let id
= match map
.borrow_mut().get_mut(&candidate
) {
417 let id
= format
!("{}-{}", candidate
, *a
);
423 map
.borrow_mut().insert(id
.clone(), 1);
428 /// Generates the documentation for `crate` into the directory `dst`
429 pub fn run(mut krate
: clean
::Crate
,
430 external_html
: &ExternalHtml
,
431 playground_url
: Option
<String
>,
433 passes
: FxHashSet
<String
>,
434 css_file_extension
: Option
<PathBuf
>,
435 renderinfo
: RenderInfo
) -> Result
<(), Error
> {
436 let src_root
= match krate
.src
.parent() {
437 Some(p
) => p
.to_path_buf(),
438 None
=> PathBuf
::new(),
440 let mut scx
= SharedContext
{
443 include_sources
: true,
444 local_sources
: FxHashMap(),
445 issue_tracker_base_url
: None
,
446 layout
: layout
::Layout
{
447 logo
: "".to_string(),
448 favicon
: "".to_string(),
449 external_html
: external_html
.clone(),
450 krate
: krate
.name
.clone(),
452 css_file_extension
: css_file_extension
.clone(),
455 // If user passed in `--playground-url` arg, we fill in crate name here
456 if let Some(url
) = playground_url
{
457 markdown
::PLAYGROUND
.with(|slot
| {
458 *slot
.borrow_mut() = Some((Some(krate
.name
.clone()), url
));
462 // Crawl the crate attributes looking for attributes which control how we're
463 // going to emit HTML
464 if let Some(attrs
) = krate
.module
.as_ref().map(|m
| &m
.attrs
) {
465 for attr
in attrs
.lists("doc") {
466 let name
= attr
.name().map(|s
| s
.as_str());
467 match (name
.as_ref().map(|s
| &s
[..]), attr
.value_str()) {
468 (Some("html_favicon_url"), Some(s
)) => {
469 scx
.layout
.favicon
= s
.to_string();
471 (Some("html_logo_url"), Some(s
)) => {
472 scx
.layout
.logo
= s
.to_string();
474 (Some("html_playground_url"), Some(s
)) => {
475 markdown
::PLAYGROUND
.with(|slot
| {
476 let name
= krate
.name
.clone();
477 *slot
.borrow_mut() = Some((Some(name
), s
.to_string()));
480 (Some("issue_tracker_base_url"), Some(s
)) => {
481 scx
.issue_tracker_base_url
= Some(s
.to_string());
483 (Some("html_no_source"), None
) if attr
.is_word() => {
484 scx
.include_sources
= false;
490 try_err
!(mkdir(&dst
), &dst
);
491 krate
= render_sources(&dst
, &mut scx
, krate
)?
;
495 render_redirect_pages
: false,
496 shared
: Arc
::new(scx
),
499 // Crawl the crate to build various caches used for the output
508 let external_paths
= external_paths
.into_iter()
509 .map(|(k
, (v
, t
))| (k
, (v
, ItemType
::from(t
))))
512 let mut cache
= Cache
{
514 external_paths
: external_paths
,
516 implementors
: FxHashMap(),
518 parent_stack
: Vec
::new(),
519 search_index
: Vec
::new(),
520 parent_is_trait_impl
: false,
521 extern_locations
: FxHashMap(),
522 primitive_locations
: FxHashMap(),
524 access_levels
: krate
.access_levels
.clone(),
525 orphan_impl_items
: Vec
::new(),
526 traits
: mem
::replace(&mut krate
.external_traits
, FxHashMap()),
527 deref_trait_did
: deref_trait_did
,
528 deref_mut_trait_did
: deref_mut_trait_did
,
529 typarams
: external_typarams
,
532 // Cache where all our extern crates are located
533 for &(n
, ref e
) in &krate
.externs
{
534 let src_root
= match Path
::new(&e
.src
).parent() {
535 Some(p
) => p
.to_path_buf(),
536 None
=> PathBuf
::new(),
538 cache
.extern_locations
.insert(n
, (e
.name
.clone(), src_root
,
539 extern_location(e
, &cx
.dst
)));
541 let did
= DefId { krate: n, index: CRATE_DEF_INDEX }
;
542 cache
.external_paths
.insert(did
, (vec
![e
.name
.to_string()], ItemType
::Module
));
545 // Cache where all known primitives have their documentation located.
547 // Favor linking to as local extern as possible, so iterate all crates in
548 // reverse topological order.
549 for &(_
, ref e
) in krate
.externs
.iter().rev() {
550 for &(def_id
, prim
, _
) in &e
.primitives
{
551 cache
.primitive_locations
.insert(prim
, def_id
);
554 for &(def_id
, prim
, _
) in &krate
.primitives
{
555 cache
.primitive_locations
.insert(prim
, def_id
);
558 cache
.stack
.push(krate
.name
.clone());
559 krate
= cache
.fold_crate(krate
);
561 // Build our search index
562 let index
= build_index(&krate
, &mut cache
);
564 // Freeze the cache now that the index has been built. Put an Arc into TLS
565 // for future parallelization opportunities
566 let cache
= Arc
::new(cache
);
567 CACHE_KEY
.with(|v
| *v
.borrow_mut() = cache
.clone());
568 CURRENT_LOCATION_KEY
.with(|s
| s
.borrow_mut().clear());
570 write_shared(&cx
, &krate
, &*cache
, index
)?
;
572 // And finally render the whole crate's documentation
576 /// Build the search index from the collected metadata
577 fn build_index(krate
: &clean
::Crate
, cache
: &mut Cache
) -> String
{
578 let mut nodeid_to_pathid
= FxHashMap();
579 let mut crate_items
= Vec
::with_capacity(cache
.search_index
.len());
580 let mut crate_paths
= Vec
::<Json
>::new();
582 let Cache
{ ref mut search_index
,
583 ref orphan_impl_items
,
584 ref mut paths
, .. } = *cache
;
586 // Attach all orphan items to the type's definition if the type
587 // has since been learned.
588 for &(did
, ref item
) in orphan_impl_items
{
589 if let Some(&(ref fqp
, _
)) = paths
.get(&did
) {
590 search_index
.push(IndexItem
{
592 name
: item
.name
.clone().unwrap(),
593 path
: fqp
[..fqp
.len() - 1].join("::"),
594 desc
: plain_summary_line(item
.doc_value()),
597 search_type
: get_index_search_type(&item
),
602 // Reduce `NodeId` in paths into smaller sequential numbers,
603 // and prune the paths that do not appear in the index.
604 let mut lastpath
= String
::new();
605 let mut lastpathid
= 0usize
;
607 for item
in search_index
{
608 item
.parent_idx
= item
.parent
.map(|nodeid
| {
609 if nodeid_to_pathid
.contains_key(&nodeid
) {
610 *nodeid_to_pathid
.get(&nodeid
).unwrap()
612 let pathid
= lastpathid
;
613 nodeid_to_pathid
.insert(nodeid
, pathid
);
616 let &(ref fqp
, short
) = paths
.get(&nodeid
).unwrap();
617 crate_paths
.push(((short
as usize), fqp
.last().unwrap().clone()).to_json());
622 // Omit the parent path if it is same to that of the prior item.
623 if lastpath
== item
.path
{
626 lastpath
= item
.path
.clone();
628 crate_items
.push(item
.to_json());
631 let crate_doc
= krate
.module
.as_ref().map(|module
| {
632 plain_summary_line(module
.doc_value())
633 }).unwrap_or(String
::new());
635 let mut crate_data
= BTreeMap
::new();
636 crate_data
.insert("doc".to_owned(), Json
::String(crate_doc
));
637 crate_data
.insert("items".to_owned(), Json
::Array(crate_items
));
638 crate_data
.insert("paths".to_owned(), Json
::Array(crate_paths
));
640 // Collect the index into a string
641 format
!("searchIndex[{}] = {};",
642 as_json(&krate
.name
),
643 Json
::Object(crate_data
))
646 fn write_shared(cx
: &Context
,
647 krate
: &clean
::Crate
,
649 search_index
: String
) -> Result
<(), Error
> {
650 // Write out the shared files. Note that these are shared among all rustdoc
651 // docs placed in the output directory, so this needs to be a synchronized
652 // operation with respect to all other rustdocs running around.
653 try_err
!(mkdir(&cx
.dst
), &cx
.dst
);
654 let _lock
= flock
::Lock
::panicking_new(&cx
.dst
.join(".lock"), true, true, true);
656 // Add all the static files. These may already exist, but we just
657 // overwrite them anyway to make sure that they're fresh and up-to-date.
659 write(cx
.dst
.join("jquery.js"),
660 include_bytes
!("static/jquery-2.1.4.min.js"))?
;
661 write(cx
.dst
.join("main.js"),
662 include_bytes
!("static/main.js"))?
;
663 write(cx
.dst
.join("rustdoc.css"),
664 include_bytes
!("static/rustdoc.css"))?
;
665 write(cx
.dst
.join("main.css"),
666 include_bytes
!("static/styles/main.css"))?
;
667 if let Some(ref css
) = cx
.shared
.css_file_extension
{
668 let mut content
= String
::new();
669 let css
= css
.as_path();
670 let mut f
= try_err
!(File
::open(css
), css
);
672 try_err
!(f
.read_to_string(&mut content
), css
);
673 let css
= cx
.dst
.join("theme.css");
674 let css
= css
.as_path();
675 let mut f
= try_err
!(File
::create(css
), css
);
676 try_err
!(write
!(f
, "{}", &content
), css
);
678 write(cx
.dst
.join("normalize.css"),
679 include_bytes
!("static/normalize.css"))?
;
680 write(cx
.dst
.join("FiraSans-Regular.woff"),
681 include_bytes
!("static/FiraSans-Regular.woff"))?
;
682 write(cx
.dst
.join("FiraSans-Medium.woff"),
683 include_bytes
!("static/FiraSans-Medium.woff"))?
;
684 write(cx
.dst
.join("FiraSans-LICENSE.txt"),
685 include_bytes
!("static/FiraSans-LICENSE.txt"))?
;
686 write(cx
.dst
.join("Heuristica-Italic.woff"),
687 include_bytes
!("static/Heuristica-Italic.woff"))?
;
688 write(cx
.dst
.join("Heuristica-LICENSE.txt"),
689 include_bytes
!("static/Heuristica-LICENSE.txt"))?
;
690 write(cx
.dst
.join("SourceSerifPro-Regular.woff"),
691 include_bytes
!("static/SourceSerifPro-Regular.woff"))?
;
692 write(cx
.dst
.join("SourceSerifPro-Bold.woff"),
693 include_bytes
!("static/SourceSerifPro-Bold.woff"))?
;
694 write(cx
.dst
.join("SourceSerifPro-LICENSE.txt"),
695 include_bytes
!("static/SourceSerifPro-LICENSE.txt"))?
;
696 write(cx
.dst
.join("SourceCodePro-Regular.woff"),
697 include_bytes
!("static/SourceCodePro-Regular.woff"))?
;
698 write(cx
.dst
.join("SourceCodePro-Semibold.woff"),
699 include_bytes
!("static/SourceCodePro-Semibold.woff"))?
;
700 write(cx
.dst
.join("SourceCodePro-LICENSE.txt"),
701 include_bytes
!("static/SourceCodePro-LICENSE.txt"))?
;
702 write(cx
.dst
.join("LICENSE-MIT.txt"),
703 include_bytes
!("static/LICENSE-MIT.txt"))?
;
704 write(cx
.dst
.join("LICENSE-APACHE.txt"),
705 include_bytes
!("static/LICENSE-APACHE.txt"))?
;
706 write(cx
.dst
.join("COPYRIGHT.txt"),
707 include_bytes
!("static/COPYRIGHT.txt"))?
;
709 fn collect(path
: &Path
, krate
: &str,
710 key
: &str) -> io
::Result
<Vec
<String
>> {
711 let mut ret
= Vec
::new();
713 for line
in BufReader
::new(File
::open(path
)?
).lines() {
715 if !line
.starts_with(key
) {
718 if line
.starts_with(&format
!(r
#"{}["{}"]"#, key, krate)) {
721 ret
.push(line
.to_string());
727 // Update the search index
728 let dst
= cx
.dst
.join("search-index.js");
729 let mut all_indexes
= try_err
!(collect(&dst
, &krate
.name
, "searchIndex"), &dst
);
730 all_indexes
.push(search_index
);
731 // Sort the indexes by crate so the file will be generated identically even
732 // with rustdoc running in parallel.
734 let mut w
= try_err
!(File
::create(&dst
), &dst
);
735 try_err
!(writeln
!(&mut w
, "var searchIndex = {{}};"), &dst
);
736 for index
in &all_indexes
{
737 try_err
!(writeln
!(&mut w
, "{}", *index
), &dst
);
739 try_err
!(writeln
!(&mut w
, "initSearch(searchIndex);"), &dst
);
741 // Update the list of all implementors for traits
742 let dst
= cx
.dst
.join("implementors");
743 for (&did
, imps
) in &cache
.implementors
{
744 // Private modules can leak through to this phase of rustdoc, which
745 // could contain implementations for otherwise private types. In some
746 // rare cases we could find an implementation for an item which wasn't
747 // indexed, so we just skip this step in that case.
749 // FIXME: this is a vague explanation for why this can't be a `get`, in
750 // theory it should be...
751 let &(ref remote_path
, remote_item_type
) = match cache
.paths
.get(&did
) {
753 None
=> match cache
.external_paths
.get(&did
) {
759 let mut implementors
= format
!(r
#"implementors["{}"] = ["#, krate.name);
761 // If the trait and implementation are in the same crate, then
762 // there's no need to emit information about it (there's inlining
763 // going on). If they're in different crates then the crate defining
764 // the trait will be interested in our implementation.
765 if imp
.def_id
.krate
== did
.krate { continue }
766 write
!(implementors
, "{},", as_json(&imp
.impl_
.to_string())).unwrap();
768 implementors
.push_str("];");
770 let mut mydst
= dst
.clone();
771 for part
in &remote_path
[..remote_path
.len() - 1] {
774 try_err
!(fs
::create_dir_all(&mydst
), &mydst
);
775 mydst
.push(&format
!("{}.{}.js",
776 remote_item_type
.css_class(),
777 remote_path
[remote_path
.len() - 1]));
779 let mut all_implementors
= try_err
!(collect(&mydst
, &krate
.name
, "implementors"), &mydst
);
780 all_implementors
.push(implementors
);
781 // Sort the implementors by crate so the file will be generated
782 // identically even with rustdoc running in parallel.
783 all_implementors
.sort();
785 let mut f
= try_err
!(File
::create(&mydst
), &mydst
);
786 try_err
!(writeln
!(&mut f
, "(function() {{var implementors = {{}};"), &mydst
);
787 for implementor
in &all_implementors
{
788 try_err
!(writeln
!(&mut f
, "{}", *implementor
), &mydst
);
790 try_err
!(writeln
!(&mut f
, "{}", r
"
791 if (window.register_implementors) {
792 window.register_implementors(implementors);
794 window.pending_implementors = implementors;
797 try_err
!(writeln
!(&mut f
, r
"}})()"), &mydst
);
802 fn render_sources(dst
: &Path
, scx
: &mut SharedContext
,
803 krate
: clean
::Crate
) -> Result
<clean
::Crate
, Error
> {
804 info
!("emitting source files");
805 let dst
= dst
.join("src");
806 try_err
!(mkdir(&dst
), &dst
);
807 let dst
= dst
.join(&krate
.name
);
808 try_err
!(mkdir(&dst
), &dst
);
809 let mut folder
= SourceCollector
{
813 Ok(folder
.fold_crate(krate
))
816 /// Writes the entire contents of a string to a destination, not attempting to
817 /// catch any errors.
818 fn write(dst
: PathBuf
, contents
: &[u8]) -> Result
<(), Error
> {
819 Ok(try_err
!(try_err
!(File
::create(&dst
), &dst
).write_all(contents
), &dst
))
822 /// Makes a directory on the filesystem, failing the thread if an error occurs
823 /// and skipping if the directory already exists.
825 /// Note that this also handles races as rustdoc is likely to be run
826 /// concurrently against another invocation.
827 fn mkdir(path
: &Path
) -> io
::Result
<()> {
828 match fs
::create_dir(path
) {
830 Err(ref e
) if e
.kind() == io
::ErrorKind
::AlreadyExists
=> Ok(()),
835 /// Takes a path to a source file and cleans the path to it. This canonicalizes
836 /// things like ".." to components which preserve the "top down" hierarchy of a
837 /// static HTML tree. Each component in the cleaned path will be passed as an
838 /// argument to `f`. The very last component of the path (ie the file name) will
839 /// be passed to `f` if `keep_filename` is true, and ignored otherwise.
840 // FIXME (#9639): The closure should deal with &[u8] instead of &str
841 // FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths
842 fn clean_srcpath
<F
>(src_root
: &Path
, p
: &Path
, keep_filename
: bool
, mut f
: F
) where
845 // make it relative, if possible
846 let p
= p
.strip_prefix(src_root
).unwrap_or(p
);
848 let mut iter
= p
.components().peekable();
850 while let Some(c
) = iter
.next() {
851 if !keep_filename
&& iter
.peek().is_none() {
856 Component
::ParentDir
=> f("up"),
857 Component
::Normal(c
) => f(c
.to_str().unwrap()),
863 /// Attempts to find where an external crate is located, given that we're
864 /// rendering in to the specified source destination.
865 fn extern_location(e
: &clean
::ExternalCrate
, dst
: &Path
) -> ExternalLocation
{
866 // See if there's documentation generated into the local directory
867 let local_location
= dst
.join(&e
.name
);
868 if local_location
.is_dir() {
872 // Failing that, see if there's an attribute specifying where to find this
875 .filter(|a
| a
.check_name("html_root_url"))
876 .filter_map(|a
| a
.value_str())
878 let mut url
= url
.to_string();
879 if !url
.ends_with("/") {
883 }).next().unwrap_or(Unknown
) // Well, at least we tried.
886 impl<'a
> DocFolder
for SourceCollector
<'a
> {
887 fn fold_item(&mut self, item
: clean
::Item
) -> Option
<clean
::Item
> {
888 // If we're including source files, and we haven't seen this file yet,
889 // then we need to render it out to the filesystem.
890 if self.scx
.include_sources
891 // skip all invalid spans
892 && item
.source
.filename
!= ""
893 // skip non-local items
894 && item
.def_id
.is_local()
895 // Macros from other libraries get special filenames which we can
897 && !(item
.source
.filename
.starts_with("<")
898 && item
.source
.filename
.ends_with("macros>")) {
900 // If it turns out that we couldn't read this file, then we probably
901 // can't read any of the files (generating html output from json or
902 // something like that), so just don't include sources for the
903 // entire crate. The other option is maintaining this mapping on a
904 // per-file basis, but that's probably not worth it...
906 .include_sources
= match self.emit_source(&item
.source
.filename
) {
909 println
!("warning: source code was requested to be rendered, \
910 but processing `{}` had an error: {}",
911 item
.source
.filename
, e
);
912 println
!(" skipping rendering of source code");
917 self.fold_item_recur(item
)
921 impl<'a
> SourceCollector
<'a
> {
922 /// Renders the given filename into its corresponding HTML source file.
923 fn emit_source(&mut self, filename
: &str) -> io
::Result
<()> {
924 let p
= PathBuf
::from(filename
);
925 if self.scx
.local_sources
.contains_key(&p
) {
926 // We've already emitted this source
930 let mut contents
= Vec
::new();
931 File
::open(&p
).and_then(|mut f
| f
.read_to_end(&mut contents
))?
;
933 let contents
= str::from_utf8(&contents
).unwrap();
935 // Remove the utf-8 BOM if any
936 let contents
= if contents
.starts_with("\u{feff}") {
942 // Create the intermediate directories
943 let mut cur
= self.dst
.clone();
944 let mut root_path
= String
::from("../../");
945 let mut href
= String
::new();
946 clean_srcpath(&self.scx
.src_root
, &p
, false, |component
| {
948 mkdir(&cur
).unwrap();
949 root_path
.push_str("../");
950 href
.push_str(component
);
953 let mut fname
= p
.file_name().expect("source has no filename")
957 href
.push_str(&fname
.to_string_lossy());
959 let mut w
= BufWriter
::new(File
::create(&cur
)?
);
960 let title
= format
!("{} -- source", cur
.file_name().unwrap()
962 let desc
= format
!("Source to the Rust file `{}`.", filename
);
963 let page
= layout
::Page
{
966 root_path
: &root_path
,
968 keywords
: BASIC_KEYWORDS
,
970 layout
::render(&mut w
, &self.scx
.layout
,
971 &page
, &(""), &Source(contents
),
972 self.scx
.css_file_extension
.is_some())?
;
974 self.scx
.local_sources
.insert(p
, href
);
979 impl DocFolder
for Cache
{
980 fn fold_item(&mut self, item
: clean
::Item
) -> Option
<clean
::Item
> {
981 // If this is a stripped module,
982 // we don't want it or its children in the search index.
983 let orig_stripped_mod
= match item
.inner
{
984 clean
::StrippedItem(box clean
::ModuleItem(..)) => {
985 mem
::replace(&mut self.stripped_mod
, true)
987 _
=> self.stripped_mod
,
990 // Register any generics to their corresponding string. This is used
991 // when pretty-printing types.
992 if let Some(generics
) = item
.inner
.generics() {
993 self.generics(generics
);
996 // Propagate a trait method's documentation to all implementors of the
998 if let clean
::TraitItem(ref t
) = item
.inner
{
999 self.traits
.entry(item
.def_id
).or_insert_with(|| t
.clone());
1002 // Collect all the implementors of traits.
1003 if let clean
::ImplItem(ref i
) = item
.inner
{
1004 if let Some(did
) = i
.trait_
.def_id() {
1005 self.implementors
.entry(did
).or_insert(vec
![]).push(Implementor
{
1006 def_id
: item
.def_id
,
1007 stability
: item
.stability
.clone(),
1013 // Index this method for searching later on.
1014 if let Some(ref s
) = item
.name
{
1015 let (parent
, is_inherent_impl_item
) = match item
.inner
{
1016 clean
::StrippedItem(..) => ((None
, None
), false),
1017 clean
::AssociatedConstItem(..) |
1018 clean
::TypedefItem(_
, true) if self.parent_is_trait_impl
=> {
1019 // skip associated items in trait impls
1020 ((None
, None
), false)
1022 clean
::AssociatedTypeItem(..) |
1023 clean
::TyMethodItem(..) |
1024 clean
::StructFieldItem(..) |
1025 clean
::VariantItem(..) => {
1026 ((Some(*self.parent_stack
.last().unwrap()),
1027 Some(&self.stack
[..self.stack
.len() - 1])),
1030 clean
::MethodItem(..) | clean
::AssociatedConstItem(..) => {
1031 if self.parent_stack
.is_empty() {
1032 ((None
, None
), false)
1034 let last
= self.parent_stack
.last().unwrap();
1036 let path
= match self.paths
.get(&did
) {
1037 // The current stack not necessarily has correlation
1038 // for where the type was defined. On the other
1039 // hand, `paths` always has the right
1040 // information if present.
1041 Some(&(ref fqp
, ItemType
::Trait
)) |
1042 Some(&(ref fqp
, ItemType
::Struct
)) |
1043 Some(&(ref fqp
, ItemType
::Union
)) |
1044 Some(&(ref fqp
, ItemType
::Enum
)) =>
1045 Some(&fqp
[..fqp
.len() - 1]),
1046 Some(..) => Some(&*self.stack
),
1049 ((Some(*last
), path
), true)
1052 _
=> ((None
, Some(&*self.stack
)), false)
1056 (parent
, Some(path
)) if is_inherent_impl_item
|| (!self.stripped_mod
) => {
1057 debug_assert
!(!item
.is_stripped());
1059 // A crate has a module at its root, containing all items,
1060 // which should not be indexed. The crate-item itself is
1061 // inserted later on when serializing the search-index.
1062 if item
.def_id
.index
!= CRATE_DEF_INDEX
{
1063 self.search_index
.push(IndexItem
{
1065 name
: s
.to_string(),
1066 path
: path
.join("::").to_string(),
1067 desc
: plain_summary_line(item
.doc_value()),
1070 search_type
: get_index_search_type(&item
),
1074 (Some(parent
), None
) if is_inherent_impl_item
=> {
1075 // We have a parent, but we don't know where they're
1076 // defined yet. Wait for later to index this item.
1077 self.orphan_impl_items
.push((parent
, item
.clone()));
1083 // Keep track of the fully qualified path for this item.
1084 let pushed
= match item
.name
{
1085 Some(ref n
) if !n
.is_empty() => {
1086 self.stack
.push(n
.to_string());
1093 clean
::StructItem(..) | clean
::EnumItem(..) |
1094 clean
::TypedefItem(..) | clean
::TraitItem(..) |
1095 clean
::FunctionItem(..) | clean
::ModuleItem(..) |
1096 clean
::ForeignFunctionItem(..) | clean
::ForeignStaticItem(..) |
1097 clean
::ConstantItem(..) | clean
::StaticItem(..) |
1098 clean
::UnionItem(..)
1099 if !self.stripped_mod
=> {
1100 // Reexported items mean that the same id can show up twice
1101 // in the rustdoc ast that we're looking at. We know,
1102 // however, that a reexported item doesn't show up in the
1103 // `public_items` map, so we can skip inserting into the
1104 // paths map if there was already an entry present and we're
1105 // not a public item.
1107 !self.paths
.contains_key(&item
.def_id
) ||
1108 self.access_levels
.is_public(item
.def_id
)
1110 self.paths
.insert(item
.def_id
,
1111 (self.stack
.clone(), item
.type_()));
1114 // Link variants to their parent enum because pages aren't emitted
1115 // for each variant.
1116 clean
::VariantItem(..) if !self.stripped_mod
=> {
1117 let mut stack
= self.stack
.clone();
1119 self.paths
.insert(item
.def_id
, (stack
, ItemType
::Enum
));
1122 clean
::PrimitiveItem(..) if item
.visibility
.is_some() => {
1123 self.paths
.insert(item
.def_id
, (self.stack
.clone(),
1130 // Maintain the parent stack
1131 let orig_parent_is_trait_impl
= self.parent_is_trait_impl
;
1132 let parent_pushed
= match item
.inner
{
1133 clean
::TraitItem(..) | clean
::EnumItem(..) |
1134 clean
::StructItem(..) | clean
::UnionItem(..) => {
1135 self.parent_stack
.push(item
.def_id
);
1136 self.parent_is_trait_impl
= false;
1139 clean
::ImplItem(ref i
) => {
1140 self.parent_is_trait_impl
= i
.trait_
.is_some();
1142 clean
::ResolvedPath{ did, .. }
=> {
1143 self.parent_stack
.push(did
);
1147 let prim_did
= t
.primitive_type().and_then(|t
| {
1148 self.primitive_locations
.get(&t
).cloned()
1152 self.parent_stack
.push(did
);
1163 // Once we've recursively found all the generics, hoard off all the
1164 // implementations elsewhere.
1165 let ret
= self.fold_item_recur(item
).and_then(|item
| {
1166 if let clean
::Item { inner: clean::ImplItem(_), .. }
= item
{
1167 // Figure out the id of this impl. This may map to a
1168 // primitive rather than always to a struct/enum.
1169 // Note: matching twice to restrict the lifetime of the `i` borrow.
1170 let did
= if let clean
::Item { inner: clean::ImplItem(ref i), .. }
= item
{
1172 clean
::ResolvedPath { did, .. }
|
1173 clean
::BorrowedRef
{
1174 type_
: box clean
::ResolvedPath { did, .. }
, ..
1179 t
.primitive_type().and_then(|t
| {
1180 self.primitive_locations
.get(&t
).cloned()
1187 if let Some(did
) = did
{
1188 self.impls
.entry(did
).or_insert(vec
![]).push(Impl
{
1198 if pushed { self.stack.pop().unwrap(); }
1199 if parent_pushed { self.parent_stack.pop().unwrap(); }
1200 self.stripped_mod
= orig_stripped_mod
;
1201 self.parent_is_trait_impl
= orig_parent_is_trait_impl
;
1207 fn generics(&mut self, generics
: &clean
::Generics
) {
1208 for typ
in &generics
.type_params
{
1209 self.typarams
.insert(typ
.did
, typ
.name
.clone());
1215 /// String representation of how to get back to the root path of the 'doc/'
1216 /// folder in terms of a relative URL.
1217 fn root_path(&self) -> String
{
1218 repeat("../").take(self.current
.len()).collect
::<String
>()
1221 /// Recurse in the directory structure and change the "root path" to make
1222 /// sure it always points to the top (relatively).
1223 fn recurse
<T
, F
>(&mut self, s
: String
, f
: F
) -> T
where
1224 F
: FnOnce(&mut Context
) -> T
,
1227 panic
!("Unexpected empty destination: {:?}", self.current
);
1229 let prev
= self.dst
.clone();
1231 self.current
.push(s
);
1233 info
!("Recursing into {}", self.dst
.display());
1237 info
!("Recursed; leaving {}", self.dst
.display());
1239 // Go back to where we were at
1241 self.current
.pop().unwrap();
1246 /// Main method for rendering a crate.
1248 /// This currently isn't parallelized, but it'd be pretty easy to add
1249 /// parallelization to this function.
1250 fn krate(self, mut krate
: clean
::Crate
) -> Result
<(), Error
> {
1251 let mut item
= match krate
.module
.take() {
1253 None
=> return Ok(()),
1255 item
.name
= Some(krate
.name
);
1257 // Render the crate documentation
1258 let mut work
= vec
![(self, item
)];
1260 while let Some((mut cx
, item
)) = work
.pop() {
1261 cx
.item(item
, |cx
, item
| {
1262 work
.push((cx
.clone(), item
))
1268 fn render_item(&self,
1269 writer
: &mut io
::Write
,
1273 // A little unfortunate that this is done like this, but it sure
1274 // does make formatting *a lot* nicer.
1275 CURRENT_LOCATION_KEY
.with(|slot
| {
1276 *slot
.borrow_mut() = self.current
.clone();
1279 let mut title
= if it
.is_primitive() {
1280 // No need to include the namespace for primitive types
1283 self.current
.join("::")
1286 if !title
.is_empty() {
1287 title
.push_str("::");
1289 title
.push_str(it
.name
.as_ref().unwrap());
1291 title
.push_str(" - Rust");
1292 let tyname
= it
.type_().css_class();
1293 let desc
= if it
.is_crate() {
1294 format
!("API documentation for the Rust `{}` crate.",
1295 self.shared
.layout
.krate
)
1297 format
!("API documentation for the Rust `{}` {} in crate `{}`.",
1298 it
.name
.as_ref().unwrap(), tyname
, self.shared
.layout
.krate
)
1300 let keywords
= make_item_keywords(it
);
1301 let page
= layout
::Page
{
1303 root_path
: &self.root_path(),
1306 keywords
: &keywords
,
1311 if !self.render_redirect_pages
{
1312 layout
::render(writer
, &self.shared
.layout
, &page
,
1313 &Sidebar{ cx: self, item: it }
,
1314 &Item{ cx: self, item: it }
,
1315 self.shared
.css_file_extension
.is_some())?
;
1317 let mut url
= self.root_path();
1318 if let Some(&(ref names
, ty
)) = cache().paths
.get(&it
.def_id
) {
1319 for name
in &names
[..names
.len() - 1] {
1323 url
.push_str(&item_path(ty
, names
.last().unwrap()));
1324 layout
::redirect(writer
, &url
)?
;
1330 /// Non-parallelized version of rendering an item. This will take the input
1331 /// item, render its contents, and then invoke the specified closure with
1332 /// all sub-items which need to be rendered.
1334 /// The rendering driver uses this closure to queue up more work.
1335 fn item
<F
>(&mut self, item
: clean
::Item
, mut f
: F
) -> Result
<(), Error
> where
1336 F
: FnMut(&mut Context
, clean
::Item
),
1338 // Stripped modules survive the rustdoc passes (i.e. `strip-private`)
1339 // if they contain impls for public types. These modules can also
1340 // contain items such as publicly reexported structures.
1342 // External crates will provide links to these structures, so
1343 // these modules are recursed into, but not rendered normally
1344 // (a flag on the context).
1345 if !self.render_redirect_pages
{
1346 self.render_redirect_pages
= maybe_ignore_item(&item
);
1350 // modules are special because they add a namespace. We also need to
1351 // recurse into the items of the module as well.
1352 let name
= item
.name
.as_ref().unwrap().to_string();
1353 let mut item
= Some(item
);
1354 self.recurse(name
, |this
| {
1355 let item
= item
.take().unwrap();
1357 let mut buf
= Vec
::new();
1358 this
.render_item(&mut buf
, &item
, false).unwrap();
1359 // buf will be empty if the module is stripped and there is no redirect for it
1360 if !buf
.is_empty() {
1361 let joint_dst
= this
.dst
.join("index.html");
1362 try_err
!(fs
::create_dir_all(&this
.dst
), &this
.dst
);
1363 let mut dst
= try_err
!(File
::create(&joint_dst
), &joint_dst
);
1364 try_err
!(dst
.write_all(&buf
), &joint_dst
);
1367 let m
= match item
.inner
{
1368 clean
::StrippedItem(box clean
::ModuleItem(m
)) |
1369 clean
::ModuleItem(m
) => m
,
1373 // Render sidebar-items.js used throughout this module.
1374 if !this
.render_redirect_pages
{
1375 let items
= this
.build_sidebar_items(&m
);
1376 let js_dst
= this
.dst
.join("sidebar-items.js");
1377 let mut js_out
= BufWriter
::new(try_err
!(File
::create(&js_dst
), &js_dst
));
1378 try_err
!(write
!(&mut js_out
, "initSidebarItems({});",
1379 as_json(&items
)), &js_dst
);
1382 for item
in m
.items
{
1388 } else if item
.name
.is_some() {
1389 let mut buf
= Vec
::new();
1390 self.render_item(&mut buf
, &item
, true).unwrap();
1391 // buf will be empty if the item is stripped and there is no redirect for it
1392 if !buf
.is_empty() {
1393 let name
= item
.name
.as_ref().unwrap();
1394 let item_type
= item
.type_();
1395 let file_name
= &item_path(item_type
, name
);
1396 let joint_dst
= self.dst
.join(file_name
);
1397 try_err
!(fs
::create_dir_all(&self.dst
), &self.dst
);
1398 let mut dst
= try_err
!(File
::create(&joint_dst
), &joint_dst
);
1399 try_err
!(dst
.write_all(&buf
), &joint_dst
);
1401 // Redirect from a sane URL using the namespace to Rustdoc's
1402 // URL for the page.
1403 let redir_name
= format
!("{}.{}.html", name
, item_type
.name_space());
1404 let redir_dst
= self.dst
.join(redir_name
);
1405 if let Ok(mut redirect_out
) = OpenOptions
::new().create_new(true)
1408 try_err
!(layout
::redirect(&mut redirect_out
, file_name
), &redir_dst
);
1411 // If the item is a macro, redirect from the old macro URL (with !)
1412 // to the new one (without).
1413 // FIXME(#35705) remove this redirect.
1414 if item_type
== ItemType
::Macro
{
1415 let redir_name
= format
!("{}.{}!.html", item_type
, name
);
1416 let redir_dst
= self.dst
.join(redir_name
);
1417 let mut redirect_out
= try_err
!(File
::create(&redir_dst
), &redir_dst
);
1418 try_err
!(layout
::redirect(&mut redirect_out
, file_name
), &redir_dst
);
1425 fn build_sidebar_items(&self, m
: &clean
::Module
) -> BTreeMap
<String
, Vec
<NameDoc
>> {
1426 // BTreeMap instead of HashMap to get a sorted output
1427 let mut map
= BTreeMap
::new();
1428 for item
in &m
.items
{
1429 if maybe_ignore_item(item
) { continue }
1431 let short
= item
.type_().css_class();
1432 let myname
= match item
.name
{
1434 Some(ref s
) => s
.to_string(),
1436 let short
= short
.to_string();
1437 map
.entry(short
).or_insert(vec
![])
1438 .push((myname
, Some(plain_summary_line(item
.doc_value()))));
1441 for (_
, items
) in &mut map
{
1449 /// Generate a url appropriate for an `href` attribute back to the source of
1452 /// The url generated, when clicked, will redirect the browser back to the
1453 /// original source code.
1455 /// If `None` is returned, then a source link couldn't be generated. This
1456 /// may happen, for example, with externally inlined items where the source
1457 /// of their crate documentation isn't known.
1458 fn src_href(&self) -> Option
<String
> {
1459 let mut root
= self.cx
.root_path();
1461 let cache
= cache();
1462 let mut path
= String
::new();
1463 let (krate
, path
) = if self.item
.def_id
.is_local() {
1464 let path
= PathBuf
::from(&self.item
.source
.filename
);
1465 if let Some(path
) = self.cx
.shared
.local_sources
.get(&path
) {
1466 (&self.cx
.shared
.layout
.krate
, path
)
1471 // Macros from other libraries get special filenames which we can
1473 if self.item
.source
.filename
.starts_with("<") &&
1474 self.item
.source
.filename
.ends_with("macros>") {
1478 let (krate
, src_root
) = match cache
.extern_locations
.get(&self.item
.def_id
.krate
) {
1479 Some(&(ref name
, ref src
, Local
)) => (name
, src
),
1480 Some(&(ref name
, ref src
, Remote(ref s
))) => {
1481 root
= s
.to_string();
1484 Some(&(_
, _
, Unknown
)) | None
=> return None
,
1487 let file
= Path
::new(&self.item
.source
.filename
);
1488 clean_srcpath(&src_root
, file
, false, |component
| {
1489 path
.push_str(component
);
1492 let mut fname
= file
.file_name().expect("source has no filename")
1494 fname
.push(".html");
1495 path
.push_str(&fname
.to_string_lossy());
1499 let lines
= if self.item
.source
.loline
== self.item
.source
.hiline
{
1500 format
!("{}", self.item
.source
.loline
)
1502 format
!("{}-{}", self.item
.source
.loline
, self.item
.source
.hiline
)
1504 Some(format
!("{root}src/{krate}/{path}#{lines}",
1512 impl<'a
> fmt
::Display
for Item
<'a
> {
1513 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
1514 debug_assert
!(!self.item
.is_stripped());
1515 // Write the breadcrumb trail header for the top
1516 write
!(fmt
, "\n<h1 class='fqn'><span class='in-band'>")?
;
1517 match self.item
.inner
{
1518 clean
::ModuleItem(ref m
) => if m
.is_crate
{
1519 write
!(fmt
, "Crate ")?
;
1521 write
!(fmt
, "Module ")?
;
1523 clean
::FunctionItem(..) | clean
::ForeignFunctionItem(..) =>
1524 write
!(fmt
, "Function ")?
,
1525 clean
::TraitItem(..) => write
!(fmt
, "Trait ")?
,
1526 clean
::StructItem(..) => write
!(fmt
, "Struct ")?
,
1527 clean
::UnionItem(..) => write
!(fmt
, "Union ")?
,
1528 clean
::EnumItem(..) => write
!(fmt
, "Enum ")?
,
1529 clean
::TypedefItem(..) => write
!(fmt
, "Type Definition ")?
,
1530 clean
::MacroItem(..) => write
!(fmt
, "Macro ")?
,
1531 clean
::PrimitiveItem(..) => write
!(fmt
, "Primitive Type ")?
,
1532 clean
::StaticItem(..) | clean
::ForeignStaticItem(..) =>
1533 write
!(fmt
, "Static ")?
,
1534 clean
::ConstantItem(..) => write
!(fmt
, "Constant ")?
,
1536 // We don't generate pages for any other type.
1540 if !self.item
.is_primitive() {
1541 let cur
= &self.cx
.current
;
1542 let amt
= if self.item
.is_mod() { cur.len() - 1 }
else { cur.len() }
;
1543 for (i
, component
) in cur
.iter().enumerate().take(amt
) {
1544 write
!(fmt
, "<a href='{}index.html'>{}</a>::<wbr>",
1545 repeat("../").take(cur
.len() - i
- 1)
1546 .collect
::<String
>(),
1550 write
!(fmt
, "<a class=\"{}\" href=''>{}</a>",
1551 self.item
.type_(), self.item
.name
.as_ref().unwrap())?
;
1553 write
!(fmt
, "</span>")?
; // in-band
1554 write
!(fmt
, "<span class='out-of-band'>")?
;
1555 if let Some(version
) = self.item
.stable_since() {
1556 write
!(fmt
, "<span class='since' title='Stable since Rust version {0}'>{0}</span>",
1560 r
##"<span id='render-detail'>
1561 <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
1562 [<span class='inner'>−</span>]
1568 // When this item is part of a `pub use` in a downstream crate, the
1569 // [src] link in the downstream documentation will actually come back to
1570 // this page, and this link will be auto-clicked. The `id` attribute is
1571 // used to find the link to auto-click.
1572 if self.cx
.shared
.include_sources
&& !self.item
.is_primitive() {
1573 if let Some(l
) = self.src_href() {
1574 write
!(fmt
, "<a class='srclink' href='{}' title='{}'>[src]</a>",
1575 l
, "goto source code")?
;
1579 write
!(fmt
, "</span>")?
; // out-of-band
1581 write
!(fmt
, "</h1>\n")?
;
1583 match self.item
.inner
{
1584 clean
::ModuleItem(ref m
) => {
1585 item_module(fmt
, self.cx
, self.item
, &m
.items
)
1587 clean
::FunctionItem(ref f
) | clean
::ForeignFunctionItem(ref f
) =>
1588 item_function(fmt
, self.cx
, self.item
, f
),
1589 clean
::TraitItem(ref t
) => item_trait(fmt
, self.cx
, self.item
, t
),
1590 clean
::StructItem(ref s
) => item_struct(fmt
, self.cx
, self.item
, s
),
1591 clean
::UnionItem(ref s
) => item_union(fmt
, self.cx
, self.item
, s
),
1592 clean
::EnumItem(ref e
) => item_enum(fmt
, self.cx
, self.item
, e
),
1593 clean
::TypedefItem(ref t
, _
) => item_typedef(fmt
, self.cx
, self.item
, t
),
1594 clean
::MacroItem(ref m
) => item_macro(fmt
, self.cx
, self.item
, m
),
1595 clean
::PrimitiveItem(ref p
) => item_primitive(fmt
, self.cx
, self.item
, p
),
1596 clean
::StaticItem(ref i
) | clean
::ForeignStaticItem(ref i
) =>
1597 item_static(fmt
, self.cx
, self.item
, i
),
1598 clean
::ConstantItem(ref c
) => item_constant(fmt
, self.cx
, self.item
, c
),
1600 // We don't generate pages for any other type.
1607 fn item_path(ty
: ItemType
, name
: &str) -> String
{
1609 ItemType
::Module
=> format
!("{}/index.html", name
),
1610 _
=> format
!("{}.{}.html", ty
.css_class(), name
),
1614 fn full_path(cx
: &Context
, item
: &clean
::Item
) -> String
{
1615 let mut s
= cx
.current
.join("::");
1617 s
.push_str(item
.name
.as_ref().unwrap());
1621 fn shorter
<'a
>(s
: Option
<&'a
str>) -> String
{
1623 Some(s
) => s
.lines().take_while(|line
|{
1624 (*line
).chars().any(|chr
|{
1625 !chr
.is_whitespace()
1627 }).collect
::<Vec
<_
>>().join("\n"),
1628 None
=> "".to_string()
1633 fn plain_summary_line(s
: Option
<&str>) -> String
{
1634 let line
= shorter(s
).replace("\n", " ");
1635 markdown
::plain_summary_line(&line
[..])
1638 fn document(w
: &mut fmt
::Formatter
, cx
: &Context
, item
: &clean
::Item
) -> fmt
::Result
{
1639 document_stability(w
, cx
, item
)?
;
1640 document_full(w
, item
)?
;
1644 fn document_short(w
: &mut fmt
::Formatter
, item
: &clean
::Item
, link
: AssocItemLink
) -> fmt
::Result
{
1645 if let Some(s
) = item
.doc_value() {
1646 let markdown
= if s
.contains('
\n'
) {
1647 format
!("{} [Read more]({})",
1648 &plain_summary_line(Some(s
)), naive_assoc_href(item
, link
))
1650 format
!("{}", &plain_summary_line(Some(s
)))
1652 write
!(w
, "<div class='docblock'>{}</div>", Markdown(&markdown
))?
;
1657 fn md_render_assoc_item(item
: &clean
::Item
) -> String
{
1659 clean
::AssociatedConstItem(ref ty
, ref default) => {
1660 if let Some(default) = default.as_ref() {
1661 format
!("```\n{}: {:?} = {}\n```\n\n", item
.name
.as_ref().unwrap(), ty
, default)
1663 format
!("```\n{}: {:?}\n```\n\n", item
.name
.as_ref().unwrap(), ty
)
1670 fn get_doc_value(item
: &clean
::Item
) -> Option
<&str> {
1671 let x
= item
.doc_value();
1674 clean
::AssociatedConstItem(_
, _
) => Some(""),
1682 fn document_full(w
: &mut fmt
::Formatter
, item
: &clean
::Item
) -> fmt
::Result
{
1683 if let Some(s
) = get_doc_value(item
) {
1684 write
!(w
, "<div class='docblock'>{}</div>",
1685 Markdown(&format
!("{}{}", md_render_assoc_item(item
), s
)))?
;
1690 fn document_stability(w
: &mut fmt
::Formatter
, cx
: &Context
, item
: &clean
::Item
) -> fmt
::Result
{
1691 let stabilities
= short_stability(item
, cx
, true);
1692 if !stabilities
.is_empty() {
1693 write
!(w
, "<div class='stability'>")?
;
1694 for stability
in stabilities
{
1695 write
!(w
, "{}", stability
)?
;
1697 write
!(w
, "</div>")?
;
1702 fn item_module(w
: &mut fmt
::Formatter
, cx
: &Context
,
1703 item
: &clean
::Item
, items
: &[clean
::Item
]) -> fmt
::Result
{
1704 document(w
, cx
, item
)?
;
1706 let mut indices
= (0..items
.len()).filter(|i
| {
1707 if let clean
::DefaultImplItem(..) = items
[*i
].inner
{
1710 !maybe_ignore_item(&items
[*i
])
1711 }).collect
::<Vec
<usize>>();
1713 // the order of item types in the listing
1714 fn reorder(ty
: ItemType
) -> u8 {
1716 ItemType
::ExternCrate
=> 0,
1717 ItemType
::Import
=> 1,
1718 ItemType
::Primitive
=> 2,
1719 ItemType
::Module
=> 3,
1720 ItemType
::Macro
=> 4,
1721 ItemType
::Struct
=> 5,
1722 ItemType
::Enum
=> 6,
1723 ItemType
::Constant
=> 7,
1724 ItemType
::Static
=> 8,
1725 ItemType
::Trait
=> 9,
1726 ItemType
::Function
=> 10,
1727 ItemType
::Typedef
=> 12,
1728 ItemType
::Union
=> 13,
1733 fn cmp(i1
: &clean
::Item
, i2
: &clean
::Item
, idx1
: usize, idx2
: usize) -> Ordering
{
1734 let ty1
= i1
.type_();
1735 let ty2
= i2
.type_();
1737 return (reorder(ty1
), idx1
).cmp(&(reorder(ty2
), idx2
))
1739 let s1
= i1
.stability
.as_ref().map(|s
| s
.level
);
1740 let s2
= i2
.stability
.as_ref().map(|s
| s
.level
);
1742 (Some(stability
::Unstable
), Some(stability
::Stable
)) => return Ordering
::Greater
,
1743 (Some(stability
::Stable
), Some(stability
::Unstable
)) => return Ordering
::Less
,
1746 i1
.name
.cmp(&i2
.name
)
1749 indices
.sort_by(|&i1
, &i2
| cmp(&items
[i1
], &items
[i2
], i1
, i2
));
1751 debug
!("{:?}", indices
);
1752 let mut curty
= None
;
1753 for &idx
in &indices
{
1754 let myitem
= &items
[idx
];
1755 if myitem
.is_stripped() {
1759 let myty
= Some(myitem
.type_());
1760 if curty
== Some(ItemType
::ExternCrate
) && myty
== Some(ItemType
::Import
) {
1761 // Put `extern crate` and `use` re-exports in the same section.
1763 } else if myty
!= curty
{
1764 if curty
.is_some() {
1765 write
!(w
, "</table>")?
;
1768 let (short
, name
) = match myty
.unwrap() {
1769 ItemType
::ExternCrate
|
1770 ItemType
::Import
=> ("reexports", "Reexports"),
1771 ItemType
::Module
=> ("modules", "Modules"),
1772 ItemType
::Struct
=> ("structs", "Structs"),
1773 ItemType
::Union
=> ("unions", "Unions"),
1774 ItemType
::Enum
=> ("enums", "Enums"),
1775 ItemType
::Function
=> ("functions", "Functions"),
1776 ItemType
::Typedef
=> ("types", "Type Definitions"),
1777 ItemType
::Static
=> ("statics", "Statics"),
1778 ItemType
::Constant
=> ("constants", "Constants"),
1779 ItemType
::Trait
=> ("traits", "Traits"),
1780 ItemType
::Impl
=> ("impls", "Implementations"),
1781 ItemType
::TyMethod
=> ("tymethods", "Type Methods"),
1782 ItemType
::Method
=> ("methods", "Methods"),
1783 ItemType
::StructField
=> ("fields", "Struct Fields"),
1784 ItemType
::Variant
=> ("variants", "Variants"),
1785 ItemType
::Macro
=> ("macros", "Macros"),
1786 ItemType
::Primitive
=> ("primitives", "Primitive Types"),
1787 ItemType
::AssociatedType
=> ("associated-types", "Associated Types"),
1788 ItemType
::AssociatedConst
=> ("associated-consts", "Associated Constants"),
1790 write
!(w
, "<h2 id='{id}' class='section-header'>\
1791 <a href=\"#{id}\">{name}</a></h2>\n<table>",
1792 id
= derive_id(short
.to_owned()), name
= name
)?
;
1795 match myitem
.inner
{
1796 clean
::ExternCrateItem(ref name
, ref src
) => {
1797 use html
::format
::HRef
;
1801 write
!(w
, "<tr><td><code>{}extern crate {} as {};",
1802 VisSpace(&myitem
.visibility
),
1803 HRef
::new(myitem
.def_id
, src
),
1807 write
!(w
, "<tr><td><code>{}extern crate {};",
1808 VisSpace(&myitem
.visibility
),
1809 HRef
::new(myitem
.def_id
, name
))?
1812 write
!(w
, "</code></td></tr>")?
;
1815 clean
::ImportItem(ref import
) => {
1816 write
!(w
, "<tr><td><code>{}{}</code></td></tr>",
1817 VisSpace(&myitem
.visibility
), *import
)?
;
1821 if myitem
.name
.is_none() { continue }
1823 let stabilities
= short_stability(myitem
, cx
, false);
1825 let stab_docs
= if !stabilities
.is_empty() {
1827 .map(|s
| format
!("[{}]", s
))
1828 .collect
::<Vec
<_
>>()
1835 let unsafety_flag
= match myitem
.inner
{
1836 clean
::FunctionItem(ref func
) | clean
::ForeignFunctionItem(ref func
)
1837 if func
.unsafety
== hir
::Unsafety
::Unsafe
=> {
1838 "<a title='unsafe function' href='#'><sup>âš </sup></a>"
1843 let doc_value
= myitem
.doc_value().unwrap_or("");
1845 <tr class='{stab} module-item'>
1846 <td><a class=\"{class}\" href=\"{href}\"
1847 title='{title_type} {title}'>{name}</a>{unsafety_flag}</td>
1848 <td class='docblock-short'>
1852 name
= *myitem
.name
.as_ref().unwrap(),
1853 stab_docs
= stab_docs
,
1854 docs
= shorter(Some(&Markdown(doc_value
).to_string())),
1855 class
= myitem
.type_(),
1856 stab
= myitem
.stability_class().unwrap_or("".to_string()),
1857 unsafety_flag
= unsafety_flag
,
1858 href
= item_path(myitem
.type_(), myitem
.name
.as_ref().unwrap()),
1859 title_type
= myitem
.type_(),
1860 title
= full_path(cx
, myitem
))?
;
1865 if curty
.is_some() {
1866 write
!(w
, "</table>")?
;
1871 fn maybe_ignore_item(it
: &clean
::Item
) -> bool
{
1873 clean
::StrippedItem(..) => true,
1874 clean
::ModuleItem(ref m
) => {
1875 it
.doc_value().is_none() && m
.items
.is_empty()
1876 && it
.visibility
!= Some(clean
::Public
)
1882 fn short_stability(item
: &clean
::Item
, cx
: &Context
, show_reason
: bool
) -> Vec
<String
> {
1883 let mut stability
= vec
![];
1885 if let Some(stab
) = item
.stability
.as_ref() {
1886 let deprecated_reason
= if show_reason
&& !stab
.deprecated_reason
.is_empty() {
1887 format
!(": {}", stab
.deprecated_reason
)
1891 if !stab
.deprecated_since
.is_empty() {
1892 let since
= if show_reason
{
1893 format
!(" since {}", Escape(&stab
.deprecated_since
))
1897 let text
= format
!("Deprecated{}{}", since
, MarkdownHtml(&deprecated_reason
));
1898 stability
.push(format
!("<div class='stab deprecated'>{}</div>", text
))
1901 if stab
.level
== stability
::Unstable
{
1903 let unstable_extra
= match (!stab
.feature
.is_empty(),
1904 &cx
.shared
.issue_tracker_base_url
,
1906 (true, &Some(ref tracker_url
), Some(issue_no
)) if issue_no
> 0 =>
1907 format
!(" (<code>{} </code><a href=\"{}{}\">#{}</a>)",
1908 Escape(&stab
.feature
), tracker_url
, issue_no
, issue_no
),
1909 (false, &Some(ref tracker_url
), Some(issue_no
)) if issue_no
> 0 =>
1910 format
!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url
), issue_no
,
1913 format
!(" (<code>{}</code>)", Escape(&stab
.feature
)),
1916 if stab
.unstable_reason
.is_empty() {
1917 stability
.push(format
!("<div class='stab unstable'>\
1918 <span class=microscope>🔬</span> \
1919 This is a nightly-only experimental API. {}\
1923 let text
= format
!("<summary><span class=microscope>🔬</span> \
1924 This is a nightly-only experimental API. {}\
1926 unstable_extra
, MarkdownHtml(&stab
.unstable_reason
));
1927 stability
.push(format
!("<div class='stab unstable'><details>{}</details></div>",
1931 stability
.push(format
!("<div class='stab unstable'>Experimental</div>"))
1934 } else if let Some(depr
) = item
.deprecation
.as_ref() {
1935 let note
= if show_reason
&& !depr
.note
.is_empty() {
1936 format
!(": {}", depr
.note
)
1940 let since
= if show_reason
&& !depr
.since
.is_empty() {
1941 format
!(" since {}", Escape(&depr
.since
))
1946 let text
= format
!("Deprecated{}{}", since
, MarkdownHtml(¬e
));
1947 stability
.push(format
!("<div class='stab deprecated'>{}</div>", text
))
1953 struct Initializer
<'a
>(&'a
str);
1955 impl<'a
> fmt
::Display
for Initializer
<'a
> {
1956 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1957 let Initializer(s
) = *self;
1958 if s
.is_empty() { return Ok(()); }
1959 write
!(f
, "<code> = </code>")?
;
1960 write
!(f
, "<code>{}</code>", Escape(s
))
1964 fn item_constant(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
1965 c
: &clean
::Constant
) -> fmt
::Result
{
1966 write
!(w
, "<pre class='rust const'>")?
;
1967 render_attributes(w
, it
)?
;
1968 write
!(w
, "{vis}const \
1969 {name}: {typ}{init}</pre>",
1970 vis
= VisSpace(&it
.visibility
),
1971 name
= it
.name
.as_ref().unwrap(),
1973 init
= Initializer(&c
.expr
))?
;
1977 fn item_static(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
1978 s
: &clean
::Static
) -> fmt
::Result
{
1979 write
!(w
, "<pre class='rust static'>")?
;
1980 render_attributes(w
, it
)?
;
1981 write
!(w
, "{vis}static {mutability}\
1982 {name}: {typ}{init}</pre>",
1983 vis
= VisSpace(&it
.visibility
),
1984 mutability
= MutableSpace(s
.mutability
),
1985 name
= it
.name
.as_ref().unwrap(),
1987 init
= Initializer(&s
.expr
))?
;
1991 fn item_function(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
1992 f
: &clean
::Function
) -> fmt
::Result
{
1993 // FIXME(#24111): remove when `const_fn` is stabilized
1994 let vis_constness
= match UnstableFeatures
::from_environment() {
1995 UnstableFeatures
::Allow
=> f
.constness
,
1996 _
=> hir
::Constness
::NotConst
1998 let indent
= format
!("{}{}{}{:#}fn {}{:#}",
1999 VisSpace(&it
.visibility
),
2000 ConstnessSpace(vis_constness
),
2001 UnsafetySpace(f
.unsafety
),
2003 it
.name
.as_ref().unwrap(),
2005 write
!(w
, "<pre class='rust fn'>")?
;
2006 render_attributes(w
, it
)?
;
2007 write
!(w
, "{vis}{constness}{unsafety}{abi}fn \
2008 {name}{generics}{decl}{where_clause}</pre>",
2009 vis
= VisSpace(&it
.visibility
),
2010 constness
= ConstnessSpace(vis_constness
),
2011 unsafety
= UnsafetySpace(f
.unsafety
),
2012 abi
= AbiSpace(f
.abi
),
2013 name
= it
.name
.as_ref().unwrap(),
2014 generics
= f
.generics
,
2015 where_clause
= WhereClause(&f
.generics
, 2),
2016 decl
= Method(&f
.decl
, indent
))?
;
2020 fn item_trait(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
2021 t
: &clean
::Trait
) -> fmt
::Result
{
2022 let mut bounds
= String
::new();
2023 let mut bounds_plain
= String
::new();
2024 if !t
.bounds
.is_empty() {
2025 if !bounds
.is_empty() {
2027 bounds_plain
.push(' '
);
2029 bounds
.push_str(": ");
2030 bounds_plain
.push_str(": ");
2031 for (i
, p
) in t
.bounds
.iter().enumerate() {
2033 bounds
.push_str(" + ");
2034 bounds_plain
.push_str(" + ");
2036 bounds
.push_str(&format
!("{}", *p
));
2037 bounds_plain
.push_str(&format
!("{:#}", *p
));
2041 // Output the trait definition
2042 write
!(w
, "<pre class='rust trait'>")?
;
2043 render_attributes(w
, it
)?
;
2044 write
!(w
, "{}{}trait {}{}{}{} ",
2045 VisSpace(&it
.visibility
),
2046 UnsafetySpace(t
.unsafety
),
2047 it
.name
.as_ref().unwrap(),
2050 // Where clauses in traits are indented nine spaces, per rustdoc.css
2051 WhereClause(&t
.generics
, 9))?
;
2053 let types
= t
.items
.iter().filter(|m
| m
.is_associated_type()).collect
::<Vec
<_
>>();
2054 let consts
= t
.items
.iter().filter(|m
| m
.is_associated_const()).collect
::<Vec
<_
>>();
2055 let required
= t
.items
.iter().filter(|m
| m
.is_ty_method()).collect
::<Vec
<_
>>();
2056 let provided
= t
.items
.iter().filter(|m
| m
.is_method()).collect
::<Vec
<_
>>();
2058 if t
.items
.is_empty() {
2059 write
!(w
, "{{ }}")?
;
2061 // FIXME: we should be using a derived_id for the Anchors here
2065 render_assoc_item(w
, t
, AssocItemLink
::Anchor(None
), ItemType
::Trait
)?
;
2068 if !types
.is_empty() && !consts
.is_empty() {
2073 render_assoc_item(w
, t
, AssocItemLink
::Anchor(None
), ItemType
::Trait
)?
;
2076 if !consts
.is_empty() && !required
.is_empty() {
2079 for m
in &required
{
2081 render_assoc_item(w
, m
, AssocItemLink
::Anchor(None
), ItemType
::Trait
)?
;
2084 if !required
.is_empty() && !provided
.is_empty() {
2087 for m
in &provided
{
2089 render_assoc_item(w
, m
, AssocItemLink
::Anchor(None
), ItemType
::Trait
)?
;
2090 write
!(w
, " {{ ... }}\n")?
;
2094 write
!(w
, "</pre>")?
;
2096 // Trait documentation
2097 document(w
, cx
, it
)?
;
2099 fn trait_item(w
: &mut fmt
::Formatter
, cx
: &Context
, m
: &clean
::Item
, t
: &clean
::Item
)
2101 let name
= m
.name
.as_ref().unwrap();
2102 let item_type
= m
.type_();
2103 let id
= derive_id(format
!("{}.{}", item_type
, name
));
2104 let ns_id
= derive_id(format
!("{}.{}", name
, item_type
.name_space()));
2105 write
!(w
, "<h3 id='{id}' class='method'>\
2106 <span id='{ns_id}' class='invisible'><code>",
2109 render_assoc_item(w
, m
, AssocItemLink
::Anchor(Some(&id
)), ItemType
::Impl
)?
;
2110 write
!(w
, "</code>")?
;
2111 render_stability_since(w
, m
, t
)?
;
2112 write
!(w
, "</span></h3>")?
;
2113 document(w
, cx
, m
)?
;
2117 if !types
.is_empty() {
2119 <h2 id='associated-types'>Associated Types</h2>
2120 <div class='methods'>
2123 trait_item(w
, cx
, *t
, it
)?
;
2125 write
!(w
, "</div>")?
;
2128 if !consts
.is_empty() {
2130 <h2 id='associated-const'>Associated Constants</h2>
2131 <div class='methods'>
2134 trait_item(w
, cx
, *t
, it
)?
;
2136 write
!(w
, "</div>")?
;
2139 // Output the documentation for each function individually
2140 if !required
.is_empty() {
2142 <h2 id='required-methods'>Required Methods</h2>
2143 <div class='methods'>
2145 for m
in &required
{
2146 trait_item(w
, cx
, *m
, it
)?
;
2148 write
!(w
, "</div>")?
;
2150 if !provided
.is_empty() {
2152 <h2 id='provided-methods'>Provided Methods</h2>
2153 <div class='methods'>
2155 for m
in &provided
{
2156 trait_item(w
, cx
, *m
, it
)?
;
2158 write
!(w
, "</div>")?
;
2161 // If there are methods directly on this trait object, render them here.
2162 render_assoc_items(w
, cx
, it
, it
.def_id
, AssocItemRender
::All
)?
;
2164 let cache
= cache();
2166 <h2 id='implementors'>Implementors</h2>
2167 <ul class='item-list' id='implementors-list'>
2169 if let Some(implementors
) = cache
.implementors
.get(&it
.def_id
) {
2170 // The DefId is for the first Type found with that name. The bool is
2171 // if any Types with the same name but different DefId have been found.
2172 let mut implementor_dups
: FxHashMap
<&str, (DefId
, bool
)> = FxHashMap();
2173 for implementor
in implementors
{
2174 match implementor
.impl_
.for_
{
2175 clean
::ResolvedPath { ref path, did, is_generic: false, .. }
|
2176 clean
::BorrowedRef
{
2177 type_
: box clean
::ResolvedPath { ref path, did, is_generic: false, .. }
,
2180 let &mut (prev_did
, ref mut has_duplicates
) =
2181 implementor_dups
.entry(path
.last_name()).or_insert((did
, false));
2182 if prev_did
!= did
{
2183 *has_duplicates
= true;
2190 for implementor
in implementors
{
2191 write
!(w
, "<li><code>")?
;
2192 // If there's already another implementor that has the same abbridged name, use the
2193 // full path, for example in `std::iter::ExactSizeIterator`
2194 let use_absolute
= match implementor
.impl_
.for_
{
2195 clean
::ResolvedPath { ref path, is_generic: false, .. }
|
2196 clean
::BorrowedRef
{
2197 type_
: box clean
::ResolvedPath { ref path, is_generic: false, .. }
,
2199 } => implementor_dups
[path
.last_name()].1,
2202 fmt_impl_for_trait_page(&implementor
.impl_
, w
, use_absolute
)?
;
2203 writeln
!(w
, "</code></li>")?
;
2206 write
!(w
, "</ul>")?
;
2207 write
!(w
, r
#"<script type="text/javascript" async
2208 src="{root_path}/implementors/{path}/{ty}.{name}.js">
2210 root_path
= vec
![".."; cx
.current
.len()].join("/"),
2211 path
= if it
.def_id
.is_local() {
2212 cx
.current
.join("/")
2214 let (ref path
, _
) = cache
.external_paths
[&it
.def_id
];
2215 path
[..path
.len() - 1].join("/")
2217 ty
= it
.type_().css_class(),
2218 name
= *it
.name
.as_ref().unwrap())?
;
2222 fn naive_assoc_href(it
: &clean
::Item
, link
: AssocItemLink
) -> String
{
2223 use html
::item_type
::ItemType
::*;
2225 let name
= it
.name
.as_ref().unwrap();
2226 let ty
= match it
.type_() {
2227 Typedef
| AssociatedType
=> AssociatedType
,
2231 let anchor
= format
!("#{}.{}", ty
, name
);
2233 AssocItemLink
::Anchor(Some(ref id
)) => format
!("#{}", id
),
2234 AssocItemLink
::Anchor(None
) => anchor
,
2235 AssocItemLink
::GotoSource(did
, _
) => {
2236 href(did
).map(|p
| format
!("{}{}", p
.0, anchor
)).unwrap_or(anchor
)
2241 fn assoc_const(w
: &mut fmt
::Formatter
,
2244 _default
: Option
<&String
>,
2245 link
: AssocItemLink
) -> fmt
::Result
{
2246 write
!(w
, "const <a href='{}' class=\"constant\"><b>{}</b></a>: {}",
2247 naive_assoc_href(it
, link
),
2248 it
.name
.as_ref().unwrap(),
2253 fn assoc_type(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2254 bounds
: &Vec
<clean
::TyParamBound
>,
2255 default: Option
<&clean
::Type
>,
2256 link
: AssocItemLink
) -> fmt
::Result
{
2257 write
!(w
, "type <a href='{}' class=\"type\">{}</a>",
2258 naive_assoc_href(it
, link
),
2259 it
.name
.as_ref().unwrap())?
;
2260 if !bounds
.is_empty() {
2261 write
!(w
, ": {}", TyParamBounds(bounds
))?
2263 if let Some(default) = default {
2264 write
!(w
, " = {}", default)?
;
2269 fn render_stability_since_raw
<'a
>(w
: &mut fmt
::Formatter
,
2270 ver
: Option
<&'a
str>,
2271 containing_ver
: Option
<&'a
str>) -> fmt
::Result
{
2272 if let Some(v
) = ver
{
2273 if containing_ver
!= ver
&& v
.len() > 0 {
2274 write
!(w
, "<div class='since' title='Stable since Rust version {0}'>{0}</div>",
2281 fn render_stability_since(w
: &mut fmt
::Formatter
,
2283 containing_item
: &clean
::Item
) -> fmt
::Result
{
2284 render_stability_since_raw(w
, item
.stable_since(), containing_item
.stable_since())
2287 fn render_assoc_item(w
: &mut fmt
::Formatter
,
2289 link
: AssocItemLink
,
2290 parent
: ItemType
) -> fmt
::Result
{
2291 fn method(w
: &mut fmt
::Formatter
,
2293 unsafety
: hir
::Unsafety
,
2294 constness
: hir
::Constness
,
2296 g
: &clean
::Generics
,
2298 link
: AssocItemLink
,
2301 let name
= meth
.name
.as_ref().unwrap();
2302 let anchor
= format
!("#{}.{}", meth
.type_(), name
);
2303 let href
= match link
{
2304 AssocItemLink
::Anchor(Some(ref id
)) => format
!("#{}", id
),
2305 AssocItemLink
::Anchor(None
) => anchor
,
2306 AssocItemLink
::GotoSource(did
, provided_methods
) => {
2307 // We're creating a link from an impl-item to the corresponding
2308 // trait-item and need to map the anchored type accordingly.
2309 let ty
= if provided_methods
.contains(name
) {
2315 href(did
).map(|p
| format
!("{}#{}.{}", p
.0, ty
, name
)).unwrap_or(anchor
)
2318 // FIXME(#24111): remove when `const_fn` is stabilized
2319 let vis_constness
= match UnstableFeatures
::from_environment() {
2320 UnstableFeatures
::Allow
=> constness
,
2321 _
=> hir
::Constness
::NotConst
2323 let prefix
= format
!("{}{}{:#}fn {}{:#}",
2324 ConstnessSpace(vis_constness
),
2325 UnsafetySpace(unsafety
),
2329 let mut indent
= prefix
.len();
2330 let where_indent
= if parent
== ItemType
::Trait
{
2333 } else if parent
== ItemType
::Impl
{
2336 let prefix
= prefix
+ &format
!("{:#}", Method(d
, indent
));
2337 prefix
.lines().last().unwrap().len() + 1
2339 write
!(w
, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
2340 {generics}{decl}{where_clause}",
2341 ConstnessSpace(vis_constness
),
2342 UnsafetySpace(unsafety
),
2347 decl
= Method(d
, indent
),
2348 where_clause
= WhereClause(g
, where_indent
))
2351 clean
::StrippedItem(..) => Ok(()),
2352 clean
::TyMethodItem(ref m
) => {
2353 method(w
, item
, m
.unsafety
, hir
::Constness
::NotConst
,
2354 m
.abi
, &m
.generics
, &m
.decl
, link
, parent
)
2356 clean
::MethodItem(ref m
) => {
2357 method(w
, item
, m
.unsafety
, m
.constness
,
2358 m
.abi
, &m
.generics
, &m
.decl
, link
, parent
)
2360 clean
::AssociatedConstItem(ref ty
, ref default) => {
2361 assoc_const(w
, item
, ty
, default.as_ref(), link
)
2363 clean
::AssociatedTypeItem(ref bounds
, ref default) => {
2364 assoc_type(w
, item
, bounds
, default.as_ref(), link
)
2366 _
=> panic
!("render_assoc_item called on non-associated-item")
2370 fn item_struct(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
2371 s
: &clean
::Struct
) -> fmt
::Result
{
2372 write
!(w
, "<pre class='rust struct'>")?
;
2373 render_attributes(w
, it
)?
;
2381 write
!(w
, "</pre>")?
;
2383 document(w
, cx
, it
)?
;
2384 let mut fields
= s
.fields
.iter().filter_map(|f
| {
2386 clean
::StructFieldItem(ref ty
) => Some((f
, ty
)),
2390 if let doctree
::Plain
= s
.struct_type
{
2391 if fields
.peek().is_some() {
2392 write
!(w
, "<h2 class='fields'>Fields</h2>")?
;
2393 for (field
, ty
) in fields
{
2394 let id
= derive_id(format
!("{}.{}",
2395 ItemType
::StructField
,
2396 field
.name
.as_ref().unwrap()));
2397 let ns_id
= derive_id(format
!("{}.{}",
2398 field
.name
.as_ref().unwrap(),
2399 ItemType
::StructField
.name_space()));
2400 write
!(w
, "<span id='{id}' class=\"{item_type}\">
2401 <span id='{ns_id}' class='invisible'>
2402 <code>{name}: {ty}</code>
2404 item_type
= ItemType
::StructField
,
2407 name
= field
.name
.as_ref().unwrap(),
2409 if let Some(stability_class
) = field
.stability_class() {
2410 write
!(w
, "<span class='stab {stab}'></span>",
2411 stab
= stability_class
)?
;
2413 document(w
, cx
, field
)?
;
2417 render_assoc_items(w
, cx
, it
, it
.def_id
, AssocItemRender
::All
)
2420 fn item_union(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
2421 s
: &clean
::Union
) -> fmt
::Result
{
2422 write
!(w
, "<pre class='rust union'>")?
;
2423 render_attributes(w
, it
)?
;
2430 write
!(w
, "</pre>")?
;
2432 document(w
, cx
, it
)?
;
2433 let mut fields
= s
.fields
.iter().filter_map(|f
| {
2435 clean
::StructFieldItem(ref ty
) => Some((f
, ty
)),
2439 if fields
.peek().is_some() {
2440 write
!(w
, "<h2 class='fields'>Fields</h2>")?
;
2441 for (field
, ty
) in fields
{
2442 write
!(w
, "<span id='{shortty}.{name}' class=\"{shortty}\"><code>{name}: {ty}</code>
2444 shortty
= ItemType
::StructField
,
2445 name
= field
.name
.as_ref().unwrap(),
2447 if let Some(stability_class
) = field
.stability_class() {
2448 write
!(w
, "<span class='stab {stab}'></span>",
2449 stab
= stability_class
)?
;
2451 document(w
, cx
, field
)?
;
2454 render_assoc_items(w
, cx
, it
, it
.def_id
, AssocItemRender
::All
)
2457 fn item_enum(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
2458 e
: &clean
::Enum
) -> fmt
::Result
{
2459 write
!(w
, "<pre class='rust enum'>")?
;
2460 render_attributes(w
, it
)?
;
2461 let padding
= format
!("{}enum {}{:#} ",
2462 VisSpace(&it
.visibility
),
2463 it
.name
.as_ref().unwrap(),
2465 write
!(w
, "{}enum {}{}{}",
2466 VisSpace(&it
.visibility
),
2467 it
.name
.as_ref().unwrap(),
2469 WhereClause(&e
.generics
, padding
))?
;
2470 if e
.variants
.is_empty() && !e
.variants_stripped
{
2471 write
!(w
, " {{}}")?
;
2473 write
!(w
, " {{\n")?
;
2474 for v
in &e
.variants
{
2476 let name
= v
.name
.as_ref().unwrap();
2478 clean
::VariantItem(ref var
) => {
2480 clean
::VariantKind
::CLike
=> write
!(w
, "{}", name
)?
,
2481 clean
::VariantKind
::Tuple(ref tys
) => {
2482 write
!(w
, "{}(", name
)?
;
2483 for (i
, ty
) in tys
.iter().enumerate() {
2485 write
!(w
, ", ")?
2487 write
!(w
, "{}", *ty
)?
;
2491 clean
::VariantKind
::Struct(ref s
) => {
2507 if e
.variants_stripped
{
2508 write
!(w
, " // some variants omitted\n")?
;
2512 write
!(w
, "</pre>")?
;
2514 document(w
, cx
, it
)?
;
2515 if !e
.variants
.is_empty() {
2516 write
!(w
, "<h2 class='variants'>Variants</h2>\n")?
;
2517 for variant
in &e
.variants
{
2518 let id
= derive_id(format
!("{}.{}",
2520 variant
.name
.as_ref().unwrap()));
2521 let ns_id
= derive_id(format
!("{}.{}",
2522 variant
.name
.as_ref().unwrap(),
2523 ItemType
::Variant
.name_space()));
2524 write
!(w
, "<span id='{id}' class='variant'>\
2525 <span id='{ns_id}' class='invisible'><code>{name}",
2528 name
= variant
.name
.as_ref().unwrap())?
;
2529 if let clean
::VariantItem(ref var
) = variant
.inner
{
2530 if let clean
::VariantKind
::Tuple(ref tys
) = var
.kind
{
2532 for (i
, ty
) in tys
.iter().enumerate() {
2534 write
!(w
, ", ")?
;
2536 write
!(w
, "{}", *ty
)?
;
2541 write
!(w
, "</code></span></span>")?
;
2542 document(w
, cx
, variant
)?
;
2544 use clean
::{Variant, VariantKind}
;
2545 if let clean
::VariantItem(Variant
{
2546 kind
: VariantKind
::Struct(ref s
)
2547 }) = variant
.inner
{
2548 let variant_id
= derive_id(format
!("{}.{}.fields",
2550 variant
.name
.as_ref().unwrap()));
2551 write
!(w
, "<span class='docblock autohide sub-variant' id='{id}'>",
2553 write
!(w
, "<h3 class='fields'>Fields of <code>{name}</code></h3>\n
2554 <table>", name
= variant
.name
.as_ref().unwrap())?
;
2555 for field
in &s
.fields
{
2556 use clean
::StructFieldItem
;
2557 if let StructFieldItem(ref ty
) = field
.inner
{
2558 let id
= derive_id(format
!("variant.{}.field.{}",
2559 variant
.name
.as_ref().unwrap(),
2560 field
.name
.as_ref().unwrap()));
2561 let ns_id
= derive_id(format
!("{}.{}.{}.{}",
2562 variant
.name
.as_ref().unwrap(),
2563 ItemType
::Variant
.name_space(),
2564 field
.name
.as_ref().unwrap(),
2565 ItemType
::StructField
.name_space()));
2566 write
!(w
, "<tr><td \
2568 <span id='{ns_id}' class='invisible'>\
2569 <code>{f}: {t}</code></span></td><td>",
2572 f
= field
.name
.as_ref().unwrap(),
2574 document(w
, cx
, field
)?
;
2575 write
!(w
, "</td></tr>")?
;
2578 write
!(w
, "</table></span>")?
;
2580 render_stability_since(w
, variant
, it
)?
;
2583 render_assoc_items(w
, cx
, it
, it
.def_id
, AssocItemRender
::All
)?
;
2587 fn render_attribute(attr
: &ast
::MetaItem
) -> Option
<String
> {
2588 let name
= attr
.name();
2591 Some(format
!("{}", name
))
2592 } else if let Some(v
) = attr
.value_str() {
2593 Some(format
!("{} = {:?}", name
, &v
.as_str()[..]))
2594 } else if let Some(values
) = attr
.meta_item_list() {
2595 let display
: Vec
<_
> = values
.iter().filter_map(|attr
| {
2596 attr
.meta_item().and_then(|mi
| render_attribute(mi
))
2599 if display
.len() > 0 {
2600 Some(format
!("{}({})", name
, display
.join(", ")))
2609 const ATTRIBUTE_WHITELIST
: &'
static [&'
static str] = &[
2616 "unsafe_destructor_blind_to_params"
2619 fn render_attributes(w
: &mut fmt
::Formatter
, it
: &clean
::Item
) -> fmt
::Result
{
2620 let mut attrs
= String
::new();
2622 for attr
in &it
.attrs
.other_attrs
{
2623 let name
= attr
.name();
2624 if !ATTRIBUTE_WHITELIST
.contains(&&name
.as_str()[..]) {
2627 if let Some(s
) = render_attribute(attr
.meta()) {
2628 attrs
.push_str(&format
!("#[{}]\n", s
));
2631 if attrs
.len() > 0 {
2632 write
!(w
, "<div class=\"docblock attributes\">{}</div>", &attrs
)?
;
2637 fn render_struct(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2638 g
: Option
<&clean
::Generics
>,
2639 ty
: doctree
::StructType
,
2640 fields
: &[clean
::Item
],
2642 structhead
: bool
) -> fmt
::Result
{
2643 let mut plain
= String
::new();
2645 VisSpace(&it
.visibility
),
2646 if structhead {"struct "}
else {""}
,
2647 it
.name
.as_ref().unwrap())?
;
2648 plain
.push_str(&format
!("{}{}{}",
2649 VisSpace(&it
.visibility
),
2650 if structhead {"struct "}
else {""}
,
2651 it
.name
.as_ref().unwrap()));
2652 if let Some(g
) = g
{
2653 plain
.push_str(&format
!("{:#}", g
));
2658 if let Some(g
) = g
{
2659 write
!(w
, "{}", WhereClause(g
, plain
.len() + 1))?
2661 let mut has_visible_fields
= false;
2663 for field
in fields
{
2664 if let clean
::StructFieldItem(ref ty
) = field
.inner
{
2665 write
!(w
, "\n{} {}{}: {},",
2667 VisSpace(&field
.visibility
),
2668 field
.name
.as_ref().unwrap(),
2670 has_visible_fields
= true;
2674 if has_visible_fields
{
2675 if it
.has_stripped_fields().unwrap() {
2676 write
!(w
, "\n{} // some fields omitted", tab
)?
;
2678 write
!(w
, "\n{}", tab
)?
;
2679 } else if it
.has_stripped_fields().unwrap() {
2680 // If there are no visible fields we can just display
2681 // `{ /* fields omitted */ }` to save space.
2682 write
!(w
, " /* fields omitted */ ")?
;
2688 plain
.push_str("(");
2689 for (i
, field
) in fields
.iter().enumerate() {
2692 plain
.push_str(", ");
2695 clean
::StrippedItem(box clean
::StructFieldItem(..)) => {
2696 plain
.push_str("_");
2699 clean
::StructFieldItem(ref ty
) => {
2700 plain
.push_str(&format
!("{}{:#}", VisSpace(&field
.visibility
), *ty
));
2701 write
!(w
, "{}{}", VisSpace(&field
.visibility
), *ty
)?
2707 plain
.push_str(")");
2708 if let Some(g
) = g
{
2709 write
!(w
, "{}", WhereClause(g
, plain
.len() + 1))?
2714 // Needed for PhantomData.
2715 if let Some(g
) = g
{
2716 write
!(w
, "{}", WhereClause(g
, plain
.len() + 1))?
2724 fn render_union(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2725 g
: Option
<&clean
::Generics
>,
2726 fields
: &[clean
::Item
],
2728 structhead
: bool
) -> fmt
::Result
{
2729 let mut plain
= String
::new();
2731 VisSpace(&it
.visibility
),
2732 if structhead {"union "}
else {""}
,
2733 it
.name
.as_ref().unwrap())?
;
2734 plain
.push_str(&format
!("{}{}{}",
2735 VisSpace(&it
.visibility
),
2736 if structhead {"union "}
else {""}
,
2737 it
.name
.as_ref().unwrap()));
2738 if let Some(g
) = g
{
2739 write
!(w
, "{}", g
)?
;
2740 plain
.push_str(&format
!("{:#}", g
));
2741 write
!(w
, "{}", WhereClause(g
, plain
.len() + 1))?
;
2744 write
!(w
, " {{\n{}", tab
)?
;
2745 for field
in fields
{
2746 if let clean
::StructFieldItem(ref ty
) = field
.inner
{
2747 write
!(w
, " {}{}: {},\n{}",
2748 VisSpace(&field
.visibility
),
2749 field
.name
.as_ref().unwrap(),
2755 if it
.has_stripped_fields().unwrap() {
2756 write
!(w
, " // some fields omitted\n{}", tab
)?
;
2762 #[derive(Copy, Clone)]
2763 enum AssocItemLink
<'a
> {
2764 Anchor(Option
<&'a
str>),
2765 GotoSource(DefId
, &'a FxHashSet
<String
>),
2768 impl<'a
> AssocItemLink
<'a
> {
2769 fn anchor(&self, id
: &'a String
) -> Self {
2771 AssocItemLink
::Anchor(_
) => { AssocItemLink::Anchor(Some(&id)) }
,
2772 ref other
=> *other
,
2777 enum AssocItemRender
<'a
> {
2779 DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type, deref_mut_: bool }
2782 #[derive(Copy, Clone, PartialEq)]
2785 ForDeref { mut_: bool }
,
2788 fn render_assoc_items(w
: &mut fmt
::Formatter
,
2790 containing_item
: &clean
::Item
,
2792 what
: AssocItemRender
) -> fmt
::Result
{
2794 let v
= match c
.impls
.get(&it
) {
2796 None
=> return Ok(()),
2798 let (non_trait
, traits
): (Vec
<_
>, _
) = v
.iter().partition(|i
| {
2799 i
.inner_impl().trait_
.is_none()
2801 if !non_trait
.is_empty() {
2802 let render_mode
= match what
{
2803 AssocItemRender
::All
=> {
2804 write
!(w
, "<h2 id='methods'>Methods</h2>")?
;
2807 AssocItemRender
::DerefFor { trait_, type_, deref_mut_ }
=> {
2808 write
!(w
, "<h2 id='deref-methods'>Methods from \
2809 {}<Target={}></h2>", trait_
, type_
)?
;
2810 RenderMode
::ForDeref { mut_: deref_mut_ }
2813 for i
in &non_trait
{
2814 render_impl(w
, cx
, i
, AssocItemLink
::Anchor(None
), render_mode
,
2815 containing_item
.stable_since())?
;
2818 if let AssocItemRender
::DerefFor { .. }
= what
{
2821 if !traits
.is_empty() {
2822 let deref_impl
= traits
.iter().find(|t
| {
2823 t
.inner_impl().trait_
.def_id() == c
.deref_trait_did
2825 if let Some(impl_
) = deref_impl
{
2826 let has_deref_mut
= traits
.iter().find(|t
| {
2827 t
.inner_impl().trait_
.def_id() == c
.deref_mut_trait_did
2829 render_deref_methods(w
, cx
, impl_
, containing_item
, has_deref_mut
)?
;
2831 write
!(w
, "<h2 id='implementations'>Trait \
2832 Implementations</h2>")?
;
2834 let did
= i
.trait_did().unwrap();
2835 let assoc_link
= AssocItemLink
::GotoSource(did
, &i
.inner_impl().provided_trait_methods
);
2836 render_impl(w
, cx
, i
, assoc_link
,
2837 RenderMode
::Normal
, containing_item
.stable_since())?
;
2843 fn render_deref_methods(w
: &mut fmt
::Formatter
, cx
: &Context
, impl_
: &Impl
,
2844 container_item
: &clean
::Item
, deref_mut
: bool
) -> fmt
::Result
{
2845 let deref_type
= impl_
.inner_impl().trait_
.as_ref().unwrap();
2846 let target
= impl_
.inner_impl().items
.iter().filter_map(|item
| {
2848 clean
::TypedefItem(ref t
, true) => Some(&t
.type_
),
2851 }).next().expect("Expected associated type binding");
2852 let what
= AssocItemRender
::DerefFor
{ trait_
: deref_type
, type_
: target
,
2853 deref_mut_
: deref_mut
};
2854 if let Some(did
) = target
.def_id() {
2855 render_assoc_items(w
, cx
, container_item
, did
, what
)
2857 if let Some(prim
) = target
.primitive_type() {
2858 if let Some(&did
) = cache().primitive_locations
.get(&prim
) {
2859 render_assoc_items(w
, cx
, container_item
, did
, what
)?
;
2866 fn render_impl(w
: &mut fmt
::Formatter
, cx
: &Context
, i
: &Impl
, link
: AssocItemLink
,
2867 render_mode
: RenderMode
, outer_version
: Option
<&str>) -> fmt
::Result
{
2868 if render_mode
== RenderMode
::Normal
{
2869 write
!(w
, "<h3 class='impl'><span class='in-band'><code>{}</code>", i
.inner_impl())?
;
2870 write
!(w
, "</span><span class='out-of-band'>")?
;
2871 let since
= i
.impl_item
.stability
.as_ref().map(|s
| &s
.since
[..]);
2872 if let Some(l
) = (Item { item: &i.impl_item, cx: cx }
).src_href() {
2873 write
!(w
, "<div class='ghost'></div>")?
;
2874 render_stability_since_raw(w
, since
, outer_version
)?
;
2875 write
!(w
, "<a class='srclink' href='{}' title='{}'>[src]</a>",
2876 l
, "goto source code")?
;
2878 render_stability_since_raw(w
, since
, outer_version
)?
;
2880 write
!(w
, "</span>")?
;
2881 write
!(w
, "</h3>\n")?
;
2882 if let Some(ref dox
) = i
.impl_item
.doc_value() {
2883 write
!(w
, "<div class='docblock'>{}</div>", Markdown(dox
))?
;
2887 fn doc_impl_item(w
: &mut fmt
::Formatter
, cx
: &Context
, item
: &clean
::Item
,
2888 link
: AssocItemLink
, render_mode
: RenderMode
,
2889 is_default_item
: bool
, outer_version
: Option
<&str>,
2890 trait_
: Option
<&clean
::Trait
>) -> fmt
::Result
{
2891 let item_type
= item
.type_();
2892 let name
= item
.name
.as_ref().unwrap();
2894 let render_method_item
: bool
= match render_mode
{
2895 RenderMode
::Normal
=> true,
2896 RenderMode
::ForDeref { mut_: deref_mut_ }
=> {
2897 let self_type_opt
= match item
.inner
{
2898 clean
::MethodItem(ref method
) => method
.decl
.self_type(),
2899 clean
::TyMethodItem(ref method
) => method
.decl
.self_type(),
2903 if let Some(self_ty
) = self_type_opt
{
2904 let by_mut_ref
= match self_ty
{
2905 SelfTy
::SelfBorrowed(_lifetime
, mutability
) => {
2906 mutability
== Mutability
::Mutable
2908 SelfTy
::SelfExplicit(clean
::BorrowedRef { mutability, .. }
) => {
2909 mutability
== Mutability
::Mutable
2914 deref_mut_
|| !by_mut_ref
2922 clean
::MethodItem(..) | clean
::TyMethodItem(..) => {
2923 // Only render when the method is not static or we allow static methods
2924 if render_method_item
{
2925 let id
= derive_id(format
!("{}.{}", item_type
, name
));
2926 let ns_id
= derive_id(format
!("{}.{}", name
, item_type
.name_space()));
2927 write
!(w
, "<h4 id='{}' class=\"{}\">", id
, item_type
)?
;
2928 write
!(w
, "<span id='{}' class='invisible'>", ns_id
)?
;
2929 write
!(w
, "<code>")?
;
2930 render_assoc_item(w
, item
, link
.anchor(&id
), ItemType
::Impl
)?
;
2931 write
!(w
, "</code>")?
;
2932 render_stability_since_raw(w
, item
.stable_since(), outer_version
)?
;
2933 write
!(w
, "</span></h4>\n")?
;
2936 clean
::TypedefItem(ref tydef
, _
) => {
2937 let id
= derive_id(format
!("{}.{}", ItemType
::AssociatedType
, name
));
2938 let ns_id
= derive_id(format
!("{}.{}", name
, item_type
.name_space()));
2939 write
!(w
, "<h4 id='{}' class=\"{}\">", id
, item_type
)?
;
2940 write
!(w
, "<span id='{}' class='invisible'><code>", ns_id
)?
;
2941 assoc_type(w
, item
, &Vec
::new(), Some(&tydef
.type_
), link
.anchor(&id
))?
;
2942 write
!(w
, "</code></span></h4>\n")?
;
2944 clean
::AssociatedConstItem(ref ty
, ref default) => {
2945 let id
= derive_id(format
!("{}.{}", item_type
, name
));
2946 let ns_id
= derive_id(format
!("{}.{}", name
, item_type
.name_space()));
2947 write
!(w
, "<h4 id='{}' class=\"{}\">", id
, item_type
)?
;
2948 write
!(w
, "<span id='{}' class='invisible'><code>", ns_id
)?
;
2949 assoc_const(w
, item
, ty
, default.as_ref(), link
.anchor(&id
))?
;
2950 write
!(w
, "</code></span></h4>\n")?
;
2952 clean
::ConstantItem(ref c
) => {
2953 let id
= derive_id(format
!("{}.{}", item_type
, name
));
2954 let ns_id
= derive_id(format
!("{}.{}", name
, item_type
.name_space()));
2955 write
!(w
, "<h4 id='{}' class=\"{}\">", id
, item_type
)?
;
2956 write
!(w
, "<span id='{}' class='invisible'><code>", ns_id
)?
;
2957 assoc_const(w
, item
, &c
.type_
, Some(&c
.expr
), link
.anchor(&id
))?
;
2958 write
!(w
, "</code></span></h4>\n")?
;
2960 clean
::AssociatedTypeItem(ref bounds
, ref default) => {
2961 let id
= derive_id(format
!("{}.{}", item_type
, name
));
2962 let ns_id
= derive_id(format
!("{}.{}", name
, item_type
.name_space()));
2963 write
!(w
, "<h4 id='{}' class=\"{}\">", id
, item_type
)?
;
2964 write
!(w
, "<span id='{}' class='invisible'><code>", ns_id
)?
;
2965 assoc_type(w
, item
, bounds
, default.as_ref(), link
.anchor(&id
))?
;
2966 write
!(w
, "</code></span></h4>\n")?
;
2968 clean
::StrippedItem(..) => return Ok(()),
2969 _
=> panic
!("can't make docs for trait item with name {:?}", item
.name
)
2972 if render_method_item
|| render_mode
== RenderMode
::Normal
{
2973 if !is_default_item
{
2974 if let Some(t
) = trait_
{
2975 // The trait item may have been stripped so we might not
2976 // find any documentation or stability for it.
2977 if let Some(it
) = t
.items
.iter().find(|i
| i
.name
== item
.name
) {
2978 // We need the stability of the item from the trait
2979 // because impls can't have a stability.
2980 document_stability(w
, cx
, it
)?
;
2981 if get_doc_value(item
).is_some() {
2982 document_full(w
, item
)?
;
2984 // In case the item isn't documented,
2985 // provide short documentation from the trait.
2986 document_short(w
, it
, link
)?
;
2990 document(w
, cx
, item
)?
;
2993 document_stability(w
, cx
, item
)?
;
2994 document_short(w
, item
, link
)?
;
3000 let traits
= &cache().traits
;
3001 let trait_
= i
.trait_did().and_then(|did
| traits
.get(&did
));
3003 write
!(w
, "<div class='impl-items'>")?
;
3004 for trait_item
in &i
.inner_impl().items
{
3005 doc_impl_item(w
, cx
, trait_item
, link
, render_mode
,
3006 false, outer_version
, trait_
)?
;
3009 fn render_default_items(w
: &mut fmt
::Formatter
,
3013 render_mode
: RenderMode
,
3014 outer_version
: Option
<&str>) -> fmt
::Result
{
3015 for trait_item
in &t
.items
{
3016 let n
= trait_item
.name
.clone();
3017 if i
.items
.iter().find(|m
| m
.name
== n
).is_some() {
3020 let did
= i
.trait_
.as_ref().unwrap().def_id().unwrap();
3021 let assoc_link
= AssocItemLink
::GotoSource(did
, &i
.provided_trait_methods
);
3023 doc_impl_item(w
, cx
, trait_item
, assoc_link
, render_mode
, true,
3024 outer_version
, None
)?
;
3029 // If we've implemented a trait, then also emit documentation for all
3030 // default items which weren't overridden in the implementation block.
3031 if let Some(t
) = trait_
{
3032 render_default_items(w
, cx
, t
, &i
.inner_impl(), render_mode
, outer_version
)?
;
3034 write
!(w
, "</div>")?
;
3038 fn item_typedef(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
3039 t
: &clean
::Typedef
) -> fmt
::Result
{
3040 let indent
= format
!("type {}{:#} ", it
.name
.as_ref().unwrap(), t
.generics
).len();
3041 write
!(w
, "<pre class='rust typedef'>")?
;
3042 render_attributes(w
, it
)?
;
3043 write
!(w
, "type {}{}{where_clause} = {type_};</pre>",
3044 it
.name
.as_ref().unwrap(),
3046 where_clause
= WhereClause(&t
.generics
, indent
),
3052 impl<'a
> fmt
::Display
for Sidebar
<'a
> {
3053 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
3056 let parentlen
= cx
.current
.len() - if it
.is_mod() {1}
else {0}
;
3058 // The sidebar is designed to display sibling functions, modules and
3059 // other miscellaneous information. since there are lots of sibling
3060 // items (and that causes quadratic growth in large modules),
3061 // we refactor common parts into a shared JavaScript file per module.
3062 // still, we don't move everything into JS because we want to preserve
3063 // as much HTML as possible in order to allow non-JS-enabled browsers
3064 // to navigate the documentation (though slightly inefficiently).
3066 write
!(fmt
, "<p class='location'>")?
;
3067 for (i
, name
) in cx
.current
.iter().take(parentlen
).enumerate() {
3069 write
!(fmt
, "::<wbr>")?
;
3071 write
!(fmt
, "<a href='{}index.html'>{}</a>",
3072 &cx
.root_path()[..(cx
.current
.len() - i
- 1) * 3],
3075 write
!(fmt
, "</p>")?
;
3077 // Sidebar refers to the enclosing module, not this module.
3078 let relpath
= if it
.is_mod() { "../" }
else { "" }
;
3080 "<script>window.sidebarCurrent = {{\
3085 name
= it
.name
.as_ref().map(|x
| &x
[..]).unwrap_or(""),
3086 ty
= it
.type_().css_class(),
3089 // There is no sidebar-items.js beyond the crate root path
3090 // FIXME maybe dynamic crate loading can be merged here
3092 write
!(fmt
, "<script defer src=\"{path}sidebar-items.js\"></script>",
3100 impl<'a
> fmt
::Display
for Source
<'a
> {
3101 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
3102 let Source(s
) = *self;
3103 let lines
= s
.lines().count();
3105 let mut tmp
= lines
;
3110 write
!(fmt
, "<pre class=\"line-numbers\">")?
;
3111 for i
in 1..lines
+ 1 {
3112 write
!(fmt
, "<span id=\"{0}\">{0:1$}</span>\n", i
, cols
)?
;
3114 write
!(fmt
, "</pre>")?
;
3115 write
!(fmt
, "{}", highlight
::render_with_highlighting(s
, None
, None
, None
))?
;
3120 fn item_macro(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
3121 t
: &clean
::Macro
) -> fmt
::Result
{
3122 w
.write_str(&highlight
::render_with_highlighting(&t
.source
,
3129 fn item_primitive(w
: &mut fmt
::Formatter
, cx
: &Context
,
3131 _p
: &clean
::PrimitiveType
) -> fmt
::Result
{
3132 document(w
, cx
, it
)?
;
3133 render_assoc_items(w
, cx
, it
, it
.def_id
, AssocItemRender
::All
)
3136 const BASIC_KEYWORDS
: &'
static str = "rust, rustlang, rust-lang";
3138 fn make_item_keywords(it
: &clean
::Item
) -> String
{
3139 format
!("{}, {}", BASIC_KEYWORDS
, it
.name
.as_ref().unwrap())
3142 fn get_index_search_type(item
: &clean
::Item
) -> Option
<IndexItemFunctionType
> {
3143 let decl
= match item
.inner
{
3144 clean
::FunctionItem(ref f
) => &f
.decl
,
3145 clean
::MethodItem(ref m
) => &m
.decl
,
3146 clean
::TyMethodItem(ref m
) => &m
.decl
,
3150 let inputs
= decl
.inputs
.values
.iter().map(|arg
| get_index_type(&arg
.type_
)).collect();
3151 let output
= match decl
.output
{
3152 clean
::FunctionRetTy
::Return(ref return_type
) => Some(get_index_type(return_type
)),
3156 Some(IndexItemFunctionType { inputs: inputs, output: output }
)
3159 fn get_index_type(clean_type
: &clean
::Type
) -> Type
{
3160 Type { name: get_index_type_name(clean_type).map(|s| s.to_ascii_lowercase()) }
3163 fn get_index_type_name(clean_type
: &clean
::Type
) -> Option
<String
> {
3165 clean
::ResolvedPath { ref path, .. }
=> {
3166 let segments
= &path
.segments
;
3167 Some(segments
[segments
.len() - 1].name
.clone())
3169 clean
::Generic(ref s
) => Some(s
.clone()),
3170 clean
::Primitive(ref p
) => Some(format
!("{:?}", p
)),
3171 clean
::BorrowedRef { ref type_, .. }
=> get_index_type_name(type_
),
3172 // FIXME: add all from clean::Type.
3177 pub fn cache() -> Arc
<Cache
> {
3178 CACHE_KEY
.with(|c
| c
.borrow().clone())
3183 fn test_unique_id() {
3184 let input
= ["foo", "examples", "examples", "method.into_iter","examples",
3185 "method.into_iter", "foo", "main", "search", "methods",
3186 "examples", "method.into_iter", "assoc_type.Item", "assoc_type.Item"];
3187 let expected
= ["foo", "examples", "examples-1", "method.into_iter", "examples-2",
3188 "method.into_iter-1", "foo-1", "main-1", "search-1", "methods-1",
3189 "examples-3", "method.into_iter-2", "assoc_type.Item", "assoc_type.Item-1"];
3192 let actual
: Vec
<String
> = input
.iter().map(|s
| derive_id(s
.to_string())).collect();
3193 assert_eq
!(&actual
[..], expected
);