1 // Copyright 2013-2014 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
::OwnedAsciiExt
;
38 use std
::cell
::RefCell
;
39 use std
::cmp
::Ordering
;
40 use std
::collections
::{BTreeMap, HashMap, HashSet}
;
41 use std
::default::Default
;
43 use std
::fs
::{self, File}
;
44 use std
::io
::prelude
::*;
45 use std
::io
::{self, BufWriter, BufReader}
;
46 use std
::iter
::repeat
;
48 use std
::path
::{PathBuf, Path}
;
52 use externalfiles
::ExternalHtml
;
54 use serialize
::json
::{self, ToJson}
;
55 use syntax
::{abi, ast, ast_util, attr}
;
56 use rustc
::util
::nodemap
::NodeSet
;
58 use clean
::{self, SelfTy}
;
61 use html
::escape
::Escape
;
62 use html
::format
::{ConstnessSpace}
;
63 use html
::format
::{TyParamBounds, WhereClause, href, AbiSpace}
;
64 use html
::format
::{VisSpace, Method, UnsafetySpace, MutableSpace}
;
65 use html
::item_type
::ItemType
;
66 use html
::markdown
::{self, Markdown}
;
67 use html
::{highlight, layout}
;
69 /// A pair of name and its optional document.
70 pub type NameDoc
= (String
, Option
<String
>);
72 /// Major driving force in all rustdoc rendering. This contains information
73 /// about where in the tree-like hierarchy rendering is occurring and controls
74 /// how the current page is being rendered.
76 /// It is intended that this context is a lightweight object which can be fairly
77 /// easily cloned because it is cloned per work-job (about once per item in the
81 /// Current hierarchy of components leading down to what's currently being
83 pub current
: Vec
<String
>,
84 /// String representation of how to get back to the root path of the 'doc/'
85 /// folder in terms of a relative URL.
86 pub root_path
: String
,
87 /// The path to the crate root source minus the file name.
88 /// Used for simplifying paths to the highlighted source code files.
89 pub src_root
: PathBuf
,
90 /// The current destination folder of where HTML artifacts should be placed.
91 /// This changes as the context descends into the module hierarchy.
93 /// This describes the layout of each page, and is not modified after
94 /// creation of the context (contains info like the favicon and added html).
95 pub layout
: layout
::Layout
,
96 /// This flag indicates whether [src] links should be generated or not. If
97 /// the source files are present in the html rendering, then this will be
99 pub include_sources
: bool
,
100 /// A flag, which when turned off, will render pages which redirect to the
101 /// real location of an item. This is used to allow external links to
102 /// publicly reused items to redirect to the right location.
103 pub render_redirect_pages
: bool
,
104 /// All the passes that were run on this crate.
105 pub passes
: HashSet
<String
>,
108 /// Indicates where an external crate can be found.
109 pub enum ExternalLocation
{
110 /// Remote URL root of the external crate
112 /// This external crate can be found in the local doc/ folder
114 /// The external crate could not be found.
118 /// Metadata about an implementor of a trait.
119 pub struct Implementor
{
120 pub def_id
: ast
::DefId
,
121 pub generics
: clean
::Generics
,
122 pub trait_
: clean
::Type
,
123 pub for_
: clean
::Type
,
124 pub stability
: Option
<clean
::Stability
>,
125 pub polarity
: Option
<clean
::ImplPolarity
>,
128 /// Metadata about implementations for a type.
131 pub impl_
: clean
::Impl
,
132 pub dox
: Option
<String
>,
133 pub stability
: Option
<clean
::Stability
>,
137 fn trait_did(&self) -> Option
<ast
::DefId
> {
138 self.impl_
.trait_
.as_ref().and_then(|tr
| {
139 if let clean
::ResolvedPath { did, .. }
= *tr {Some(did)}
else {None}
144 /// This cache is used to store information about the `clean::Crate` being
145 /// rendered in order to provide more useful documentation. This contains
146 /// information like all implementors of a trait, all traits a type implements,
147 /// documentation for all known traits, etc.
149 /// This structure purposefully does not implement `Clone` because it's intended
150 /// to be a fairly large and expensive structure to clone. Instead this adheres
151 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
152 /// rendering threads.
155 /// Mapping of typaram ids to the name of the type parameter. This is used
156 /// when pretty-printing a type (so pretty printing doesn't have to
157 /// painfully maintain a context like this)
158 pub typarams
: HashMap
<ast
::DefId
, String
>,
160 /// Maps a type id to all known implementations for that type. This is only
161 /// recognized for intra-crate `ResolvedPath` types, and is used to print
162 /// out extra documentation on the page of an enum/struct.
164 /// The values of the map are a list of implementations and documentation
165 /// found on that implementation.
166 pub impls
: HashMap
<ast
::DefId
, Vec
<Impl
>>,
168 /// Maintains a mapping of local crate node ids to the fully qualified name
169 /// and "short type description" of that node. This is used when generating
170 /// URLs when a type is being linked to. External paths are not located in
171 /// this map because the `External` type itself has all the information
173 pub paths
: HashMap
<ast
::DefId
, (Vec
<String
>, ItemType
)>,
175 /// Similar to `paths`, but only holds external paths. This is only used for
176 /// generating explicit hyperlinks to other crates.
177 pub external_paths
: HashMap
<ast
::DefId
, Vec
<String
>>,
179 /// This map contains information about all known traits of this crate.
180 /// Implementations of a crate should inherit the documentation of the
181 /// parent trait if no extra documentation is specified, and default methods
182 /// should show up in documentation about trait implementations.
183 pub traits
: HashMap
<ast
::DefId
, clean
::Trait
>,
185 /// When rendering traits, it's often useful to be able to list all
186 /// implementors of the trait, and this mapping is exactly, that: a mapping
187 /// of trait ids to the list of known implementors of the trait
188 pub implementors
: HashMap
<ast
::DefId
, Vec
<Implementor
>>,
190 /// Cache of where external crate documentation can be found.
191 pub extern_locations
: HashMap
<ast
::CrateNum
, (String
, ExternalLocation
)>,
193 /// Cache of where documentation for primitives can be found.
194 pub primitive_locations
: HashMap
<clean
::PrimitiveType
, ast
::CrateNum
>,
196 /// Set of definitions which have been inlined from external crates.
197 pub inlined
: HashSet
<ast
::DefId
>,
199 // Private fields only used when initially crawling a crate to build a cache
202 parent_stack
: Vec
<ast
::DefId
>,
203 search_index
: Vec
<IndexItem
>,
206 public_items
: NodeSet
,
207 deref_trait_did
: Option
<ast
::DefId
>,
209 // In rare case where a structure is defined in one module but implemented
210 // in another, if the implementing module is parsed before defining module,
211 // then the fully qualified name of the structure isn't presented in `paths`
212 // yet when its implementation methods are being indexed. Caches such methods
213 // and their parent id here and indexes them at the end of crate parsing.
214 orphan_methods
: Vec
<(ast
::NodeId
, clean
::Item
)>,
217 /// Helper struct to render all source code to HTML pages
218 struct SourceCollector
<'a
> {
221 /// Processed source-file paths
222 seen
: HashSet
<String
>,
223 /// Root destination to place all HTML output into
227 /// Wrapper struct to render the source code of a file. This will do things like
228 /// adding line numbers to the left-hand side.
229 struct Source
<'a
>(&'a
str);
231 // Helper structs for rendering items/sidebars and carrying along contextual
234 #[derive(Copy, Clone)]
237 item
: &'a clean
::Item
,
240 struct Sidebar
<'a
> { cx: &'a Context, item: &'a clean::Item, }
242 /// Struct representing one entry in the JS search index. These are all emitted
243 /// by hand to a large JS file at the end of cache-creation.
249 parent
: Option
<ast
::DefId
>,
250 search_type
: Option
<IndexItemFunctionType
>,
253 /// A type used for the search index.
255 name
: Option
<String
>,
258 impl fmt
::Display
for Type
{
259 /// Formats type as {name: $name}.
260 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
261 // Wrapping struct fmt should never call us when self.name is None,
262 // but just to be safe we write `null` in that case.
264 Some(ref n
) => write
!(f
, "{{\"name\":\"{}\"}}", n
),
265 None
=> write
!(f
, "null")
270 /// Full type of functions/methods in the search index.
271 struct IndexItemFunctionType
{
276 impl fmt
::Display
for IndexItemFunctionType
{
277 /// Formats a full fn type as a JSON {inputs: [Type], outputs: Type/null}.
278 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
279 // If we couldn't figure out a type, just write `null`.
280 if self.inputs
.iter().any(|ref i
| i
.name
.is_none()) ||
281 (self.output
.is_some() && self.output
.as_ref().unwrap().name
.is_none()) {
282 return write
!(f
, "null")
285 let inputs
: Vec
<String
> = self.inputs
.iter().map(|ref t
| {
288 try
!(write
!(f
, "{{\"inputs\":[{}],\"output\":", inputs
.connect(",")));
291 Some(ref t
) => try
!(write
!(f
, "{}", t
)),
292 None
=> try
!(write
!(f
, "null"))
295 Ok(try
!(write
!(f
, "}}")))
299 // TLS keys used to carry information around during rendering.
301 thread_local
!(static CACHE_KEY
: RefCell
<Arc
<Cache
>> = Default
::default());
302 thread_local
!(pub static CURRENT_LOCATION_KEY
: RefCell
<Vec
<String
>> =
303 RefCell
::new(Vec
::new()));
305 /// Generates the documentation for `crate` into the directory `dst`
306 pub fn run(mut krate
: clean
::Crate
,
307 external_html
: &ExternalHtml
,
309 passes
: HashSet
<String
>) -> io
::Result
<()> {
310 let src_root
= match krate
.src
.parent() {
311 Some(p
) => p
.to_path_buf(),
312 None
=> PathBuf
::new(),
314 let mut cx
= Context
{
319 root_path
: String
::new(),
320 layout
: layout
::Layout
{
321 logo
: "".to_string(),
322 favicon
: "".to_string(),
323 external_html
: external_html
.clone(),
324 krate
: krate
.name
.clone(),
325 playground_url
: "".to_string(),
327 include_sources
: true,
328 render_redirect_pages
: false,
331 try
!(mkdir(&cx
.dst
));
333 // Crawl the crate attributes looking for attributes which control how we're
334 // going to emit HTML
335 let default: &[_
] = &[];
336 match krate
.module
.as_ref().map(|m
| m
.doc_list().unwrap_or(default)) {
340 clean
::NameValue(ref x
, ref s
)
341 if "html_favicon_url" == *x
=> {
342 cx
.layout
.favicon
= s
.to_string();
344 clean
::NameValue(ref x
, ref s
)
345 if "html_logo_url" == *x
=> {
346 cx
.layout
.logo
= s
.to_string();
348 clean
::NameValue(ref x
, ref s
)
349 if "html_playground_url" == *x
=> {
350 cx
.layout
.playground_url
= s
.to_string();
351 markdown
::PLAYGROUND_KRATE
.with(|slot
| {
352 if slot
.borrow().is_none() {
353 let name
= krate
.name
.clone();
354 *slot
.borrow_mut() = Some(Some(name
));
359 if "html_no_source" == *x
=> {
360 cx
.include_sources
= false;
369 // Crawl the crate to build various caches used for the output
370 let analysis
= ::ANALYSISKEY
.with(|a
| a
.clone());
371 let analysis
= analysis
.borrow();
372 let public_items
= analysis
.as_ref().map(|a
| a
.public_items
.clone());
373 let public_items
= public_items
.unwrap_or(NodeSet());
374 let paths
: HashMap
<ast
::DefId
, (Vec
<String
>, ItemType
)> =
375 analysis
.as_ref().map(|a
| {
376 let paths
= a
.external_paths
.borrow_mut().take().unwrap();
377 paths
.into_iter().map(|(k
, (v
, t
))| (k
, (v
, ItemType
::from_type_kind(t
)))).collect()
378 }).unwrap_or(HashMap
::new());
379 let mut cache
= Cache
{
380 impls
: HashMap
::new(),
381 external_paths
: paths
.iter().map(|(&k
, v
)| (k
, v
.0.clone()))
384 implementors
: HashMap
::new(),
386 parent_stack
: Vec
::new(),
387 search_index
: Vec
::new(),
388 extern_locations
: HashMap
::new(),
389 primitive_locations
: HashMap
::new(),
390 remove_priv
: cx
.passes
.contains("strip-private"),
392 public_items
: public_items
,
393 orphan_methods
: Vec
::new(),
394 traits
: mem
::replace(&mut krate
.external_traits
, HashMap
::new()),
395 deref_trait_did
: analysis
.as_ref().and_then(|a
| a
.deref_trait_did
),
396 typarams
: analysis
.as_ref().map(|a
| {
397 a
.external_typarams
.borrow_mut().take().unwrap()
398 }).unwrap_or(HashMap
::new()),
399 inlined
: analysis
.as_ref().map(|a
| {
400 a
.inlined
.borrow_mut().take().unwrap()
401 }).unwrap_or(HashSet
::new()),
404 // Cache where all our extern crates are located
405 for &(n
, ref e
) in &krate
.externs
{
406 cache
.extern_locations
.insert(n
, (e
.name
.clone(),
407 extern_location(e
, &cx
.dst
)));
408 let did
= ast
::DefId { krate: n, node: ast::CRATE_NODE_ID }
;
409 cache
.paths
.insert(did
, (vec
![e
.name
.to_string()], ItemType
::Module
));
412 // Cache where all known primitives have their documentation located.
414 // Favor linking to as local extern as possible, so iterate all crates in
415 // reverse topological order.
416 for &(n
, ref e
) in krate
.externs
.iter().rev() {
417 for &prim
in &e
.primitives
{
418 cache
.primitive_locations
.insert(prim
, n
);
421 for &prim
in &krate
.primitives
{
422 cache
.primitive_locations
.insert(prim
, ast
::LOCAL_CRATE
);
425 cache
.stack
.push(krate
.name
.clone());
426 krate
= cache
.fold_crate(krate
);
428 // Build our search index
429 let index
= try
!(build_index(&krate
, &mut cache
));
431 // Freeze the cache now that the index has been built. Put an Arc into TLS
432 // for future parallelization opportunities
433 let cache
= Arc
::new(cache
);
434 CACHE_KEY
.with(|v
| *v
.borrow_mut() = cache
.clone());
435 CURRENT_LOCATION_KEY
.with(|s
| s
.borrow_mut().clear());
437 try
!(write_shared(&cx
, &krate
, &*cache
, index
));
438 let krate
= try
!(render_sources(&mut cx
, krate
));
440 // And finally render the whole crate's documentation
444 fn build_index(krate
: &clean
::Crate
, cache
: &mut Cache
) -> io
::Result
<String
> {
445 // Build the search index from the collected metadata
446 let mut nodeid_to_pathid
= HashMap
::new();
447 let mut pathid_to_nodeid
= Vec
::new();
449 let Cache
{ ref mut search_index
,
451 ref mut paths
, .. } = *cache
;
453 // Attach all orphan methods to the type's definition if the type
454 // has since been learned.
455 for &(pid
, ref item
) in orphan_methods
{
456 let did
= ast_util
::local_def(pid
);
457 match paths
.get(&did
) {
458 Some(&(ref fqp
, _
)) => {
459 // Needed to determine `self` type.
460 let parent_basename
= Some(fqp
[fqp
.len() - 1].clone());
461 search_index
.push(IndexItem
{
463 name
: item
.name
.clone().unwrap(),
464 path
: fqp
[..fqp
.len() - 1].connect("::"),
465 desc
: shorter(item
.doc_value()),
467 search_type
: get_index_search_type(&item
, parent_basename
),
474 // Reduce `NodeId` in paths into smaller sequential numbers,
475 // and prune the paths that do not appear in the index.
476 for item
in search_index
.iter() {
479 if !nodeid_to_pathid
.contains_key(&nodeid
) {
480 let pathid
= pathid_to_nodeid
.len();
481 nodeid_to_pathid
.insert(nodeid
, pathid
);
482 pathid_to_nodeid
.push(nodeid
);
488 assert_eq
!(nodeid_to_pathid
.len(), pathid_to_nodeid
.len());
491 // Collect the index into a string
492 let mut w
= io
::Cursor
::new(Vec
::new());
493 try
!(write
!(&mut w
, r
#"searchIndex['{}'] = {{"items":["#, krate.name));
495 let mut lastpath
= "".to_string();
496 for (i
, item
) in cache
.search_index
.iter().enumerate() {
497 // Omit the path if it is same to that of the prior item.
499 if lastpath
== item
.path
{
502 lastpath
= item
.path
.to_string();
507 try
!(write
!(&mut w
, ","));
509 try
!(write
!(&mut w
, r
#"[{},"{}","{}",{}"#,
510 item
.ty
as usize, item
.name
, path
,
511 item
.desc
.to_json().to_string()));
514 let pathid
= *nodeid_to_pathid
.get(&nodeid
).unwrap();
515 try
!(write
!(&mut w
, ",{}", pathid
));
517 None
=> try
!(write
!(&mut w
, ",null"))
519 match item
.search_type
{
520 Some(ref t
) => try
!(write
!(&mut w
, ",{}", t
)),
521 None
=> try
!(write
!(&mut w
, ",null"))
523 try
!(write
!(&mut w
, "]"));
526 try
!(write
!(&mut w
, r
#"],"paths":["#));
528 for (i
, &did
) in pathid_to_nodeid
.iter().enumerate() {
529 let &(ref fqp
, short
) = cache
.paths
.get(&did
).unwrap();
531 try
!(write
!(&mut w
, ","));
533 try
!(write
!(&mut w
, r
#"[{},"{}"]"#,
534 short
as usize, *fqp
.last().unwrap()));
537 try
!(write
!(&mut w
, "]}};"));
539 Ok(String
::from_utf8(w
.into_inner()).unwrap())
542 fn write_shared(cx
: &Context
,
543 krate
: &clean
::Crate
,
545 search_index
: String
) -> io
::Result
<()> {
546 // Write out the shared files. Note that these are shared among all rustdoc
547 // docs placed in the output directory, so this needs to be a synchronized
548 // operation with respect to all other rustdocs running around.
549 try
!(mkdir(&cx
.dst
));
550 let _lock
= ::flock
::Lock
::new(&cx
.dst
.join(".lock"));
552 // Add all the static files. These may already exist, but we just
553 // overwrite them anyway to make sure that they're fresh and up-to-date.
554 try
!(write(cx
.dst
.join("jquery.js"),
555 include_bytes
!("static/jquery-2.1.0.min.js")));
556 try
!(write(cx
.dst
.join("main.js"), include_bytes
!("static/main.js")));
557 try
!(write(cx
.dst
.join("playpen.js"), include_bytes
!("static/playpen.js")));
558 try
!(write(cx
.dst
.join("main.css"), include_bytes
!("static/main.css")));
559 try
!(write(cx
.dst
.join("normalize.css"),
560 include_bytes
!("static/normalize.css")));
561 try
!(write(cx
.dst
.join("FiraSans-Regular.woff"),
562 include_bytes
!("static/FiraSans-Regular.woff")));
563 try
!(write(cx
.dst
.join("FiraSans-Medium.woff"),
564 include_bytes
!("static/FiraSans-Medium.woff")));
565 try
!(write(cx
.dst
.join("Heuristica-Italic.woff"),
566 include_bytes
!("static/Heuristica-Italic.woff")));
567 try
!(write(cx
.dst
.join("SourceSerifPro-Regular.woff"),
568 include_bytes
!("static/SourceSerifPro-Regular.woff")));
569 try
!(write(cx
.dst
.join("SourceSerifPro-Bold.woff"),
570 include_bytes
!("static/SourceSerifPro-Bold.woff")));
571 try
!(write(cx
.dst
.join("SourceCodePro-Regular.woff"),
572 include_bytes
!("static/SourceCodePro-Regular.woff")));
573 try
!(write(cx
.dst
.join("SourceCodePro-Semibold.woff"),
574 include_bytes
!("static/SourceCodePro-Semibold.woff")));
576 fn collect(path
: &Path
, krate
: &str,
577 key
: &str) -> io
::Result
<Vec
<String
>> {
578 let mut ret
= Vec
::new();
580 for line
in BufReader
::new(try
!(File
::open(path
))).lines() {
581 let line
= try
!(line
);
582 if !line
.starts_with(key
) {
585 if line
.starts_with(&format
!("{}['{}']", key
, krate
)) {
588 ret
.push(line
.to_string());
594 // Update the search index
595 let dst
= cx
.dst
.join("search-index.js");
596 let all_indexes
= try
!(collect(&dst
, &krate
.name
, "searchIndex"));
597 let mut w
= try
!(File
::create(&dst
));
598 try
!(writeln
!(&mut w
, "var searchIndex = {{}};"));
599 try
!(writeln
!(&mut w
, "{}", search_index
));
600 for index
in &all_indexes
{
601 try
!(writeln
!(&mut w
, "{}", *index
));
603 try
!(writeln
!(&mut w
, "initSearch(searchIndex);"));
605 // Update the list of all implementors for traits
606 let dst
= cx
.dst
.join("implementors");
608 for (&did
, imps
) in &cache
.implementors
{
609 // Private modules can leak through to this phase of rustdoc, which
610 // could contain implementations for otherwise private types. In some
611 // rare cases we could find an implementation for an item which wasn't
612 // indexed, so we just skip this step in that case.
614 // FIXME: this is a vague explanation for why this can't be a `get`, in
615 // theory it should be...
616 let &(ref remote_path
, remote_item_type
) = match cache
.paths
.get(&did
) {
621 let mut mydst
= dst
.clone();
622 for part
in &remote_path
[..remote_path
.len() - 1] {
626 mydst
.push(&format
!("{}.{}.js",
627 remote_item_type
.to_static_str(),
628 remote_path
[remote_path
.len() - 1]));
629 let all_implementors
= try
!(collect(&mydst
, &krate
.name
,
632 try
!(mkdir(mydst
.parent().unwrap()));
633 let mut f
= BufWriter
::new(try
!(File
::create(&mydst
)));
634 try
!(writeln
!(&mut f
, "(function() {{var implementors = {{}};"));
636 for implementor
in &all_implementors
{
637 try
!(write
!(&mut f
, "{}", *implementor
));
640 try
!(write
!(&mut f
, r
"implementors['{}'] = [", krate
.name
));
642 // If the trait and implementation are in the same crate, then
643 // there's no need to emit information about it (there's inlining
644 // going on). If they're in different crates then the crate defining
645 // the trait will be interested in our implementation.
646 if imp
.def_id
.krate
== did
.krate { continue }
647 try
!(write
!(&mut f
, r
#""impl{} {}{} for {}","#,
649 if imp
.polarity
== Some(clean
::ImplPolarity
::Negative
) { "!" }
else { "" }
,
650 imp
.trait_
, imp
.for_
));
652 try
!(writeln
!(&mut f
, r
"];"));
653 try
!(writeln
!(&mut f
, "{}", r
"
654 if (window.register_implementors) {
655 window.register_implementors(implementors);
657 window.pending_implementors = implementors;
660 try
!(writeln
!(&mut f
, r
"}})()"));
665 fn render_sources(cx
: &mut Context
,
666 krate
: clean
::Crate
) -> io
::Result
<clean
::Crate
> {
667 info
!("emitting source files");
668 let dst
= cx
.dst
.join("src");
670 let dst
= dst
.join(&krate
.name
);
672 let mut folder
= SourceCollector
{
674 seen
: HashSet
::new(),
677 // skip all invalid spans
678 folder
.seen
.insert("".to_string());
679 Ok(folder
.fold_crate(krate
))
682 /// Writes the entire contents of a string to a destination, not attempting to
683 /// catch any errors.
684 fn write(dst
: PathBuf
, contents
: &[u8]) -> io
::Result
<()> {
685 try
!(File
::create(&dst
)).write_all(contents
)
688 /// Makes a directory on the filesystem, failing the thread if an error occurs and
689 /// skipping if the directory already exists.
690 fn mkdir(path
: &Path
) -> io
::Result
<()> {
698 /// Returns a documentation-level item type from the item.
699 fn shortty(item
: &clean
::Item
) -> ItemType
{
700 ItemType
::from_item(item
)
703 /// Takes a path to a source file and cleans the path to it. This canonicalizes
704 /// things like ".." to components which preserve the "top down" hierarchy of a
705 /// static HTML tree. Each component in the cleaned path will be passed as an
706 /// argument to `f`. The very last component of the path (ie the file name) will
707 /// be passed to `f` if `keep_filename` is true, and ignored otherwise.
708 // FIXME (#9639): The closure should deal with &[u8] instead of &str
709 // FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths
710 fn clean_srcpath
<F
>(src_root
: &Path
, p
: &Path
, keep_filename
: bool
, mut f
: F
) where
713 // make it relative, if possible
714 let p
= p
.relative_from(src_root
).unwrap_or(p
);
716 let mut iter
= p
.iter().map(|x
| x
.to_str().unwrap()).peekable();
717 while let Some(c
) = iter
.next() {
718 if !keep_filename
&& iter
.peek().is_none() {
730 /// Attempts to find where an external crate is located, given that we're
731 /// rendering in to the specified source destination.
732 fn extern_location(e
: &clean
::ExternalCrate
, dst
: &Path
) -> ExternalLocation
{
733 // See if there's documentation generated into the local directory
734 let local_location
= dst
.join(&e
.name
);
735 if local_location
.is_dir() {
739 // Failing that, see if there's an attribute specifying where to find this
741 for attr
in &e
.attrs
{
743 clean
::List(ref x
, ref list
) if "doc" == *x
=> {
746 clean
::NameValue(ref x
, ref s
)
747 if "html_root_url" == *x
=> {
748 if s
.ends_with("/") {
749 return Remote(s
.to_string());
751 return Remote(format
!("{}/", s
));
761 // Well, at least we tried.
765 impl<'a
> DocFolder
for SourceCollector
<'a
> {
766 fn fold_item(&mut self, item
: clean
::Item
) -> Option
<clean
::Item
> {
767 // If we're including source files, and we haven't seen this file yet,
768 // then we need to render it out to the filesystem
769 if self.cx
.include_sources
&& !self.seen
.contains(&item
.source
.filename
) {
771 // If it turns out that we couldn't read this file, then we probably
772 // can't read any of the files (generating html output from json or
773 // something like that), so just don't include sources for the
774 // entire crate. The other option is maintaining this mapping on a
775 // per-file basis, but that's probably not worth it...
777 .include_sources
= match self.emit_source(&item
.source
.filename
) {
780 println
!("warning: source code was requested to be rendered, \
781 but processing `{}` had an error: {}",
782 item
.source
.filename
, e
);
783 println
!(" skipping rendering of source code");
787 self.seen
.insert(item
.source
.filename
.clone());
790 self.fold_item_recur(item
)
794 impl<'a
> SourceCollector
<'a
> {
795 /// Renders the given filename into its corresponding HTML source file.
796 fn emit_source(&mut self, filename
: &str) -> io
::Result
<()> {
797 let p
= PathBuf
::from(filename
);
799 // If we couldn't open this file, then just returns because it
800 // probably means that it's some standard library macro thing and we
801 // can't have the source to it anyway.
802 let mut contents
= Vec
::new();
803 match File
::open(&p
).and_then(|mut f
| f
.read_to_end(&mut contents
)) {
805 // macros from other libraries get special filenames which we can
807 Err(..) if filename
.starts_with("<") &&
808 filename
.ends_with("macros>") => return Ok(()),
809 Err(e
) => return Err(e
)
811 let contents
= str::from_utf8(&contents
).unwrap();
813 // Remove the utf-8 BOM if any
814 let contents
= if contents
.starts_with("\u{feff}") {
820 // Create the intermediate directories
821 let mut cur
= self.dst
.clone();
822 let mut root_path
= String
::from("../../");
823 clean_srcpath(&self.cx
.src_root
, &p
, false, |component
| {
825 mkdir(&cur
).unwrap();
826 root_path
.push_str("../");
829 let mut fname
= p
.file_name().expect("source has no filename")
832 cur
.push(&fname
[..]);
833 let mut w
= BufWriter
::new(try
!(File
::create(&cur
)));
835 let title
= format
!("{} -- source", cur
.file_name().unwrap()
837 let desc
= format
!("Source to the Rust file `{}`.", filename
);
838 let page
= layout
::Page
{
841 root_path
: &root_path
,
843 keywords
: get_basic_keywords(),
845 try
!(layout
::render(&mut w
, &self.cx
.layout
,
846 &page
, &(""), &Source(contents
)));
852 impl DocFolder
for Cache
{
853 fn fold_item(&mut self, item
: clean
::Item
) -> Option
<clean
::Item
> {
854 // If this is a private module, we don't want it in the search index.
855 let orig_privmod
= match item
.inner
{
856 clean
::ModuleItem(..) => {
857 let prev
= self.privmod
;
858 self.privmod
= prev
|| (self.remove_priv
&& item
.visibility
!= Some(ast
::Public
));
864 // Register any generics to their corresponding string. This is used
865 // when pretty-printing types
867 clean
::StructItem(ref s
) => self.generics(&s
.generics
),
868 clean
::EnumItem(ref e
) => self.generics(&e
.generics
),
869 clean
::FunctionItem(ref f
) => self.generics(&f
.generics
),
870 clean
::TypedefItem(ref t
, _
) => self.generics(&t
.generics
),
871 clean
::TraitItem(ref t
) => self.generics(&t
.generics
),
872 clean
::ImplItem(ref i
) => self.generics(&i
.generics
),
873 clean
::TyMethodItem(ref i
) => self.generics(&i
.generics
),
874 clean
::MethodItem(ref i
) => self.generics(&i
.generics
),
875 clean
::ForeignFunctionItem(ref f
) => self.generics(&f
.generics
),
879 // Propagate a trait methods' documentation to all implementors of the
881 if let clean
::TraitItem(ref t
) = item
.inner
{
882 self.traits
.insert(item
.def_id
, t
.clone());
885 // Collect all the implementors of traits.
886 if let clean
::ImplItem(ref i
) = item
.inner
{
888 Some(clean
::ResolvedPath{ did, .. }
) => {
889 self.implementors
.entry(did
).or_insert(vec
![]).push(Implementor
{
891 generics
: i
.generics
.clone(),
892 trait_
: i
.trait_
.as_ref().unwrap().clone(),
893 for_
: i
.for_
.clone(),
894 stability
: item
.stability
.clone(),
895 polarity
: i
.polarity
.clone(),
898 Some(..) | None
=> {}
902 // Index this method for searching later on
903 if let Some(ref s
) = item
.name
{
904 let (parent
, is_method
) = match item
.inner
{
905 clean
::AssociatedTypeItem(..) |
906 clean
::AssociatedConstItem(..) |
907 clean
::TyMethodItem(..) |
908 clean
::StructFieldItem(..) |
909 clean
::VariantItem(..) => {
910 ((Some(*self.parent_stack
.last().unwrap()),
911 Some(&self.stack
[..self.stack
.len() - 1])),
914 clean
::MethodItem(..) => {
915 if self.parent_stack
.is_empty() {
916 ((None
, None
), false)
918 let last
= self.parent_stack
.last().unwrap();
920 let path
= match self.paths
.get(&did
) {
921 Some(&(_
, ItemType
::Trait
)) =>
922 Some(&self.stack
[..self.stack
.len() - 1]),
923 // The current stack not necessarily has correlation
924 // for where the type was defined. On the other
925 // hand, `paths` always has the right
926 // information if present.
927 Some(&(ref fqp
, ItemType
::Struct
)) |
928 Some(&(ref fqp
, ItemType
::Enum
)) =>
929 Some(&fqp
[..fqp
.len() - 1]),
930 Some(..) => Some(&*self.stack
),
933 ((Some(*last
), path
), true)
936 clean
::TypedefItem(_
, true) => {
937 // skip associated types in impls
938 ((None
, None
), false)
940 _
=> ((None
, Some(&*self.stack
)), false)
942 let hidden_field
= match item
.inner
{
943 clean
::StructFieldItem(clean
::HiddenStructField
) => true,
948 (parent
, Some(path
)) if is_method
|| (!self.privmod
&& !hidden_field
) => {
949 // Needed to determine `self` type.
950 let parent_basename
= self.parent_stack
.first().and_then(|parent
| {
951 match self.paths
.get(parent
) {
952 Some(&(ref fqp
, _
)) => Some(fqp
[fqp
.len() - 1].clone()),
957 self.search_index
.push(IndexItem
{
960 path
: path
.connect("::").to_string(),
961 desc
: shorter(item
.doc_value()),
963 search_type
: get_index_search_type(&item
, parent_basename
),
966 (Some(parent
), None
) if is_method
|| (!self.privmod
&& !hidden_field
)=> {
967 if ast_util
::is_local(parent
) {
968 // We have a parent, but we don't know where they're
969 // defined yet. Wait for later to index this item.
970 self.orphan_methods
.push((parent
.node
, item
.clone()))
977 // Keep track of the fully qualified path for this item.
978 let pushed
= if item
.name
.is_some() {
979 let n
= item
.name
.as_ref().unwrap();
981 self.stack
.push(n
.to_string());
986 clean
::StructItem(..) | clean
::EnumItem(..) |
987 clean
::TypedefItem(..) | clean
::TraitItem(..) |
988 clean
::FunctionItem(..) | clean
::ModuleItem(..) |
989 clean
::ForeignFunctionItem(..) if !self.privmod
=> {
990 // Reexported items mean that the same id can show up twice
991 // in the rustdoc ast that we're looking at. We know,
992 // however, that a reexported item doesn't show up in the
993 // `public_items` map, so we can skip inserting into the
994 // paths map if there was already an entry present and we're
995 // not a public item.
996 let id
= item
.def_id
.node
;
997 if !self.paths
.contains_key(&item
.def_id
) ||
998 !ast_util
::is_local(item
.def_id
) ||
999 self.public_items
.contains(&id
) {
1000 self.paths
.insert(item
.def_id
,
1001 (self.stack
.clone(), shortty(&item
)));
1004 // link variants to their parent enum because pages aren't emitted
1006 clean
::VariantItem(..) if !self.privmod
=> {
1007 let mut stack
= self.stack
.clone();
1009 self.paths
.insert(item
.def_id
, (stack
, ItemType
::Enum
));
1012 clean
::PrimitiveItem(..) if item
.visibility
.is_some() => {
1013 self.paths
.insert(item
.def_id
, (self.stack
.clone(),
1020 // Maintain the parent stack
1021 let parent_pushed
= match item
.inner
{
1022 clean
::TraitItem(..) | clean
::EnumItem(..) | clean
::StructItem(..) => {
1023 self.parent_stack
.push(item
.def_id
);
1026 clean
::ImplItem(ref i
) => {
1028 clean
::ResolvedPath{ did, .. }
=> {
1029 self.parent_stack
.push(did
);
1033 match t
.primitive_type() {
1035 let did
= ast_util
::local_def(prim
.to_node_id());
1036 self.parent_stack
.push(did
);
1047 // Once we've recursively found all the generics, then hoard off all the
1048 // implementations elsewhere
1049 let ret
= match self.fold_item_recur(item
) {
1052 clean
::Item{ attrs, inner: clean::ImplItem(i), .. }
=> {
1053 // extract relevant documentation for this impl
1054 let dox
= match attrs
.into_iter().find(|a
| {
1056 clean
::NameValue(ref x
, _
)
1063 Some(clean
::NameValue(_
, dox
)) => Some(dox
),
1064 Some(..) | None
=> None
,
1067 // Figure out the id of this impl. This may map to a
1068 // primitive rather than always to a struct/enum.
1069 let did
= match i
.for_
{
1070 clean
::ResolvedPath { did, .. }
|
1071 clean
::BorrowedRef
{
1072 type_
: box clean
::ResolvedPath { did, .. }
, ..
1078 t
.primitive_type().and_then(|t
| {
1079 self.primitive_locations
.get(&t
).map(|n
| {
1080 let id
= t
.to_node_id();
1081 ast
::DefId { krate: *n, node: id }
1087 if let Some(did
) = did
{
1088 self.impls
.entry(did
).or_insert(vec
![]).push(Impl
{
1091 stability
: item
.stability
.clone(),
1104 if pushed { self.stack.pop().unwrap(); }
1105 if parent_pushed { self.parent_stack.pop().unwrap(); }
1106 self.privmod
= orig_privmod
;
1112 fn generics(&mut self, generics
: &clean
::Generics
) {
1113 for typ
in &generics
.type_params
{
1114 self.typarams
.insert(typ
.did
, typ
.name
.clone());
1120 /// Recurse in the directory structure and change the "root path" to make
1121 /// sure it always points to the top (relatively)
1122 fn recurse
<T
, F
>(&mut self, s
: String
, f
: F
) -> T
where
1123 F
: FnOnce(&mut Context
) -> T
,
1126 panic
!("Unexpected empty destination: {:?}", self.current
);
1128 let prev
= self.dst
.clone();
1130 self.root_path
.push_str("../");
1131 self.current
.push(s
);
1133 info
!("Recursing into {}", self.dst
.display());
1135 mkdir(&self.dst
).unwrap();
1138 info
!("Recursed; leaving {}", self.dst
.display());
1140 // Go back to where we were at
1142 let len
= self.root_path
.len();
1143 self.root_path
.truncate(len
- 3);
1144 self.current
.pop().unwrap();
1149 /// Main method for rendering a crate.
1151 /// This currently isn't parallelized, but it'd be pretty easy to add
1152 /// parallelization to this function.
1153 fn krate(self, mut krate
: clean
::Crate
) -> io
::Result
<()> {
1154 let mut item
= match krate
.module
.take() {
1156 None
=> return Ok(())
1158 item
.name
= Some(krate
.name
);
1160 // render the crate documentation
1161 let mut work
= vec
!((self, item
));
1164 Some((mut cx
, item
)) => try
!(cx
.item(item
, |cx
, item
| {
1165 work
.push((cx
.clone(), item
));
1174 /// Non-parallelized version of rendering an item. This will take the input
1175 /// item, render its contents, and then invoke the specified closure with
1176 /// all sub-items which need to be rendered.
1178 /// The rendering driver uses this closure to queue up more work.
1179 fn item
<F
>(&mut self, item
: clean
::Item
, mut f
: F
) -> io
::Result
<()> where
1180 F
: FnMut(&mut Context
, clean
::Item
),
1182 fn render(w
: File
, cx
: &Context
, it
: &clean
::Item
,
1183 pushname
: bool
) -> io
::Result
<()> {
1184 // A little unfortunate that this is done like this, but it sure
1185 // does make formatting *a lot* nicer.
1186 CURRENT_LOCATION_KEY
.with(|slot
| {
1187 *slot
.borrow_mut() = cx
.current
.clone();
1190 let mut title
= cx
.current
.connect("::");
1192 if !title
.is_empty() {
1193 title
.push_str("::");
1195 title
.push_str(it
.name
.as_ref().unwrap());
1197 title
.push_str(" - Rust");
1198 let tyname
= shortty(it
).to_static_str();
1199 let is_crate
= match it
.inner
{
1200 clean
::ModuleItem(clean
::Module { items: _, is_crate: true }
) => true,
1203 let desc
= if is_crate
{
1204 format
!("API documentation for the Rust `{}` crate.",
1207 format
!("API documentation for the Rust `{}` {} in crate `{}`.",
1208 it
.name
.as_ref().unwrap(), tyname
, cx
.layout
.krate
)
1210 let keywords
= make_item_keywords(it
);
1211 let page
= layout
::Page
{
1213 root_path
: &cx
.root_path
,
1216 keywords
: &keywords
,
1219 markdown
::reset_headers();
1221 // We have a huge number of calls to write, so try to alleviate some
1222 // of the pain by using a buffered writer instead of invoking the
1223 // write syscall all the time.
1224 let mut writer
= BufWriter
::new(w
);
1225 if !cx
.render_redirect_pages
{
1226 try
!(layout
::render(&mut writer
, &cx
.layout
, &page
,
1227 &Sidebar{ cx: cx, item: it }
,
1228 &Item{ cx: cx, item: it }
));
1230 let mut url
= repeat("../").take(cx
.current
.len())
1231 .collect
::<String
>();
1232 match cache().paths
.get(&it
.def_id
) {
1233 Some(&(ref names
, _
)) => {
1234 for name
in &names
[..names
.len() - 1] {
1238 url
.push_str(&item_path(it
));
1239 try
!(layout
::redirect(&mut writer
, &url
));
1247 // Private modules may survive the strip-private pass if they
1248 // contain impls for public types. These modules can also
1249 // contain items such as publicly reexported structures.
1251 // External crates will provide links to these structures, so
1252 // these modules are recursed into, but not rendered normally (a
1253 // flag on the context).
1254 if !self.render_redirect_pages
{
1255 self.render_redirect_pages
= self.ignore_private_item(&item
);
1259 // modules are special because they add a namespace. We also need to
1260 // recurse into the items of the module as well.
1261 clean
::ModuleItem(..) => {
1262 let name
= item
.name
.as_ref().unwrap().to_string();
1263 let mut item
= Some(item
);
1264 self.recurse(name
, |this
| {
1265 let item
= item
.take().unwrap();
1266 let dst
= this
.dst
.join("index.html");
1267 let dst
= try
!(File
::create(&dst
));
1268 try
!(render(dst
, this
, &item
, false));
1270 let m
= match item
.inner
{
1271 clean
::ModuleItem(m
) => m
,
1275 // render sidebar-items.js used throughout this module
1277 let items
= this
.build_sidebar_items(&m
);
1278 let js_dst
= this
.dst
.join("sidebar-items.js");
1279 let mut js_out
= BufWriter
::new(try
!(File
::create(&js_dst
)));
1280 try
!(write
!(&mut js_out
, "initSidebarItems({});",
1281 json
::as_json(&items
)));
1284 for item
in m
.items
{
1291 // Things which don't have names (like impls) don't get special
1292 // pages dedicated to them.
1293 _
if item
.name
.is_some() => {
1294 let dst
= self.dst
.join(&item_path(&item
));
1295 let dst
= try
!(File
::create(&dst
));
1296 render(dst
, self, &item
, true)
1303 fn build_sidebar_items(&self, m
: &clean
::Module
) -> BTreeMap
<String
, Vec
<NameDoc
>> {
1304 // BTreeMap instead of HashMap to get a sorted output
1305 let mut map
= BTreeMap
::new();
1306 for item
in &m
.items
{
1307 if self.ignore_private_item(item
) { continue }
1309 let short
= shortty(item
).to_static_str();
1310 let myname
= match item
.name
{
1312 Some(ref s
) => s
.to_string(),
1314 let short
= short
.to_string();
1315 map
.entry(short
).or_insert(vec
![])
1316 .push((myname
, Some(plain_summary_line(item
.doc_value()))));
1319 for (_
, items
) in &mut map
{
1325 fn ignore_private_item(&self, it
: &clean
::Item
) -> bool
{
1327 clean
::ModuleItem(ref m
) => {
1328 (m
.items
.is_empty() &&
1329 it
.doc_value().is_none() &&
1330 it
.visibility
!= Some(ast
::Public
)) ||
1331 (self.passes
.contains("strip-private") && it
.visibility
!= Some(ast
::Public
))
1333 clean
::PrimitiveItem(..) => it
.visibility
!= Some(ast
::Public
),
1340 fn ismodule(&self) -> bool
{
1341 match self.item
.inner
{
1342 clean
::ModuleItem(..) => true, _
=> false
1346 /// Generate a url appropriate for an `href` attribute back to the source of
1349 /// The url generated, when clicked, will redirect the browser back to the
1350 /// original source code.
1352 /// If `None` is returned, then a source link couldn't be generated. This
1353 /// may happen, for example, with externally inlined items where the source
1354 /// of their crate documentation isn't known.
1355 fn href(&self, cx
: &Context
) -> Option
<String
> {
1356 let href
= if self.item
.source
.loline
== self.item
.source
.hiline
{
1357 format
!("{}", self.item
.source
.loline
)
1359 format
!("{}-{}", self.item
.source
.loline
, self.item
.source
.hiline
)
1362 // First check to see if this is an imported macro source. In this case
1363 // we need to handle it specially as cross-crate inlined macros have...
1365 let imported_macro_from
= match self.item
.inner
{
1366 clean
::MacroItem(ref m
) => m
.imported_from
.as_ref(),
1369 if let Some(krate
) = imported_macro_from
{
1370 let cache
= cache();
1371 let root
= cache
.extern_locations
.values().find(|&&(ref n
, _
)| {
1374 let root
= match root
{
1375 Some(&Remote(ref s
)) => s
.to_string(),
1376 Some(&Local
) => self.cx
.root_path
.clone(),
1377 None
| Some(&Unknown
) => return None
,
1379 Some(format
!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1",
1382 name
= self.item
.name
.as_ref().unwrap()))
1384 // If this item is part of the local crate, then we're guaranteed to
1385 // know the span, so we plow forward and generate a proper url. The url
1386 // has anchors for the line numbers that we're linking to.
1387 } else if ast_util
::is_local(self.item
.def_id
) {
1388 let mut path
= Vec
::new();
1389 clean_srcpath(&cx
.src_root
, Path
::new(&self.item
.source
.filename
),
1391 path
.push(component
.to_string());
1393 Some(format
!("{root}src/{krate}/{path}.html#{href}",
1394 root
= self.cx
.root_path
,
1395 krate
= self.cx
.layout
.krate
,
1396 path
= path
.connect("/"),
1399 // If this item is not part of the local crate, then things get a little
1400 // trickier. We don't actually know the span of the external item, but
1401 // we know that the documentation on the other end knows the span!
1403 // In this case, we generate a link to the *documentation* for this type
1404 // in the original crate. There's an extra URL parameter which says that
1405 // we want to go somewhere else, and the JS on the destination page will
1406 // pick it up and instantly redirect the browser to the source code.
1408 // If we don't know where the external documentation for this crate is
1409 // located, then we return `None`.
1411 let cache
= cache();
1412 let path
= &cache
.external_paths
[&self.item
.def_id
];
1413 let root
= match cache
.extern_locations
[&self.item
.def_id
.krate
] {
1414 (_
, Remote(ref s
)) => s
.to_string(),
1415 (_
, Local
) => self.cx
.root_path
.clone(),
1416 (_
, Unknown
) => return None
,
1418 Some(format
!("{root}{path}/{file}?gotosrc={goto}",
1420 path
= path
[..path
.len() - 1].connect("/"),
1421 file
= item_path(self.item
),
1422 goto
= self.item
.def_id
.node
))
1428 impl<'a
> fmt
::Display
for Item
<'a
> {
1429 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
1430 // Write the breadcrumb trail header for the top
1431 try
!(write
!(fmt
, "\n<h1 class='fqn'><span class='in-band'>"));
1432 match self.item
.inner
{
1433 clean
::ModuleItem(ref m
) => if m
.is_crate
{
1434 try
!(write
!(fmt
, "Crate "));
1436 try
!(write
!(fmt
, "Module "));
1438 clean
::FunctionItem(..) => try
!(write
!(fmt
, "Function ")),
1439 clean
::TraitItem(..) => try
!(write
!(fmt
, "Trait ")),
1440 clean
::StructItem(..) => try
!(write
!(fmt
, "Struct ")),
1441 clean
::EnumItem(..) => try
!(write
!(fmt
, "Enum ")),
1442 clean
::PrimitiveItem(..) => try
!(write
!(fmt
, "Primitive Type ")),
1445 let is_primitive
= match self.item
.inner
{
1446 clean
::PrimitiveItem(..) => true,
1450 let cur
= &self.cx
.current
;
1451 let amt
= if self.ismodule() { cur.len() - 1 }
else { cur.len() }
;
1452 for (i
, component
) in cur
.iter().enumerate().take(amt
) {
1453 try
!(write
!(fmt
, "<a href='{}index.html'>{}</a>::<wbr>",
1454 repeat("../").take(cur
.len() - i
- 1)
1455 .collect
::<String
>(),
1459 try
!(write
!(fmt
, "<a class='{}' href=''>{}</a>",
1460 shortty(self.item
), self.item
.name
.as_ref().unwrap()));
1462 try
!(write
!(fmt
, "</span>")); // in-band
1463 try
!(write
!(fmt
, "<span class='out-of-band'>"));
1465 r
##"<span id='render-detail'>
1466 <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
1467 [<span class='inner'>−</span>]
1473 // When this item is part of a `pub use` in a downstream crate, the
1474 // [src] link in the downstream documentation will actually come back to
1475 // this page, and this link will be auto-clicked. The `id` attribute is
1476 // used to find the link to auto-click.
1477 if self.cx
.include_sources
&& !is_primitive
{
1478 match self.href(self.cx
) {
1480 try
!(write
!(fmt
, "<a id='src-{}' class='srclink' \
1481 href='{}' title='{}'>[src]</a>",
1482 self.item
.def_id
.node
, l
, "goto source code"));
1488 try
!(write
!(fmt
, "</span>")); // out-of-band
1490 try
!(write
!(fmt
, "</h1>\n"));
1492 match self.item
.inner
{
1493 clean
::ModuleItem(ref m
) => {
1494 item_module(fmt
, self.cx
, self.item
, &m
.items
)
1496 clean
::FunctionItem(ref f
) | clean
::ForeignFunctionItem(ref f
) =>
1497 item_function(fmt
, self.item
, f
),
1498 clean
::TraitItem(ref t
) => item_trait(fmt
, self.cx
, self.item
, t
),
1499 clean
::StructItem(ref s
) => item_struct(fmt
, self.item
, s
),
1500 clean
::EnumItem(ref e
) => item_enum(fmt
, self.item
, e
),
1501 clean
::TypedefItem(ref t
, _
) => item_typedef(fmt
, self.item
, t
),
1502 clean
::MacroItem(ref m
) => item_macro(fmt
, self.item
, m
),
1503 clean
::PrimitiveItem(ref p
) => item_primitive(fmt
, self.item
, p
),
1504 clean
::StaticItem(ref i
) | clean
::ForeignStaticItem(ref i
) =>
1505 item_static(fmt
, self.item
, i
),
1506 clean
::ConstantItem(ref c
) => item_constant(fmt
, self.item
, c
),
1512 fn item_path(item
: &clean
::Item
) -> String
{
1514 clean
::ModuleItem(..) => {
1515 format
!("{}/index.html", item
.name
.as_ref().unwrap())
1518 format
!("{}.{}.html",
1519 shortty(item
).to_static_str(),
1520 *item
.name
.as_ref().unwrap())
1525 fn full_path(cx
: &Context
, item
: &clean
::Item
) -> String
{
1526 let mut s
= cx
.current
.connect("::");
1528 s
.push_str(item
.name
.as_ref().unwrap());
1532 fn shorter
<'a
>(s
: Option
<&'a
str>) -> String
{
1534 Some(s
) => s
.lines().take_while(|line
|{
1535 (*line
).chars().any(|chr
|{
1536 !chr
.is_whitespace()
1538 }).collect
::<Vec
<_
>>().connect("\n"),
1539 None
=> "".to_string()
1544 fn plain_summary_line(s
: Option
<&str>) -> String
{
1545 let line
= shorter(s
).replace("\n", " ");
1546 markdown
::plain_summary_line(&line
[..])
1549 fn document(w
: &mut fmt
::Formatter
, item
: &clean
::Item
) -> fmt
::Result
{
1550 if let Some(s
) = short_stability(item
, true) {
1551 try
!(write
!(w
, "<div class='stability'>{}</div>", s
));
1553 if let Some(s
) = item
.doc_value() {
1554 try
!(write
!(w
, "<div class='docblock'>{}</div>", Markdown(s
)));
1559 fn item_module(w
: &mut fmt
::Formatter
, cx
: &Context
,
1560 item
: &clean
::Item
, items
: &[clean
::Item
]) -> fmt
::Result
{
1561 try
!(document(w
, item
));
1563 let mut indices
= (0..items
.len()).filter(|i
| {
1564 !cx
.ignore_private_item(&items
[*i
])
1565 }).collect
::<Vec
<usize>>();
1567 // the order of item types in the listing
1568 fn reorder(ty
: ItemType
) -> u8 {
1570 ItemType
::ExternCrate
=> 0,
1571 ItemType
::Import
=> 1,
1572 ItemType
::Primitive
=> 2,
1573 ItemType
::Module
=> 3,
1574 ItemType
::Macro
=> 4,
1575 ItemType
::Struct
=> 5,
1576 ItemType
::Enum
=> 6,
1577 ItemType
::Constant
=> 7,
1578 ItemType
::Static
=> 8,
1579 ItemType
::Trait
=> 9,
1580 ItemType
::Function
=> 10,
1581 ItemType
::Typedef
=> 12,
1586 fn cmp(i1
: &clean
::Item
, i2
: &clean
::Item
, idx1
: usize, idx2
: usize) -> Ordering
{
1587 let ty1
= shortty(i1
);
1588 let ty2
= shortty(i2
);
1590 return (reorder(ty1
), idx1
).cmp(&(reorder(ty2
), idx2
))
1592 let s1
= i1
.stability
.as_ref().map(|s
| s
.level
);
1593 let s2
= i2
.stability
.as_ref().map(|s
| s
.level
);
1595 (Some(attr
::Unstable
), Some(attr
::Stable
)) => return Ordering
::Greater
,
1596 (Some(attr
::Stable
), Some(attr
::Unstable
)) => return Ordering
::Less
,
1599 i1
.name
.cmp(&i2
.name
)
1602 indices
.sort_by(|&i1
, &i2
| cmp(&items
[i1
], &items
[i2
], i1
, i2
));
1604 debug
!("{:?}", indices
);
1605 let mut curty
= None
;
1606 for &idx
in &indices
{
1607 let myitem
= &items
[idx
];
1609 let myty
= Some(shortty(myitem
));
1610 if curty
== Some(ItemType
::ExternCrate
) && myty
== Some(ItemType
::Import
) {
1611 // Put `extern crate` and `use` re-exports in the same section.
1613 } else if myty
!= curty
{
1614 if curty
.is_some() {
1615 try
!(write
!(w
, "</table>"));
1618 let (short
, name
) = match myty
.unwrap() {
1619 ItemType
::ExternCrate
|
1620 ItemType
::Import
=> ("reexports", "Reexports"),
1621 ItemType
::Module
=> ("modules", "Modules"),
1622 ItemType
::Struct
=> ("structs", "Structs"),
1623 ItemType
::Enum
=> ("enums", "Enums"),
1624 ItemType
::Function
=> ("functions", "Functions"),
1625 ItemType
::Typedef
=> ("types", "Type Definitions"),
1626 ItemType
::Static
=> ("statics", "Statics"),
1627 ItemType
::Constant
=> ("constants", "Constants"),
1628 ItemType
::Trait
=> ("traits", "Traits"),
1629 ItemType
::Impl
=> ("impls", "Implementations"),
1630 ItemType
::TyMethod
=> ("tymethods", "Type Methods"),
1631 ItemType
::Method
=> ("methods", "Methods"),
1632 ItemType
::StructField
=> ("fields", "Struct Fields"),
1633 ItemType
::Variant
=> ("variants", "Variants"),
1634 ItemType
::Macro
=> ("macros", "Macros"),
1635 ItemType
::Primitive
=> ("primitives", "Primitive Types"),
1636 ItemType
::AssociatedType
=> ("associated-types", "Associated Types"),
1637 ItemType
::AssociatedConst
=> ("associated-consts", "Associated Constants"),
1640 "<h2 id='{id}' class='section-header'>\
1641 <a href=\"#{id}\">{name}</a></h2>\n<table>",
1642 id
= short
, name
= name
));
1645 match myitem
.inner
{
1646 clean
::ExternCrateItem(ref name
, ref src
) => {
1649 try
!(write
!(w
, "<tr><td><code>{}extern crate {} as {};",
1650 VisSpace(myitem
.visibility
),
1655 try
!(write
!(w
, "<tr><td><code>{}extern crate {};",
1656 VisSpace(myitem
.visibility
), name
))
1659 try
!(write
!(w
, "</code></td></tr>"));
1662 clean
::ImportItem(ref import
) => {
1663 try
!(write
!(w
, "<tr><td><code>{}{}</code></td></tr>",
1664 VisSpace(myitem
.visibility
), *import
));
1668 if myitem
.name
.is_none() { continue }
1669 let stab_docs
= if let Some(s
) = short_stability(myitem
, false) {
1675 <tr class='{stab} module-item'>
1676 <td><a class='{class}' href='{href}'
1677 title='{title}'>{name}</a></td>
1678 <td class='docblock short'>
1683 name
= *myitem
.name
.as_ref().unwrap(),
1684 stab_docs
= stab_docs
,
1685 docs
= Markdown(&shorter(myitem
.doc_value())),
1686 class
= shortty(myitem
),
1687 stab
= myitem
.stability_class(),
1688 href
= item_path(myitem
),
1689 title
= full_path(cx
, myitem
)));
1694 write
!(w
, "</table>")
1697 fn short_stability(item
: &clean
::Item
, show_reason
: bool
) -> Option
<String
> {
1698 item
.stability
.as_ref().and_then(|stab
| {
1699 let reason
= if show_reason
&& !stab
.reason
.is_empty() {
1700 format
!(": {}", stab
.reason
)
1704 let text
= if !stab
.deprecated_since
.is_empty() {
1705 let since
= if show_reason
{
1706 format
!(" since {}", Escape(&stab
.deprecated_since
))
1710 format
!("Deprecated{}{}", since
, Markdown(&reason
))
1711 } else if stab
.level
== attr
::Unstable
{
1712 format
!("Unstable{}", Markdown(&reason
))
1716 Some(format
!("<em class='stab {}'>{}</em>",
1717 item
.stability_class(), text
))
1721 struct Initializer
<'a
>(&'a
str);
1723 impl<'a
> fmt
::Display
for Initializer
<'a
> {
1724 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1725 let Initializer(s
) = *self;
1726 if s
.is_empty() { return Ok(()); }
1727 try
!(write
!(f
, "<code> = </code>"));
1728 write
!(f
, "<code>{}</code>", s
)
1732 fn item_constant(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1733 c
: &clean
::Constant
) -> fmt
::Result
{
1734 try
!(write
!(w
, "<pre class='rust const'>{vis}const \
1735 {name}: {typ}{init}</pre>",
1736 vis
= VisSpace(it
.visibility
),
1737 name
= it
.name
.as_ref().unwrap(),
1739 init
= Initializer(&c
.expr
)));
1743 fn item_static(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1744 s
: &clean
::Static
) -> fmt
::Result
{
1745 try
!(write
!(w
, "<pre class='rust static'>{vis}static {mutability}\
1746 {name}: {typ}{init}</pre>",
1747 vis
= VisSpace(it
.visibility
),
1748 mutability
= MutableSpace(s
.mutability
),
1749 name
= it
.name
.as_ref().unwrap(),
1751 init
= Initializer(&s
.expr
)));
1755 fn item_function(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1756 f
: &clean
::Function
) -> fmt
::Result
{
1757 try
!(write
!(w
, "<pre class='rust fn'>{vis}{unsafety}{abi}{constness}fn \
1758 {name}{generics}{decl}{where_clause}</pre>",
1759 vis
= VisSpace(it
.visibility
),
1760 unsafety
= UnsafetySpace(f
.unsafety
),
1761 abi
= AbiSpace(f
.abi
),
1762 constness
= ConstnessSpace(f
.constness
),
1763 name
= it
.name
.as_ref().unwrap(),
1764 generics
= f
.generics
,
1765 where_clause
= WhereClause(&f
.generics
),
1770 fn item_trait(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
1771 t
: &clean
::Trait
) -> fmt
::Result
{
1772 let mut bounds
= String
::new();
1773 if !t
.bounds
.is_empty() {
1774 if !bounds
.is_empty() {
1777 bounds
.push_str(": ");
1778 for (i
, p
) in t
.bounds
.iter().enumerate() {
1779 if i
> 0 { bounds.push_str(" + "); }
1780 bounds
.push_str(&format
!("{}", *p
));
1784 // Output the trait definition
1785 try
!(write
!(w
, "<pre class='rust trait'>{}{}trait {}{}{}{} ",
1786 VisSpace(it
.visibility
),
1787 UnsafetySpace(t
.unsafety
),
1788 it
.name
.as_ref().unwrap(),
1791 WhereClause(&t
.generics
)));
1793 let types
= t
.items
.iter().filter(|m
| {
1794 match m
.inner { clean::AssociatedTypeItem(..) => true, _ => false }
1795 }).collect
::<Vec
<_
>>();
1796 let consts
= t
.items
.iter().filter(|m
| {
1797 match m
.inner { clean::AssociatedConstItem(..) => true, _ => false }
1798 }).collect
::<Vec
<_
>>();
1799 let required
= t
.items
.iter().filter(|m
| {
1800 match m
.inner { clean::TyMethodItem(_) => true, _ => false }
1801 }).collect
::<Vec
<_
>>();
1802 let provided
= t
.items
.iter().filter(|m
| {
1803 match m
.inner { clean::MethodItem(_) => true, _ => false }
1804 }).collect
::<Vec
<_
>>();
1806 if t
.items
.is_empty() {
1807 try
!(write
!(w
, "{{ }}"));
1809 try
!(write
!(w
, "{{\n"));
1811 try
!(write
!(w
, " "));
1812 try
!(render_assoc_item(w
, t
, AssocItemLink
::Anchor
));
1813 try
!(write
!(w
, ";\n"));
1815 if !types
.is_empty() && !consts
.is_empty() {
1816 try
!(w
.write_str("\n"));
1819 try
!(write
!(w
, " "));
1820 try
!(render_assoc_item(w
, t
, AssocItemLink
::Anchor
));
1821 try
!(write
!(w
, ";\n"));
1823 if !consts
.is_empty() && !required
.is_empty() {
1824 try
!(w
.write_str("\n"));
1826 for m
in &required
{
1827 try
!(write
!(w
, " "));
1828 try
!(render_assoc_item(w
, m
, AssocItemLink
::Anchor
));
1829 try
!(write
!(w
, ";\n"));
1831 if !required
.is_empty() && !provided
.is_empty() {
1832 try
!(w
.write_str("\n"));
1834 for m
in &provided
{
1835 try
!(write
!(w
, " "));
1836 try
!(render_assoc_item(w
, m
, AssocItemLink
::Anchor
));
1837 try
!(write
!(w
, " {{ ... }}\n"));
1839 try
!(write
!(w
, "}}"));
1841 try
!(write
!(w
, "</pre>"));
1843 // Trait documentation
1844 try
!(document(w
, it
));
1846 fn trait_item(w
: &mut fmt
::Formatter
, m
: &clean
::Item
)
1848 try
!(write
!(w
, "<h3 id='{ty}.{name}' class='method stab {stab}'><code>",
1850 name
= *m
.name
.as_ref().unwrap(),
1851 stab
= m
.stability_class()));
1852 try
!(render_assoc_item(w
, m
, AssocItemLink
::Anchor
));
1853 try
!(write
!(w
, "</code></h3>"));
1854 try
!(document(w
, m
));
1858 if !types
.is_empty() {
1860 <h2 id='associated-types'>Associated Types</h2>
1861 <div class='methods'>
1864 try
!(trait_item(w
, *t
));
1866 try
!(write
!(w
, "</div>"));
1869 if !consts
.is_empty() {
1871 <h2 id='associated-const'>Associated Constants</h2>
1872 <div class='methods'>
1875 try
!(trait_item(w
, *t
));
1877 try
!(write
!(w
, "</div>"));
1880 // Output the documentation for each function individually
1881 if !required
.is_empty() {
1883 <h2 id='required-methods'>Required Methods</h2>
1884 <div class='methods'>
1886 for m
in &required
{
1887 try
!(trait_item(w
, *m
));
1889 try
!(write
!(w
, "</div>"));
1891 if !provided
.is_empty() {
1893 <h2 id='provided-methods'>Provided Methods</h2>
1894 <div class='methods'>
1896 for m
in &provided
{
1897 try
!(trait_item(w
, *m
));
1899 try
!(write
!(w
, "</div>"));
1902 // If there are methods directly on this trait object, render them here.
1903 try
!(render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
));
1905 let cache
= cache();
1907 <h2 id='implementors'>Implementors</h2>
1908 <ul class='item-list' id='implementors-list'>
1910 match cache
.implementors
.get(&it
.def_id
) {
1911 Some(implementors
) => {
1912 for i
in implementors
{
1913 try
!(writeln
!(w
, "<li><code>impl{} {} for {}{}</code></li>",
1914 i
.generics
, i
.trait_
, i
.for_
, WhereClause(&i
.generics
)));
1919 try
!(write
!(w
, "</ul>"));
1920 try
!(write
!(w
, r
#"<script type="text/javascript" async
1921 src="{root_path}/implementors/{path}/{ty}.{name}.js">
1923 root_path
= repeat("..").take(cx
.current
.len()).collect
::<Vec
<_
>>().connect("/"),
1924 path
= if ast_util
::is_local(it
.def_id
) {
1925 cx
.current
.connect("/")
1927 let path
= &cache
.external_paths
[&it
.def_id
];
1928 path
[..path
.len() - 1].connect("/")
1930 ty
= shortty(it
).to_static_str(),
1931 name
= *it
.name
.as_ref().unwrap()));
1935 fn assoc_const(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1936 ty
: &clean
::Type
, default: Option
<&String
>)
1938 try
!(write
!(w
, "const {}", it
.name
.as_ref().unwrap()));
1939 try
!(write
!(w
, ": {}", ty
));
1940 if let Some(default) = default {
1941 try
!(write
!(w
, " = {}", default));
1946 fn assoc_type(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1947 bounds
: &Vec
<clean
::TyParamBound
>,
1948 default: &Option
<clean
::Type
>)
1950 try
!(write
!(w
, "type {}", it
.name
.as_ref().unwrap()));
1951 if !bounds
.is_empty() {
1952 try
!(write
!(w
, ": {}", TyParamBounds(bounds
)))
1954 if let Some(ref default) = *default {
1955 try
!(write
!(w
, " = {}", default));
1960 fn render_assoc_item(w
: &mut fmt
::Formatter
, meth
: &clean
::Item
,
1961 link
: AssocItemLink
) -> fmt
::Result
{
1962 fn method(w
: &mut fmt
::Formatter
,
1964 unsafety
: ast
::Unsafety
,
1965 constness
: ast
::Constness
,
1967 g
: &clean
::Generics
,
1968 selfty
: &clean
::SelfTy
,
1970 link
: AssocItemLink
)
1972 use syntax
::abi
::Abi
;
1974 let name
= it
.name
.as_ref().unwrap();
1975 let anchor
= format
!("#{}.{}", shortty(it
), name
);
1976 let href
= match link
{
1977 AssocItemLink
::Anchor
=> anchor
,
1978 AssocItemLink
::GotoSource(did
) => {
1979 href(did
).map(|p
| format
!("{}{}", p
.0, anchor
)).unwrap_or(anchor
)
1982 write
!(w
, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
1983 {generics}{decl}{where_clause}",
1984 UnsafetySpace(unsafety
),
1985 ConstnessSpace(constness
),
1987 Abi
::Rust
=> String
::new(),
1988 a
=> format
!("extern {} ", a
.to_string())
1993 decl
= Method(selfty
, d
),
1994 where_clause
= WhereClause(g
))
1997 clean
::TyMethodItem(ref m
) => {
1998 method(w
, meth
, m
.unsafety
, ast
::Constness
::NotConst
,
1999 m
.abi
, &m
.generics
, &m
.self_
, &m
.decl
, link
)
2001 clean
::MethodItem(ref m
) => {
2002 method(w
, meth
, m
.unsafety
, m
.constness
,
2003 m
.abi
, &m
.generics
, &m
.self_
, &m
.decl
,
2006 clean
::AssociatedConstItem(ref ty
, ref default) => {
2007 assoc_const(w
, meth
, ty
, default.as_ref())
2009 clean
::AssociatedTypeItem(ref bounds
, ref default) => {
2010 assoc_type(w
, meth
, bounds
, default)
2012 _
=> panic
!("render_assoc_item called on non-associated-item")
2016 fn item_struct(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2017 s
: &clean
::Struct
) -> fmt
::Result
{
2018 try
!(write
!(w
, "<pre class='rust struct'>"));
2019 try
!(render_attributes(w
, it
));
2020 try
!(render_struct(w
,
2027 try
!(write
!(w
, "</pre>"));
2029 try
!(document(w
, it
));
2030 let mut fields
= s
.fields
.iter().filter(|f
| {
2032 clean
::StructFieldItem(clean
::HiddenStructField
) => false,
2033 clean
::StructFieldItem(clean
::TypedStructField(..)) => true,
2037 if let doctree
::Plain
= s
.struct_type
{
2038 if fields
.peek().is_some() {
2039 try
!(write
!(w
, "<h2 class='fields'>Fields</h2>\n<table>"));
2040 for field
in fields
{
2041 try
!(write
!(w
, "<tr class='stab {stab}'>
2042 <td id='structfield.{name}'>\
2043 <code>{name}</code></td><td>",
2044 stab
= field
.stability_class(),
2045 name
= field
.name
.as_ref().unwrap()));
2046 try
!(document(w
, field
));
2047 try
!(write
!(w
, "</td></tr>"));
2049 try
!(write
!(w
, "</table>"));
2052 render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
)
2055 fn item_enum(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2056 e
: &clean
::Enum
) -> fmt
::Result
{
2057 try
!(write
!(w
, "<pre class='rust enum'>"));
2058 try
!(render_attributes(w
, it
));
2059 try
!(write
!(w
, "{}enum {}{}{}",
2060 VisSpace(it
.visibility
),
2061 it
.name
.as_ref().unwrap(),
2063 WhereClause(&e
.generics
)));
2064 if e
.variants
.is_empty() && !e
.variants_stripped
{
2065 try
!(write
!(w
, " {{}}"));
2067 try
!(write
!(w
, " {{\n"));
2068 for v
in &e
.variants
{
2069 try
!(write
!(w
, " "));
2070 let name
= v
.name
.as_ref().unwrap();
2072 clean
::VariantItem(ref var
) => {
2074 clean
::CLikeVariant
=> try
!(write
!(w
, "{}", name
)),
2075 clean
::TupleVariant(ref tys
) => {
2076 try
!(write
!(w
, "{}(", name
));
2077 for (i
, ty
) in tys
.iter().enumerate() {
2079 try
!(write
!(w
, ", "))
2081 try
!(write
!(w
, "{}", *ty
));
2083 try
!(write
!(w
, ")"));
2085 clean
::StructVariant(ref s
) => {
2086 try
!(render_struct(w
,
2098 try
!(write
!(w
, ",\n"));
2101 if e
.variants_stripped
{
2102 try
!(write
!(w
, " // some variants omitted\n"));
2104 try
!(write
!(w
, "}}"));
2106 try
!(write
!(w
, "</pre>"));
2108 try
!(document(w
, it
));
2109 if !e
.variants
.is_empty() {
2110 try
!(write
!(w
, "<h2 class='variants'>Variants</h2>\n<table>"));
2111 for variant
in &e
.variants
{
2112 try
!(write
!(w
, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
2113 name
= variant
.name
.as_ref().unwrap()));
2114 try
!(document(w
, variant
));
2115 match variant
.inner
{
2116 clean
::VariantItem(ref var
) => {
2118 clean
::StructVariant(ref s
) => {
2119 let fields
= s
.fields
.iter().filter(|f
| {
2121 clean
::StructFieldItem(ref t
) => match *t
{
2122 clean
::HiddenStructField
=> false,
2123 clean
::TypedStructField(..) => true,
2128 try
!(write
!(w
, "<h3 class='fields'>Fields</h3>\n
2130 for field
in fields
{
2131 try
!(write
!(w
, "<tr><td \
2132 id='variant.{v}.field.{f}'>\
2133 <code>{f}</code></td><td>",
2134 v
= variant
.name
.as_ref().unwrap(),
2135 f
= field
.name
.as_ref().unwrap()));
2136 try
!(document(w
, field
));
2137 try
!(write
!(w
, "</td></tr>"));
2139 try
!(write
!(w
, "</table>"));
2146 try
!(write
!(w
, "</td></tr>"));
2148 try
!(write
!(w
, "</table>"));
2151 try
!(render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
));
2155 fn render_attributes(w
: &mut fmt
::Formatter
, it
: &clean
::Item
) -> fmt
::Result
{
2156 for attr
in &it
.attrs
{
2158 clean
::Word(ref s
) if *s
== "must_use" => {
2159 try
!(write
!(w
, "#[{}]\n", s
));
2161 clean
::NameValue(ref k
, ref v
) if *k
== "must_use" => {
2162 try
!(write
!(w
, "#[{} = \"{}\"]\n", k
, v
));
2170 fn render_struct(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2171 g
: Option
<&clean
::Generics
>,
2172 ty
: doctree
::StructType
,
2173 fields
: &[clean
::Item
],
2175 structhead
: bool
) -> fmt
::Result
{
2176 try
!(write
!(w
, "{}{}{}",
2177 VisSpace(it
.visibility
),
2178 if structhead {"struct "}
else {""}
,
2179 it
.name
.as_ref().unwrap()));
2181 Some(g
) => try
!(write
!(w
, "{}{}", *g
, WhereClause(g
))),
2186 try
!(write
!(w
, " {{\n{}", tab
));
2187 let mut fields_stripped
= false;
2188 for field
in fields
{
2190 clean
::StructFieldItem(clean
::HiddenStructField
) => {
2191 fields_stripped
= true;
2193 clean
::StructFieldItem(clean
::TypedStructField(ref ty
)) => {
2194 try
!(write
!(w
, " {}{}: {},\n{}",
2195 VisSpace(field
.visibility
),
2196 field
.name
.as_ref().unwrap(),
2200 _
=> unreachable
!(),
2204 if fields_stripped
{
2205 try
!(write
!(w
, " // some fields omitted\n{}", tab
));
2207 try
!(write
!(w
, "}}"));
2209 doctree
::Tuple
| doctree
::Newtype
=> {
2210 try
!(write
!(w
, "("));
2211 for (i
, field
) in fields
.iter().enumerate() {
2213 try
!(write
!(w
, ", "));
2216 clean
::StructFieldItem(clean
::HiddenStructField
) => {
2217 try
!(write
!(w
, "_"))
2219 clean
::StructFieldItem(clean
::TypedStructField(ref ty
)) => {
2220 try
!(write
!(w
, "{}{}", VisSpace(field
.visibility
), *ty
))
2225 try
!(write
!(w
, ");"));
2228 try
!(write
!(w
, ";"));
2234 #[derive(Copy, Clone)]
2235 enum AssocItemLink
{
2237 GotoSource(ast
::DefId
),
2240 enum AssocItemRender
<'a
> {
2242 DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type }
,
2245 fn render_assoc_items(w
: &mut fmt
::Formatter
,
2247 what
: AssocItemRender
) -> fmt
::Result
{
2249 let v
= match c
.impls
.get(&it
) {
2251 None
=> return Ok(()),
2253 let (non_trait
, traits
): (Vec
<_
>, _
) = v
.iter().partition(|i
| {
2254 i
.impl_
.trait_
.is_none()
2256 if !non_trait
.is_empty() {
2257 let render_header
= match what
{
2258 AssocItemRender
::All
=> {
2259 try
!(write
!(w
, "<h2 id='methods'>Methods</h2>"));
2262 AssocItemRender
::DerefFor { trait_, type_ }
=> {
2263 try
!(write
!(w
, "<h2 id='deref-methods'>Methods from \
2264 {}<Target={}></h2>", trait_
, type_
));
2268 for i
in &non_trait
{
2269 try
!(render_impl(w
, i
, AssocItemLink
::Anchor
, render_header
));
2272 if let AssocItemRender
::DerefFor { .. }
= what
{
2275 if !traits
.is_empty() {
2276 let deref_impl
= traits
.iter().find(|t
| {
2277 match *t
.impl_
.trait_
.as_ref().unwrap() {
2278 clean
::ResolvedPath { did, .. }
=> {
2279 Some(did
) == c
.deref_trait_did
2284 if let Some(impl_
) = deref_impl
{
2285 try
!(render_deref_methods(w
, impl_
));
2287 try
!(write
!(w
, "<h2 id='implementations'>Trait \
2288 Implementations</h2>"));
2289 let (derived
, manual
): (Vec
<_
>, Vec
<&Impl
>) = traits
.iter().partition(|i
| {
2293 let did
= i
.trait_did().unwrap();
2294 try
!(render_impl(w
, i
, AssocItemLink
::GotoSource(did
), true));
2296 if !derived
.is_empty() {
2297 try
!(write
!(w
, "<h3 id='derived_implementations'>\
2298 Derived Implementations \
2301 let did
= i
.trait_did().unwrap();
2302 try
!(render_impl(w
, i
, AssocItemLink
::GotoSource(did
), true));
2309 fn render_deref_methods(w
: &mut fmt
::Formatter
, impl_
: &Impl
) -> fmt
::Result
{
2310 let deref_type
= impl_
.impl_
.trait_
.as_ref().unwrap();
2311 let target
= impl_
.impl_
.items
.iter().filter_map(|item
| {
2313 clean
::TypedefItem(ref t
, true) => Some(&t
.type_
),
2316 }).next().expect("Expected associated type binding");
2317 let what
= AssocItemRender
::DerefFor { trait_: deref_type, type_: target }
;
2319 clean
::ResolvedPath { did, .. }
=> render_assoc_items(w
, did
, what
),
2321 if let Some(prim
) = target
.primitive_type() {
2322 if let Some(c
) = cache().primitive_locations
.get(&prim
) {
2323 let did
= ast
::DefId { krate: *c, node: prim.to_node_id() }
;
2324 try
!(render_assoc_items(w
, did
, what
));
2332 // Render_header is false when we are rendering a `Deref` impl and true
2333 // otherwise. If render_header is false, we will avoid rendering static
2334 // methods, since they are not accessible for the type implementing `Deref`
2335 fn render_impl(w
: &mut fmt
::Formatter
, i
: &Impl
, link
: AssocItemLink
,
2336 render_header
: bool
) -> fmt
::Result
{
2338 try
!(write
!(w
, "<h3 class='impl'><code>impl{} ",
2340 if let Some(clean
::ImplPolarity
::Negative
) = i
.impl_
.polarity
{
2341 try
!(write
!(w
, "!"));
2343 if let Some(ref ty
) = i
.impl_
.trait_
{
2344 try
!(write
!(w
, "{} for ", *ty
));
2346 try
!(write
!(w
, "{}{}</code></h3>", i
.impl_
.for_
,
2347 WhereClause(&i
.impl_
.generics
)));
2348 if let Some(ref dox
) = i
.dox
{
2349 try
!(write
!(w
, "<div class='docblock'>{}</div>", Markdown(dox
)));
2353 fn doctraititem(w
: &mut fmt
::Formatter
, item
: &clean
::Item
,
2354 link
: AssocItemLink
, render_static
: bool
) -> fmt
::Result
{
2356 clean
::MethodItem(..) | clean
::TyMethodItem(..) => {
2357 // Only render when the method is not static or we allow static methods
2358 if !is_static_method(item
) || render_static
{
2359 try
!(write
!(w
, "<h4 id='method.{}' class='{}'><code>",
2360 *item
.name
.as_ref().unwrap(),
2362 try
!(render_assoc_item(w
, item
, link
));
2363 try
!(write
!(w
, "</code></h4>\n"));
2366 clean
::TypedefItem(ref tydef
, _
) => {
2367 let name
= item
.name
.as_ref().unwrap();
2368 try
!(write
!(w
, "<h4 id='assoc_type.{}' class='{}'><code>",
2371 try
!(write
!(w
, "type {} = {}", name
, tydef
.type_
));
2372 try
!(write
!(w
, "</code></h4>\n"));
2374 clean
::AssociatedConstItem(ref ty
, ref default) => {
2375 let name
= item
.name
.as_ref().unwrap();
2376 try
!(write
!(w
, "<h4 id='assoc_const.{}' class='{}'><code>",
2377 *name
, shortty(item
)));
2378 try
!(assoc_const(w
, item
, ty
, default.as_ref()));
2379 try
!(write
!(w
, "</code></h4>\n"));
2381 clean
::ConstantItem(ref c
) => {
2382 let name
= item
.name
.as_ref().unwrap();
2383 try
!(write
!(w
, "<h4 id='assoc_const.{}' class='{}'><code>",
2384 *name
, shortty(item
)));
2385 try
!(assoc_const(w
, item
, &c
.type_
, Some(&c
.expr
)));
2386 try
!(write
!(w
, "</code></h4>\n"));
2388 clean
::AssociatedTypeItem(ref bounds
, ref default) => {
2389 let name
= item
.name
.as_ref().unwrap();
2390 try
!(write
!(w
, "<h4 id='assoc_type.{}' class='{}'><code>",
2393 try
!(assoc_type(w
, item
, bounds
, default));
2394 try
!(write
!(w
, "</code></h4>\n"));
2396 _
=> panic
!("can't make docs for trait item with name {:?}", item
.name
)
2399 return if let AssocItemLink
::Anchor
= link
{
2400 if is_static_method(item
) && !render_static
{
2409 fn is_static_method(item
: &clean
::Item
) -> bool
{
2411 clean
::MethodItem(ref method
) => method
.self_
== SelfTy
::SelfStatic
,
2412 clean
::TyMethodItem(ref method
) => method
.self_
== SelfTy
::SelfStatic
,
2418 try
!(write
!(w
, "<div class='impl-items'>"));
2419 for trait_item
in &i
.impl_
.items
{
2420 try
!(doctraititem(w
, trait_item
, link
, render_header
));
2423 fn render_default_items(w
: &mut fmt
::Formatter
,
2427 render_static
: bool
) -> fmt
::Result
{
2428 for trait_item
in &t
.items
{
2429 let n
= trait_item
.name
.clone();
2430 match i
.items
.iter().find(|m
| { m.name == n }
) {
2431 Some(..) => continue,
2435 try
!(doctraititem(w
, trait_item
, AssocItemLink
::GotoSource(did
), render_static
));
2440 // If we've implemented a trait, then also emit documentation for all
2441 // default methods which weren't overridden in the implementation block.
2442 // FIXME: this also needs to be done for associated types, whenever defaults
2444 if let Some(clean
::ResolvedPath { did, .. }
) = i
.impl_
.trait_
{
2445 if let Some(t
) = cache().traits
.get(&did
) {
2446 try
!(render_default_items(w
, did
, t
, &i
.impl_
, render_header
));
2450 try
!(write
!(w
, "</div>"));
2454 fn item_typedef(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2455 t
: &clean
::Typedef
) -> fmt
::Result
{
2456 try
!(write
!(w
, "<pre class='rust typedef'>type {}{}{where_clause} = {type_};</pre>",
2457 it
.name
.as_ref().unwrap(),
2459 where_clause
= WhereClause(&t
.generics
),
2465 impl<'a
> fmt
::Display
for Sidebar
<'a
> {
2466 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
2469 let parentlen
= cx
.current
.len() - if it
.is_mod() {1}
else {0}
;
2471 // the sidebar is designed to display sibling functions, modules and
2472 // other miscellaneous informations. since there are lots of sibling
2473 // items (and that causes quadratic growth in large modules),
2474 // we refactor common parts into a shared JavaScript file per module.
2475 // still, we don't move everything into JS because we want to preserve
2476 // as much HTML as possible in order to allow non-JS-enabled browsers
2477 // to navigate the documentation (though slightly inefficiently).
2479 try
!(write
!(fmt
, "<p class='location'>"));
2480 for (i
, name
) in cx
.current
.iter().take(parentlen
).enumerate() {
2482 try
!(write
!(fmt
, "::<wbr>"));
2484 try
!(write
!(fmt
, "<a href='{}index.html'>{}</a>",
2485 &cx
.root_path
[..(cx
.current
.len() - i
- 1) * 3],
2488 try
!(write
!(fmt
, "</p>"));
2490 // sidebar refers to the enclosing module, not this module
2491 let relpath
= if shortty(it
) == ItemType
::Module { "../" }
else { "" }
;
2493 "<script>window.sidebarCurrent = {{\
2498 name
= it
.name
.as_ref().map(|x
| &x
[..]).unwrap_or(""),
2499 ty
= shortty(it
).to_static_str(),
2502 // there is no sidebar-items.js beyond the crate root path
2503 // FIXME maybe dynamic crate loading can be merged here
2505 try
!(write
!(fmt
, "<script defer src=\"{path}sidebar-items.js\"></script>",
2513 impl<'a
> fmt
::Display
for Source
<'a
> {
2514 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
2515 let Source(s
) = *self;
2516 let lines
= s
.lines().count();
2518 let mut tmp
= lines
;
2523 try
!(write
!(fmt
, "<pre class=\"line-numbers\">"));
2524 for i
in 1..lines
+ 1 {
2525 try
!(write
!(fmt
, "<span id=\"{0}\">{0:1$}</span>\n", i
, cols
));
2527 try
!(write
!(fmt
, "</pre>"));
2528 try
!(write
!(fmt
, "{}", highlight
::highlight(s
, None
, None
)));
2533 fn item_macro(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2534 t
: &clean
::Macro
) -> fmt
::Result
{
2535 try
!(w
.write_str(&highlight
::highlight(&t
.source
,
2541 fn item_primitive(w
: &mut fmt
::Formatter
,
2543 _p
: &clean
::PrimitiveType
) -> fmt
::Result
{
2544 try
!(document(w
, it
));
2545 render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
)
2548 fn get_basic_keywords() -> &'
static str {
2549 "rust, rustlang, rust-lang"
2552 fn make_item_keywords(it
: &clean
::Item
) -> String
{
2553 format
!("{}, {}", get_basic_keywords(), it
.name
.as_ref().unwrap())
2556 fn get_index_search_type(item
: &clean
::Item
,
2557 parent
: Option
<String
>) -> Option
<IndexItemFunctionType
> {
2558 let decl
= match item
.inner
{
2559 clean
::FunctionItem(ref f
) => &f
.decl
,
2560 clean
::MethodItem(ref m
) => &m
.decl
,
2561 clean
::TyMethodItem(ref m
) => &m
.decl
,
2565 let mut inputs
= Vec
::new();
2567 // Consider `self` an argument as well.
2568 if let Some(name
) = parent
{
2569 inputs
.push(Type { name: Some(name.into_ascii_lowercase()) }
);
2572 inputs
.extend(&mut decl
.inputs
.values
.iter().map(|arg
| {
2573 get_index_type(&arg
.type_
)
2576 let output
= match decl
.output
{
2577 clean
::FunctionRetTy
::Return(ref return_type
) => Some(get_index_type(return_type
)),
2581 Some(IndexItemFunctionType { inputs: inputs, output: output }
)
2584 fn get_index_type(clean_type
: &clean
::Type
) -> Type
{
2585 Type { name: get_index_type_name(clean_type).map(|s| s.into_ascii_lowercase()) }
2588 fn get_index_type_name(clean_type
: &clean
::Type
) -> Option
<String
> {
2590 clean
::ResolvedPath { ref path, .. }
=> {
2591 let segments
= &path
.segments
;
2592 Some(segments
[segments
.len() - 1].name
.clone())
2594 clean
::Generic(ref s
) => Some(s
.clone()),
2595 clean
::Primitive(ref p
) => Some(format
!("{:?}", p
)),
2596 clean
::BorrowedRef { ref type_, .. }
=> get_index_type_name(type_
),
2597 // FIXME: add all from clean::Type.
2602 pub fn cache() -> Arc
<Cache
> {
2603 CACHE_KEY
.with(|c
| c
.borrow().clone())