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
;
55 use serialize
::json
::ToJson
;
60 use rustc
::util
::nodemap
::NodeSet
;
65 use html
::escape
::Escape
;
66 use html
::format
::{TyParamBounds, WhereClause, href, AbiSpace}
;
67 use html
::format
::{VisSpace, Method, UnsafetySpace, MutableSpace}
;
69 use html
::item_type
::ItemType
;
71 use html
::markdown
::Markdown
;
74 /// A pair of name and its optional document.
75 pub type NameDoc
= (String
, Option
<String
>);
77 /// Major driving force in all rustdoc rendering. This contains information
78 /// about where in the tree-like hierarchy rendering is occurring and controls
79 /// how the current page is being rendered.
81 /// It is intended that this context is a lightweight object which can be fairly
82 /// easily cloned because it is cloned per work-job (about once per item in the
86 /// Current hierarchy of components leading down to what's currently being
88 pub current
: Vec
<String
>,
89 /// String representation of how to get back to the root path of the 'doc/'
90 /// folder in terms of a relative URL.
91 pub root_path
: String
,
92 /// The path to the crate root source minus the file name.
93 /// Used for simplifying paths to the highlighted source code files.
94 pub src_root
: PathBuf
,
95 /// The current destination folder of where HTML artifacts should be placed.
96 /// This changes as the context descends into the module hierarchy.
98 /// This describes the layout of each page, and is not modified after
99 /// creation of the context (contains info like the favicon and added html).
100 pub layout
: layout
::Layout
,
101 /// This flag indicates whether [src] links should be generated or not. If
102 /// the source files are present in the html rendering, then this will be
104 pub include_sources
: bool
,
105 /// A flag, which when turned off, will render pages which redirect to the
106 /// real location of an item. This is used to allow external links to
107 /// publicly reused items to redirect to the right location.
108 pub render_redirect_pages
: bool
,
109 /// All the passes that were run on this crate.
110 pub passes
: HashSet
<String
>,
113 /// Indicates where an external crate can be found.
114 pub enum ExternalLocation
{
115 /// Remote URL root of the external crate
117 /// This external crate can be found in the local doc/ folder
119 /// The external crate could not be found.
123 /// Metadata about an implementor of a trait.
124 pub struct Implementor
{
125 pub def_id
: ast
::DefId
,
126 pub generics
: clean
::Generics
,
127 pub trait_
: clean
::Type
,
128 pub for_
: clean
::Type
,
129 pub stability
: Option
<clean
::Stability
>,
130 pub polarity
: Option
<clean
::ImplPolarity
>,
133 /// Metadata about implementations for a type.
136 pub impl_
: clean
::Impl
,
137 pub dox
: Option
<String
>,
138 pub stability
: Option
<clean
::Stability
>,
142 fn trait_did(&self) -> Option
<ast
::DefId
> {
143 self.impl_
.trait_
.as_ref().and_then(|tr
| {
144 if let clean
::ResolvedPath { did, .. }
= *tr {Some(did)}
else {None}
149 /// This cache is used to store information about the `clean::Crate` being
150 /// rendered in order to provide more useful documentation. This contains
151 /// information like all implementors of a trait, all traits a type implements,
152 /// documentation for all known traits, etc.
154 /// This structure purposefully does not implement `Clone` because it's intended
155 /// to be a fairly large and expensive structure to clone. Instead this adheres
156 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
157 /// rendering threads.
160 /// Mapping of typaram ids to the name of the type parameter. This is used
161 /// when pretty-printing a type (so pretty printing doesn't have to
162 /// painfully maintain a context like this)
163 pub typarams
: HashMap
<ast
::DefId
, String
>,
165 /// Maps a type id to all known implementations for that type. This is only
166 /// recognized for intra-crate `ResolvedPath` types, and is used to print
167 /// out extra documentation on the page of an enum/struct.
169 /// The values of the map are a list of implementations and documentation
170 /// found on that implementation.
171 pub impls
: HashMap
<ast
::DefId
, Vec
<Impl
>>,
173 /// Maintains a mapping of local crate node ids to the fully qualified name
174 /// and "short type description" of that node. This is used when generating
175 /// URLs when a type is being linked to. External paths are not located in
176 /// this map because the `External` type itself has all the information
178 pub paths
: HashMap
<ast
::DefId
, (Vec
<String
>, ItemType
)>,
180 /// Similar to `paths`, but only holds external paths. This is only used for
181 /// generating explicit hyperlinks to other crates.
182 pub external_paths
: HashMap
<ast
::DefId
, Vec
<String
>>,
184 /// This map contains information about all known traits of this crate.
185 /// Implementations of a crate should inherit the documentation of the
186 /// parent trait if no extra documentation is specified, and default methods
187 /// should show up in documentation about trait implementations.
188 pub traits
: HashMap
<ast
::DefId
, clean
::Trait
>,
190 /// When rendering traits, it's often useful to be able to list all
191 /// implementors of the trait, and this mapping is exactly, that: a mapping
192 /// of trait ids to the list of known implementors of the trait
193 pub implementors
: HashMap
<ast
::DefId
, Vec
<Implementor
>>,
195 /// Cache of where external crate documentation can be found.
196 pub extern_locations
: HashMap
<ast
::CrateNum
, (String
, ExternalLocation
)>,
198 /// Cache of where documentation for primitives can be found.
199 pub primitive_locations
: HashMap
<clean
::PrimitiveType
, ast
::CrateNum
>,
201 /// Set of definitions which have been inlined from external crates.
202 pub inlined
: HashSet
<ast
::DefId
>,
204 // Private fields only used when initially crawling a crate to build a cache
207 parent_stack
: Vec
<ast
::DefId
>,
208 search_index
: Vec
<IndexItem
>,
211 public_items
: NodeSet
,
212 deref_trait_did
: Option
<ast
::DefId
>,
214 // In rare case where a structure is defined in one module but implemented
215 // in another, if the implementing module is parsed before defining module,
216 // then the fully qualified name of the structure isn't presented in `paths`
217 // yet when its implementation methods are being indexed. Caches such methods
218 // and their parent id here and indexes them at the end of crate parsing.
219 orphan_methods
: Vec
<(ast
::NodeId
, clean
::Item
)>,
222 /// Helper struct to render all source code to HTML pages
223 struct SourceCollector
<'a
> {
226 /// Processed source-file paths
227 seen
: HashSet
<String
>,
228 /// Root destination to place all HTML output into
232 /// Wrapper struct to render the source code of a file. This will do things like
233 /// adding line numbers to the left-hand side.
234 struct Source
<'a
>(&'a
str);
236 // Helper structs for rendering items/sidebars and carrying along contextual
239 #[derive(Copy, Clone)]
242 item
: &'a clean
::Item
,
245 struct Sidebar
<'a
> { cx: &'a Context, item: &'a clean::Item, }
247 /// Struct representing one entry in the JS search index. These are all emitted
248 /// by hand to a large JS file at the end of cache-creation.
254 parent
: Option
<ast
::DefId
>,
255 search_type
: Option
<IndexItemFunctionType
>,
258 /// A type used for the search index.
260 name
: Option
<String
>,
263 impl fmt
::Display
for Type
{
264 /// Formats type as {name: $name}.
265 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
266 // Wrapping struct fmt should never call us when self.name is None,
267 // but just to be safe we write `null` in that case.
269 Some(ref n
) => write
!(f
, "{{\"name\":\"{}\"}}", n
),
270 None
=> write
!(f
, "null")
275 /// Full type of functions/methods in the search index.
276 struct IndexItemFunctionType
{
281 impl fmt
::Display
for IndexItemFunctionType
{
282 /// Formats a full fn type as a JSON {inputs: [Type], outputs: Type/null}.
283 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
284 // If we couldn't figure out a type, just write `null`.
285 if self.inputs
.iter().any(|ref i
| i
.name
.is_none()) ||
286 (self.output
.is_some() && self.output
.as_ref().unwrap().name
.is_none()) {
287 return write
!(f
, "null")
290 let inputs
: Vec
<String
> = self.inputs
.iter().map(|ref t
| {
293 try
!(write
!(f
, "{{\"inputs\":[{}],\"output\":", inputs
.connect(",")));
296 Some(ref t
) => try
!(write
!(f
, "{}", t
)),
297 None
=> try
!(write
!(f
, "null"))
300 Ok(try
!(write
!(f
, "}}")))
304 // TLS keys used to carry information around during rendering.
306 thread_local
!(static CACHE_KEY
: RefCell
<Arc
<Cache
>> = Default
::default());
307 thread_local
!(pub static CURRENT_LOCATION_KEY
: RefCell
<Vec
<String
>> =
308 RefCell
::new(Vec
::new()));
310 /// Generates the documentation for `crate` into the directory `dst`
311 pub fn run(mut krate
: clean
::Crate
,
312 external_html
: &ExternalHtml
,
314 passes
: HashSet
<String
>) -> io
::Result
<()> {
315 let src_root
= match krate
.src
.parent() {
316 Some(p
) => p
.to_path_buf(),
317 None
=> PathBuf
::new(),
319 let mut cx
= Context
{
324 root_path
: String
::new(),
325 layout
: layout
::Layout
{
326 logo
: "".to_string(),
327 favicon
: "".to_string(),
328 external_html
: external_html
.clone(),
329 krate
: krate
.name
.clone(),
330 playground_url
: "".to_string(),
332 include_sources
: true,
333 render_redirect_pages
: false,
336 try
!(mkdir(&cx
.dst
));
338 // Crawl the crate attributes looking for attributes which control how we're
339 // going to emit HTML
340 let default: &[_
] = &[];
341 match krate
.module
.as_ref().map(|m
| m
.doc_list().unwrap_or(default)) {
345 clean
::NameValue(ref x
, ref s
)
346 if "html_favicon_url" == *x
=> {
347 cx
.layout
.favicon
= s
.to_string();
349 clean
::NameValue(ref x
, ref s
)
350 if "html_logo_url" == *x
=> {
351 cx
.layout
.logo
= s
.to_string();
353 clean
::NameValue(ref x
, ref s
)
354 if "html_playground_url" == *x
=> {
355 cx
.layout
.playground_url
= s
.to_string();
356 markdown
::PLAYGROUND_KRATE
.with(|slot
| {
357 if slot
.borrow().is_none() {
358 let name
= krate
.name
.clone();
359 *slot
.borrow_mut() = Some(Some(name
));
364 if "html_no_source" == *x
=> {
365 cx
.include_sources
= false;
374 // Crawl the crate to build various caches used for the output
375 let analysis
= ::ANALYSISKEY
.with(|a
| a
.clone());
376 let analysis
= analysis
.borrow();
377 let public_items
= analysis
.as_ref().map(|a
| a
.public_items
.clone());
378 let public_items
= public_items
.unwrap_or(NodeSet());
379 let paths
: HashMap
<ast
::DefId
, (Vec
<String
>, ItemType
)> =
380 analysis
.as_ref().map(|a
| {
381 let paths
= a
.external_paths
.borrow_mut().take().unwrap();
382 paths
.into_iter().map(|(k
, (v
, t
))| (k
, (v
, ItemType
::from_type_kind(t
)))).collect()
383 }).unwrap_or(HashMap
::new());
384 let mut cache
= Cache
{
385 impls
: HashMap
::new(),
386 external_paths
: paths
.iter().map(|(&k
, v
)| (k
, v
.0.clone()))
389 implementors
: HashMap
::new(),
391 parent_stack
: Vec
::new(),
392 search_index
: Vec
::new(),
393 extern_locations
: HashMap
::new(),
394 primitive_locations
: HashMap
::new(),
395 remove_priv
: cx
.passes
.contains("strip-private"),
397 public_items
: public_items
,
398 orphan_methods
: Vec
::new(),
399 traits
: mem
::replace(&mut krate
.external_traits
, HashMap
::new()),
400 deref_trait_did
: analysis
.as_ref().and_then(|a
| a
.deref_trait_did
),
401 typarams
: analysis
.as_ref().map(|a
| {
402 a
.external_typarams
.borrow_mut().take().unwrap()
403 }).unwrap_or(HashMap
::new()),
404 inlined
: analysis
.as_ref().map(|a
| {
405 a
.inlined
.borrow_mut().take().unwrap()
406 }).unwrap_or(HashSet
::new()),
409 // Cache where all our extern crates are located
410 for &(n
, ref e
) in &krate
.externs
{
411 cache
.extern_locations
.insert(n
, (e
.name
.clone(),
412 extern_location(e
, &cx
.dst
)));
413 let did
= ast
::DefId { krate: n, node: ast::CRATE_NODE_ID }
;
414 cache
.paths
.insert(did
, (vec
![e
.name
.to_string()], ItemType
::Module
));
417 // Cache where all known primitives have their documentation located.
419 // Favor linking to as local extern as possible, so iterate all crates in
420 // reverse topological order.
421 for &(n
, ref e
) in krate
.externs
.iter().rev() {
422 for &prim
in &e
.primitives
{
423 cache
.primitive_locations
.insert(prim
, n
);
426 for &prim
in &krate
.primitives
{
427 cache
.primitive_locations
.insert(prim
, ast
::LOCAL_CRATE
);
430 cache
.stack
.push(krate
.name
.clone());
431 krate
= cache
.fold_crate(krate
);
433 // Build our search index
434 let index
= try
!(build_index(&krate
, &mut cache
));
436 // Freeze the cache now that the index has been built. Put an Arc into TLS
437 // for future parallelization opportunities
438 let cache
= Arc
::new(cache
);
439 CACHE_KEY
.with(|v
| *v
.borrow_mut() = cache
.clone());
440 CURRENT_LOCATION_KEY
.with(|s
| s
.borrow_mut().clear());
442 try
!(write_shared(&cx
, &krate
, &*cache
, index
));
443 let krate
= try
!(render_sources(&mut cx
, krate
));
445 // And finally render the whole crate's documentation
449 fn build_index(krate
: &clean
::Crate
, cache
: &mut Cache
) -> io
::Result
<String
> {
450 // Build the search index from the collected metadata
451 let mut nodeid_to_pathid
= HashMap
::new();
452 let mut pathid_to_nodeid
= Vec
::new();
454 let Cache
{ ref mut search_index
,
456 ref mut paths
, .. } = *cache
;
458 // Attach all orphan methods to the type's definition if the type
459 // has since been learned.
460 for &(pid
, ref item
) in orphan_methods
{
461 let did
= ast_util
::local_def(pid
);
462 match paths
.get(&did
) {
463 Some(&(ref fqp
, _
)) => {
464 search_index
.push(IndexItem
{
466 name
: item
.name
.clone().unwrap(),
467 path
: fqp
[..fqp
.len() - 1].connect("::"),
468 desc
: shorter(item
.doc_value()),
477 // Reduce `NodeId` in paths into smaller sequential numbers,
478 // and prune the paths that do not appear in the index.
479 for item
in &*search_index
{
482 if !nodeid_to_pathid
.contains_key(&nodeid
) {
483 let pathid
= pathid_to_nodeid
.len();
484 nodeid_to_pathid
.insert(nodeid
, pathid
);
485 pathid_to_nodeid
.push(nodeid
);
491 assert_eq
!(nodeid_to_pathid
.len(), pathid_to_nodeid
.len());
494 // Collect the index into a string
495 let mut w
= io
::Cursor
::new(Vec
::new());
496 try
!(write
!(&mut w
, r
#"searchIndex['{}'] = {{"items":["#, krate.name));
498 let mut lastpath
= "".to_string();
499 for (i
, item
) in cache
.search_index
.iter().enumerate() {
500 // Omit the path if it is same to that of the prior item.
502 if lastpath
== item
.path
{
505 lastpath
= item
.path
.to_string();
510 try
!(write
!(&mut w
, ","));
512 try
!(write
!(&mut w
, r
#"[{},"{}","{}",{}"#,
513 item
.ty
as usize, item
.name
, path
,
514 item
.desc
.to_json().to_string()));
517 let pathid
= *nodeid_to_pathid
.get(&nodeid
).unwrap();
518 try
!(write
!(&mut w
, ",{}", pathid
));
520 None
=> try
!(write
!(&mut w
, ",null"))
522 match item
.search_type
{
523 Some(ref t
) => try
!(write
!(&mut w
, ",{}", t
)),
524 None
=> try
!(write
!(&mut w
, ",null"))
526 try
!(write
!(&mut w
, "]"));
529 try
!(write
!(&mut w
, r
#"],"paths":["#));
531 for (i
, &did
) in pathid_to_nodeid
.iter().enumerate() {
532 let &(ref fqp
, short
) = cache
.paths
.get(&did
).unwrap();
534 try
!(write
!(&mut w
, ","));
536 try
!(write
!(&mut w
, r
#"[{},"{}"]"#,
537 short
as usize, *fqp
.last().unwrap()));
540 try
!(write
!(&mut w
, "]}};"));
542 Ok(String
::from_utf8(w
.into_inner()).unwrap())
545 fn write_shared(cx
: &Context
,
546 krate
: &clean
::Crate
,
548 search_index
: String
) -> io
::Result
<()> {
549 // Write out the shared files. Note that these are shared among all rustdoc
550 // docs placed in the output directory, so this needs to be a synchronized
551 // operation with respect to all other rustdocs running around.
552 try
!(mkdir(&cx
.dst
));
553 let _lock
= ::flock
::Lock
::new(&cx
.dst
.join(".lock"));
555 // Add all the static files. These may already exist, but we just
556 // overwrite them anyway to make sure that they're fresh and up-to-date.
557 try
!(write(cx
.dst
.join("jquery.js"),
558 include_bytes
!("static/jquery-2.1.0.min.js")));
559 try
!(write(cx
.dst
.join("main.js"), include_bytes
!("static/main.js")));
560 try
!(write(cx
.dst
.join("playpen.js"), include_bytes
!("static/playpen.js")));
561 try
!(write(cx
.dst
.join("main.css"), include_bytes
!("static/main.css")));
562 try
!(write(cx
.dst
.join("normalize.css"),
563 include_bytes
!("static/normalize.css")));
564 try
!(write(cx
.dst
.join("FiraSans-Regular.woff"),
565 include_bytes
!("static/FiraSans-Regular.woff")));
566 try
!(write(cx
.dst
.join("FiraSans-Medium.woff"),
567 include_bytes
!("static/FiraSans-Medium.woff")));
568 try
!(write(cx
.dst
.join("Heuristica-Italic.woff"),
569 include_bytes
!("static/Heuristica-Italic.woff")));
570 try
!(write(cx
.dst
.join("SourceSerifPro-Regular.woff"),
571 include_bytes
!("static/SourceSerifPro-Regular.woff")));
572 try
!(write(cx
.dst
.join("SourceSerifPro-Bold.woff"),
573 include_bytes
!("static/SourceSerifPro-Bold.woff")));
574 try
!(write(cx
.dst
.join("SourceCodePro-Regular.woff"),
575 include_bytes
!("static/SourceCodePro-Regular.woff")));
576 try
!(write(cx
.dst
.join("SourceCodePro-Semibold.woff"),
577 include_bytes
!("static/SourceCodePro-Semibold.woff")));
579 fn collect(path
: &Path
, krate
: &str,
580 key
: &str) -> io
::Result
<Vec
<String
>> {
581 let mut ret
= Vec
::new();
583 for line
in BufReader
::new(try
!(File
::open(path
))).lines() {
584 let line
= try
!(line
);
585 if !line
.starts_with(key
) {
588 if line
.starts_with(&format
!("{}['{}']", key
, krate
)) {
591 ret
.push(line
.to_string());
597 // Update the search index
598 let dst
= cx
.dst
.join("search-index.js");
599 let all_indexes
= try
!(collect(&dst
, &krate
.name
, "searchIndex"));
600 let mut w
= try
!(File
::create(&dst
));
601 try
!(writeln
!(&mut w
, "var searchIndex = {{}};"));
602 try
!(writeln
!(&mut w
, "{}", search_index
));
603 for index
in &all_indexes
{
604 try
!(writeln
!(&mut w
, "{}", *index
));
606 try
!(writeln
!(&mut w
, "initSearch(searchIndex);"));
608 // Update the list of all implementors for traits
609 let dst
= cx
.dst
.join("implementors");
611 for (&did
, imps
) in &cache
.implementors
{
612 // Private modules can leak through to this phase of rustdoc, which
613 // could contain implementations for otherwise private types. In some
614 // rare cases we could find an implementation for an item which wasn't
615 // indexed, so we just skip this step in that case.
617 // FIXME: this is a vague explanation for why this can't be a `get`, in
618 // theory it should be...
619 let &(ref remote_path
, remote_item_type
) = match cache
.paths
.get(&did
) {
624 let mut mydst
= dst
.clone();
625 for part
in &remote_path
[..remote_path
.len() - 1] {
629 mydst
.push(&format
!("{}.{}.js",
630 remote_item_type
.to_static_str(),
631 remote_path
[remote_path
.len() - 1]));
632 let all_implementors
= try
!(collect(&mydst
, &krate
.name
,
635 try
!(mkdir(mydst
.parent().unwrap()));
636 let mut f
= BufWriter
::new(try
!(File
::create(&mydst
)));
637 try
!(writeln
!(&mut f
, "(function() {{var implementors = {{}};"));
639 for implementor
in &all_implementors
{
640 try
!(write
!(&mut f
, "{}", *implementor
));
643 try
!(write
!(&mut f
, r
"implementors['{}'] = [", krate
.name
));
645 // If the trait and implementation are in the same crate, then
646 // there's no need to emit information about it (there's inlining
647 // going on). If they're in different crates then the crate defining
648 // the trait will be interested in our implementation.
649 if imp
.def_id
.krate
== did
.krate { continue }
650 try
!(write
!(&mut f
, r
#""impl{} {}{} for {}","#,
652 if imp
.polarity
== Some(clean
::ImplPolarity
::Negative
) { "!" }
else { "" }
,
653 imp
.trait_
, imp
.for_
));
655 try
!(writeln
!(&mut f
, r
"];"));
656 try
!(writeln
!(&mut f
, "{}", r
"
657 if (window.register_implementors) {
658 window.register_implementors(implementors);
660 window.pending_implementors = implementors;
663 try
!(writeln
!(&mut f
, r
"}})()"));
668 fn render_sources(cx
: &mut Context
,
669 krate
: clean
::Crate
) -> io
::Result
<clean
::Crate
> {
670 info
!("emitting source files");
671 let dst
= cx
.dst
.join("src");
673 let dst
= dst
.join(&krate
.name
);
675 let mut folder
= SourceCollector
{
677 seen
: HashSet
::new(),
680 // skip all invalid spans
681 folder
.seen
.insert("".to_string());
682 Ok(folder
.fold_crate(krate
))
685 /// Writes the entire contents of a string to a destination, not attempting to
686 /// catch any errors.
687 fn write(dst
: PathBuf
, contents
: &[u8]) -> io
::Result
<()> {
688 try
!(File
::create(&dst
)).write_all(contents
)
691 /// Makes a directory on the filesystem, failing the thread if an error occurs and
692 /// skipping if the directory already exists.
693 fn mkdir(path
: &Path
) -> io
::Result
<()> {
701 /// Returns a documentation-level item type from the item.
702 fn shortty(item
: &clean
::Item
) -> ItemType
{
703 ItemType
::from_item(item
)
706 /// Takes a path to a source file and cleans the path to it. This canonicalizes
707 /// things like ".." to components which preserve the "top down" hierarchy of a
708 /// static HTML tree. Each component in the cleaned path will be passed as an
709 /// argument to `f`. The very last component of the path (ie the file name) will
710 /// be passed to `f` if `keep_filename` is true, and ignored otherwise.
711 // FIXME (#9639): The closure should deal with &[u8] instead of &str
712 // FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths
713 fn clean_srcpath
<F
>(src_root
: &Path
, p
: &Path
, keep_filename
: bool
, mut f
: F
) where
716 // make it relative, if possible
717 let p
= p
.relative_from(src_root
).unwrap_or(p
);
719 let mut iter
= p
.iter().map(|x
| x
.to_str().unwrap()).peekable();
720 while let Some(c
) = iter
.next() {
721 if !keep_filename
&& iter
.peek().is_none() {
733 /// Attempts to find where an external crate is located, given that we're
734 /// rendering in to the specified source destination.
735 fn extern_location(e
: &clean
::ExternalCrate
, dst
: &Path
) -> ExternalLocation
{
736 // See if there's documentation generated into the local directory
737 let local_location
= dst
.join(&e
.name
);
738 if local_location
.is_dir() {
742 // Failing that, see if there's an attribute specifying where to find this
744 for attr
in &e
.attrs
{
746 clean
::List(ref x
, ref list
) if "doc" == *x
=> {
749 clean
::NameValue(ref x
, ref s
)
750 if "html_root_url" == *x
=> {
751 if s
.ends_with("/") {
752 return Remote(s
.to_string());
754 return Remote(format
!("{}/", s
));
764 // Well, at least we tried.
768 impl<'a
> DocFolder
for SourceCollector
<'a
> {
769 fn fold_item(&mut self, item
: clean
::Item
) -> Option
<clean
::Item
> {
770 // If we're including source files, and we haven't seen this file yet,
771 // then we need to render it out to the filesystem
772 if self.cx
.include_sources
&& !self.seen
.contains(&item
.source
.filename
) {
774 // If it turns out that we couldn't read this file, then we probably
775 // can't read any of the files (generating html output from json or
776 // something like that), so just don't include sources for the
777 // entire crate. The other option is maintaining this mapping on a
778 // per-file basis, but that's probably not worth it...
780 .include_sources
= match self.emit_source(&item
.source
.filename
) {
783 println
!("warning: source code was requested to be rendered, \
784 but processing `{}` had an error: {}",
785 item
.source
.filename
, e
);
786 println
!(" skipping rendering of source code");
790 self.seen
.insert(item
.source
.filename
.clone());
793 self.fold_item_recur(item
)
797 impl<'a
> SourceCollector
<'a
> {
798 /// Renders the given filename into its corresponding HTML source file.
799 fn emit_source(&mut self, filename
: &str) -> io
::Result
<()> {
800 let p
= PathBuf
::from(filename
);
802 // If we couldn't open this file, then just returns because it
803 // probably means that it's some standard library macro thing and we
804 // can't have the source to it anyway.
805 let mut contents
= Vec
::new();
806 match File
::open(&p
).and_then(|mut f
| f
.read_to_end(&mut contents
)) {
808 // macros from other libraries get special filenames which we can
810 Err(..) if filename
.starts_with("<") &&
811 filename
.ends_with("macros>") => return Ok(()),
812 Err(e
) => return Err(e
)
814 let contents
= str::from_utf8(&contents
).unwrap();
816 // Remove the utf-8 BOM if any
817 let contents
= if contents
.starts_with("\u{feff}") {
823 // Create the intermediate directories
824 let mut cur
= self.dst
.clone();
825 let mut root_path
= String
::from_str("../../");
826 clean_srcpath(&self.cx
.src_root
, &p
, false, |component
| {
828 mkdir(&cur
).unwrap();
829 root_path
.push_str("../");
832 let mut fname
= p
.file_name().expect("source has no filename")
835 cur
.push(&fname
[..]);
836 let mut w
= BufWriter
::new(try
!(File
::create(&cur
)));
838 let title
= format
!("{} -- source", cur
.file_name().unwrap()
840 let desc
= format
!("Source to the Rust file `{}`.", filename
);
841 let page
= layout
::Page
{
844 root_path
: &root_path
,
846 keywords
: get_basic_keywords(),
848 try
!(layout
::render(&mut w
, &self.cx
.layout
,
849 &page
, &(""), &Source(contents
)));
855 impl DocFolder
for Cache
{
856 fn fold_item(&mut self, item
: clean
::Item
) -> Option
<clean
::Item
> {
857 // If this is a private module, we don't want it in the search index.
858 let orig_privmod
= match item
.inner
{
859 clean
::ModuleItem(..) => {
860 let prev
= self.privmod
;
861 self.privmod
= prev
|| (self.remove_priv
&& item
.visibility
!= Some(ast
::Public
));
867 // Register any generics to their corresponding string. This is used
868 // when pretty-printing types
870 clean
::StructItem(ref s
) => self.generics(&s
.generics
),
871 clean
::EnumItem(ref e
) => self.generics(&e
.generics
),
872 clean
::FunctionItem(ref f
) => self.generics(&f
.generics
),
873 clean
::TypedefItem(ref t
) => self.generics(&t
.generics
),
874 clean
::TraitItem(ref t
) => self.generics(&t
.generics
),
875 clean
::ImplItem(ref i
) => self.generics(&i
.generics
),
876 clean
::TyMethodItem(ref i
) => self.generics(&i
.generics
),
877 clean
::MethodItem(ref i
) => self.generics(&i
.generics
),
878 clean
::ForeignFunctionItem(ref f
) => self.generics(&f
.generics
),
882 // Propagate a trait methods' documentation to all implementors of the
884 if let clean
::TraitItem(ref t
) = item
.inner
{
885 self.traits
.insert(item
.def_id
, t
.clone());
888 // Collect all the implementors of traits.
889 if let clean
::ImplItem(ref i
) = item
.inner
{
891 Some(clean
::ResolvedPath{ did, .. }
) => {
892 self.implementors
.entry(did
).or_insert(vec
![]).push(Implementor
{
894 generics
: i
.generics
.clone(),
895 trait_
: i
.trait_
.as_ref().unwrap().clone(),
896 for_
: i
.for_
.clone(),
897 stability
: item
.stability
.clone(),
898 polarity
: i
.polarity
.clone(),
901 Some(..) | None
=> {}
905 // Index this method for searching later on
906 if let Some(ref s
) = item
.name
{
907 let (parent
, is_method
) = match item
.inner
{
908 clean
::AssociatedTypeItem(..) |
909 clean
::AssociatedConstItem(..) |
910 clean
::TyMethodItem(..) |
911 clean
::StructFieldItem(..) |
912 clean
::VariantItem(..) => {
913 ((Some(*self.parent_stack
.last().unwrap()),
914 Some(&self.stack
[..self.stack
.len() - 1])),
917 clean
::MethodItem(..) => {
918 if self.parent_stack
.is_empty() {
919 ((None
, None
), false)
921 let last
= self.parent_stack
.last().unwrap();
923 let path
= match self.paths
.get(&did
) {
924 Some(&(_
, ItemType
::Trait
)) =>
925 Some(&self.stack
[..self.stack
.len() - 1]),
926 // The current stack not necessarily has correlation
927 // for where the type was defined. On the other
928 // hand, `paths` always has the right
929 // information if present.
930 Some(&(ref fqp
, ItemType
::Struct
)) |
931 Some(&(ref fqp
, ItemType
::Enum
)) =>
932 Some(&fqp
[..fqp
.len() - 1]),
933 Some(..) => Some(&*self.stack
),
936 ((Some(*last
), path
), true)
939 _
=> ((None
, Some(&*self.stack
)), false)
941 let hidden_field
= match item
.inner
{
942 clean
::StructFieldItem(clean
::HiddenStructField
) => true,
947 (parent
, Some(path
)) if is_method
|| (!self.privmod
&& !hidden_field
) => {
948 // Needed to determine `self` type.
949 let parent_basename
= self.parent_stack
.first().and_then(|parent
| {
950 match self.paths
.get(parent
) {
951 Some(&(ref fqp
, _
)) => Some(fqp
[fqp
.len() - 1].clone()),
956 self.search_index
.push(IndexItem
{
959 path
: path
.connect("::").to_string(),
960 desc
: shorter(item
.doc_value()),
962 search_type
: get_index_search_type(&item
, parent_basename
),
965 (Some(parent
), None
) if is_method
|| (!self.privmod
&& !hidden_field
)=> {
966 if ast_util
::is_local(parent
) {
967 // We have a parent, but we don't know where they're
968 // defined yet. Wait for later to index this item.
969 self.orphan_methods
.push((parent
.node
, item
.clone()))
976 // Keep track of the fully qualified path for this item.
977 let pushed
= if item
.name
.is_some() {
978 let n
= item
.name
.as_ref().unwrap();
980 self.stack
.push(n
.to_string());
985 clean
::StructItem(..) | clean
::EnumItem(..) |
986 clean
::TypedefItem(..) | clean
::TraitItem(..) |
987 clean
::FunctionItem(..) | clean
::ModuleItem(..) |
988 clean
::ForeignFunctionItem(..) if !self.privmod
=> {
989 // Reexported items mean that the same id can show up twice
990 // in the rustdoc ast that we're looking at. We know,
991 // however, that a reexported item doesn't show up in the
992 // `public_items` map, so we can skip inserting into the
993 // paths map if there was already an entry present and we're
994 // not a public item.
995 let id
= item
.def_id
.node
;
996 if !self.paths
.contains_key(&item
.def_id
) ||
997 !ast_util
::is_local(item
.def_id
) ||
998 self.public_items
.contains(&id
) {
999 self.paths
.insert(item
.def_id
,
1000 (self.stack
.clone(), shortty(&item
)));
1003 // link variants to their parent enum because pages aren't emitted
1005 clean
::VariantItem(..) if !self.privmod
=> {
1006 let mut stack
= self.stack
.clone();
1008 self.paths
.insert(item
.def_id
, (stack
, ItemType
::Enum
));
1011 clean
::PrimitiveItem(..) if item
.visibility
.is_some() => {
1012 self.paths
.insert(item
.def_id
, (self.stack
.clone(),
1019 // Maintain the parent stack
1020 let parent_pushed
= match item
.inner
{
1021 clean
::TraitItem(..) | clean
::EnumItem(..) | clean
::StructItem(..) => {
1022 self.parent_stack
.push(item
.def_id
);
1025 clean
::ImplItem(ref i
) => {
1027 clean
::ResolvedPath{ did, .. }
=> {
1028 self.parent_stack
.push(did
);
1032 match t
.primitive_type() {
1034 let did
= ast_util
::local_def(prim
.to_node_id());
1035 self.parent_stack
.push(did
);
1046 // Once we've recursively found all the generics, then hoard off all the
1047 // implementations elsewhere
1048 let ret
= match self.fold_item_recur(item
) {
1051 clean
::Item{ attrs, inner: clean::ImplItem(i), .. }
=> {
1052 // extract relevant documentation for this impl
1053 let dox
= match attrs
.into_iter().find(|a
| {
1055 clean
::NameValue(ref x
, _
)
1062 Some(clean
::NameValue(_
, dox
)) => Some(dox
),
1063 Some(..) | None
=> None
,
1066 // Figure out the id of this impl. This may map to a
1067 // primitive rather than always to a struct/enum.
1068 let did
= match i
.for_
{
1069 clean
::ResolvedPath { did, .. }
|
1070 clean
::BorrowedRef
{
1071 type_
: box clean
::ResolvedPath { did, .. }
, ..
1077 t
.primitive_type().and_then(|t
| {
1078 self.primitive_locations
.get(&t
).map(|n
| {
1079 let id
= t
.to_node_id();
1080 ast
::DefId { krate: *n, node: id }
1086 if let Some(did
) = did
{
1087 self.impls
.entry(did
).or_insert(vec
![]).push(Impl
{
1090 stability
: item
.stability
.clone(),
1103 if pushed { self.stack.pop().unwrap(); }
1104 if parent_pushed { self.parent_stack.pop().unwrap(); }
1105 self.privmod
= orig_privmod
;
1111 fn generics(&mut self, generics
: &clean
::Generics
) {
1112 for typ
in &generics
.type_params
{
1113 self.typarams
.insert(typ
.did
, typ
.name
.clone());
1119 /// Recurse in the directory structure and change the "root path" to make
1120 /// sure it always points to the top (relatively)
1121 fn recurse
<T
, F
>(&mut self, s
: String
, f
: F
) -> T
where
1122 F
: FnOnce(&mut Context
) -> T
,
1125 panic
!("Unexpected empty destination: {:?}", self.current
);
1127 let prev
= self.dst
.clone();
1129 self.root_path
.push_str("../");
1130 self.current
.push(s
);
1132 info
!("Recursing into {}", self.dst
.display());
1134 mkdir(&self.dst
).unwrap();
1137 info
!("Recursed; leaving {}", self.dst
.display());
1139 // Go back to where we were at
1141 let len
= self.root_path
.len();
1142 self.root_path
.truncate(len
- 3);
1143 self.current
.pop().unwrap();
1148 /// Main method for rendering a crate.
1150 /// This currently isn't parallelized, but it'd be pretty easy to add
1151 /// parallelization to this function.
1152 fn krate(self, mut krate
: clean
::Crate
) -> io
::Result
<()> {
1153 let mut item
= match krate
.module
.take() {
1155 None
=> return Ok(())
1157 item
.name
= Some(krate
.name
);
1159 // render the crate documentation
1160 let mut work
= vec
!((self, item
));
1163 Some((mut cx
, item
)) => try
!(cx
.item(item
, |cx
, item
| {
1164 work
.push((cx
.clone(), item
));
1173 /// Non-parallelized version of rendering an item. This will take the input
1174 /// item, render its contents, and then invoke the specified closure with
1175 /// all sub-items which need to be rendered.
1177 /// The rendering driver uses this closure to queue up more work.
1178 fn item
<F
>(&mut self, item
: clean
::Item
, mut f
: F
) -> io
::Result
<()> where
1179 F
: FnMut(&mut Context
, clean
::Item
),
1181 fn render(w
: File
, cx
: &Context
, it
: &clean
::Item
,
1182 pushname
: bool
) -> io
::Result
<()> {
1183 // A little unfortunate that this is done like this, but it sure
1184 // does make formatting *a lot* nicer.
1185 CURRENT_LOCATION_KEY
.with(|slot
| {
1186 *slot
.borrow_mut() = cx
.current
.clone();
1189 let mut title
= cx
.current
.connect("::");
1191 if !title
.is_empty() {
1192 title
.push_str("::");
1194 title
.push_str(it
.name
.as_ref().unwrap());
1196 title
.push_str(" - Rust");
1197 let tyname
= shortty(it
).to_static_str();
1198 let is_crate
= match it
.inner
{
1199 clean
::ModuleItem(clean
::Module { items: _, is_crate: true }
) => true,
1202 let desc
= if is_crate
{
1203 format
!("API documentation for the Rust `{}` crate.",
1206 format
!("API documentation for the Rust `{}` {} in crate `{}`.",
1207 it
.name
.as_ref().unwrap(), tyname
, cx
.layout
.krate
)
1209 let keywords
= make_item_keywords(it
);
1210 let page
= layout
::Page
{
1212 root_path
: &cx
.root_path
,
1215 keywords
: &keywords
,
1218 markdown
::reset_headers();
1220 // We have a huge number of calls to write, so try to alleviate some
1221 // of the pain by using a buffered writer instead of invoking the
1222 // write syscall all the time.
1223 let mut writer
= BufWriter
::new(w
);
1224 if !cx
.render_redirect_pages
{
1225 try
!(layout
::render(&mut writer
, &cx
.layout
, &page
,
1226 &Sidebar{ cx: cx, item: it }
,
1227 &Item{ cx: cx, item: it }
));
1229 let mut url
= repeat("../").take(cx
.current
.len())
1230 .collect
::<String
>();
1231 match cache().paths
.get(&it
.def_id
) {
1232 Some(&(ref names
, _
)) => {
1233 for name
in &names
[..names
.len() - 1] {
1237 url
.push_str(&item_path(it
));
1238 try
!(layout
::redirect(&mut writer
, &url
));
1246 // Private modules may survive the strip-private pass if they
1247 // contain impls for public types. These modules can also
1248 // contain items such as publicly reexported structures.
1250 // External crates will provide links to these structures, so
1251 // these modules are recursed into, but not rendered normally (a
1252 // flag on the context).
1253 if !self.render_redirect_pages
{
1254 self.render_redirect_pages
= self.ignore_private_item(&item
);
1258 // modules are special because they add a namespace. We also need to
1259 // recurse into the items of the module as well.
1260 clean
::ModuleItem(..) => {
1261 let name
= item
.name
.as_ref().unwrap().to_string();
1262 let mut item
= Some(item
);
1263 self.recurse(name
, |this
| {
1264 let item
= item
.take().unwrap();
1265 let dst
= this
.dst
.join("index.html");
1266 let dst
= try
!(File
::create(&dst
));
1267 try
!(render(dst
, this
, &item
, false));
1269 let m
= match item
.inner
{
1270 clean
::ModuleItem(m
) => m
,
1274 // render sidebar-items.js used throughout this module
1276 let items
= this
.build_sidebar_items(&m
);
1277 let js_dst
= this
.dst
.join("sidebar-items.js");
1278 let mut js_out
= BufWriter
::new(try
!(File
::create(&js_dst
)));
1279 try
!(write
!(&mut js_out
, "initSidebarItems({});",
1280 json
::as_json(&items
)));
1283 for item
in m
.items
{
1290 // Things which don't have names (like impls) don't get special
1291 // pages dedicated to them.
1292 _
if item
.name
.is_some() => {
1293 let dst
= self.dst
.join(&item_path(&item
));
1294 let dst
= try
!(File
::create(&dst
));
1295 render(dst
, self, &item
, true)
1302 fn build_sidebar_items(&self, m
: &clean
::Module
) -> BTreeMap
<String
, Vec
<NameDoc
>> {
1303 // BTreeMap instead of HashMap to get a sorted output
1304 let mut map
= BTreeMap
::new();
1305 for item
in &m
.items
{
1306 if self.ignore_private_item(item
) { continue }
1308 let short
= shortty(item
).to_static_str();
1309 let myname
= match item
.name
{
1311 Some(ref s
) => s
.to_string(),
1313 let short
= short
.to_string();
1314 map
.entry(short
).or_insert(vec
![])
1315 .push((myname
, Some(plain_summary_line(item
.doc_value()))));
1318 for (_
, items
) in &mut map
{
1324 fn ignore_private_item(&self, it
: &clean
::Item
) -> bool
{
1326 clean
::ModuleItem(ref m
) => {
1327 (m
.items
.is_empty() &&
1328 it
.doc_value().is_none() &&
1329 it
.visibility
!= Some(ast
::Public
)) ||
1330 (self.passes
.contains("strip-private") && it
.visibility
!= Some(ast
::Public
))
1332 clean
::PrimitiveItem(..) => it
.visibility
!= Some(ast
::Public
),
1339 fn ismodule(&self) -> bool
{
1340 match self.item
.inner
{
1341 clean
::ModuleItem(..) => true, _
=> false
1345 /// Generate a url appropriate for an `href` attribute back to the source of
1348 /// The url generated, when clicked, will redirect the browser back to the
1349 /// original source code.
1351 /// If `None` is returned, then a source link couldn't be generated. This
1352 /// may happen, for example, with externally inlined items where the source
1353 /// of their crate documentation isn't known.
1354 fn href(&self, cx
: &Context
) -> Option
<String
> {
1355 let href
= if self.item
.source
.loline
== self.item
.source
.hiline
{
1356 format
!("{}", self.item
.source
.loline
)
1358 format
!("{}-{}", self.item
.source
.loline
, self.item
.source
.hiline
)
1361 // First check to see if this is an imported macro source. In this case
1362 // we need to handle it specially as cross-crate inlined macros have...
1364 let imported_macro_from
= match self.item
.inner
{
1365 clean
::MacroItem(ref m
) => m
.imported_from
.as_ref(),
1368 if let Some(krate
) = imported_macro_from
{
1369 let cache
= cache();
1370 let root
= cache
.extern_locations
.values().find(|&&(ref n
, _
)| {
1373 let root
= match root
{
1374 Some(&Remote(ref s
)) => s
.to_string(),
1375 Some(&Local
) => self.cx
.root_path
.clone(),
1376 None
| Some(&Unknown
) => return None
,
1378 Some(format
!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1",
1381 name
= self.item
.name
.as_ref().unwrap()))
1383 // If this item is part of the local crate, then we're guaranteed to
1384 // know the span, so we plow forward and generate a proper url. The url
1385 // has anchors for the line numbers that we're linking to.
1386 } else if ast_util
::is_local(self.item
.def_id
) {
1387 let mut path
= Vec
::new();
1388 clean_srcpath(&cx
.src_root
, Path
::new(&self.item
.source
.filename
),
1390 path
.push(component
.to_string());
1392 Some(format
!("{root}src/{krate}/{path}.html#{href}",
1393 root
= self.cx
.root_path
,
1394 krate
= self.cx
.layout
.krate
,
1395 path
= path
.connect("/"),
1398 // If this item is not part of the local crate, then things get a little
1399 // trickier. We don't actually know the span of the external item, but
1400 // we know that the documentation on the other end knows the span!
1402 // In this case, we generate a link to the *documentation* for this type
1403 // in the original crate. There's an extra URL parameter which says that
1404 // we want to go somewhere else, and the JS on the destination page will
1405 // pick it up and instantly redirect the browser to the source code.
1407 // If we don't know where the external documentation for this crate is
1408 // located, then we return `None`.
1410 let cache
= cache();
1411 let path
= &cache
.external_paths
[&self.item
.def_id
];
1412 let root
= match cache
.extern_locations
[&self.item
.def_id
.krate
] {
1413 (_
, Remote(ref s
)) => s
.to_string(),
1414 (_
, Local
) => self.cx
.root_path
.clone(),
1415 (_
, Unknown
) => return None
,
1417 Some(format
!("{root}{path}/{file}?gotosrc={goto}",
1419 path
= path
[..path
.len() - 1].connect("/"),
1420 file
= item_path(self.item
),
1421 goto
= self.item
.def_id
.node
))
1427 impl<'a
> fmt
::Display
for Item
<'a
> {
1428 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
1429 // Write the breadcrumb trail header for the top
1430 try
!(write
!(fmt
, "\n<h1 class='fqn'><span class='in-band'>"));
1431 match self.item
.inner
{
1432 clean
::ModuleItem(ref m
) => if m
.is_crate
{
1433 try
!(write
!(fmt
, "Crate "));
1435 try
!(write
!(fmt
, "Module "));
1437 clean
::FunctionItem(..) => try
!(write
!(fmt
, "Function ")),
1438 clean
::TraitItem(..) => try
!(write
!(fmt
, "Trait ")),
1439 clean
::StructItem(..) => try
!(write
!(fmt
, "Struct ")),
1440 clean
::EnumItem(..) => try
!(write
!(fmt
, "Enum ")),
1441 clean
::PrimitiveItem(..) => try
!(write
!(fmt
, "Primitive Type ")),
1444 let is_primitive
= match self.item
.inner
{
1445 clean
::PrimitiveItem(..) => true,
1449 let cur
= &self.cx
.current
;
1450 let amt
= if self.ismodule() { cur.len() - 1 }
else { cur.len() }
;
1451 for (i
, component
) in cur
.iter().enumerate().take(amt
) {
1452 try
!(write
!(fmt
, "<a href='{}index.html'>{}</a>::<wbr>",
1453 repeat("../").take(cur
.len() - i
- 1)
1454 .collect
::<String
>(),
1458 try
!(write
!(fmt
, "<a class='{}' href=''>{}</a>",
1459 shortty(self.item
), self.item
.name
.as_ref().unwrap()));
1461 try
!(write
!(fmt
, "</span>")); // in-band
1462 try
!(write
!(fmt
, "<span class='out-of-band'>"));
1464 r
##"<span id='render-detail'>
1465 <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
1466 [<span class='inner'>−</span>]
1472 // When this item is part of a `pub use` in a downstream crate, the
1473 // [src] link in the downstream documentation will actually come back to
1474 // this page, and this link will be auto-clicked. The `id` attribute is
1475 // used to find the link to auto-click.
1476 if self.cx
.include_sources
&& !is_primitive
{
1477 match self.href(self.cx
) {
1479 try
!(write
!(fmt
, "<a id='src-{}' class='srclink' \
1480 href='{}' title='{}'>[src]</a>",
1481 self.item
.def_id
.node
, l
, "goto source code"));
1487 try
!(write
!(fmt
, "</span>")); // out-of-band
1489 try
!(write
!(fmt
, "</h1>\n"));
1491 match self.item
.inner
{
1492 clean
::ModuleItem(ref m
) => {
1493 item_module(fmt
, self.cx
, self.item
, &m
.items
)
1495 clean
::FunctionItem(ref f
) | clean
::ForeignFunctionItem(ref f
) =>
1496 item_function(fmt
, self.item
, f
),
1497 clean
::TraitItem(ref t
) => item_trait(fmt
, self.cx
, self.item
, t
),
1498 clean
::StructItem(ref s
) => item_struct(fmt
, self.item
, s
),
1499 clean
::EnumItem(ref e
) => item_enum(fmt
, self.item
, e
),
1500 clean
::TypedefItem(ref t
) => item_typedef(fmt
, self.item
, t
),
1501 clean
::MacroItem(ref m
) => item_macro(fmt
, self.item
, m
),
1502 clean
::PrimitiveItem(ref p
) => item_primitive(fmt
, self.item
, p
),
1503 clean
::StaticItem(ref i
) | clean
::ForeignStaticItem(ref i
) =>
1504 item_static(fmt
, self.item
, i
),
1505 clean
::ConstantItem(ref c
) => item_constant(fmt
, self.item
, c
),
1511 fn item_path(item
: &clean
::Item
) -> String
{
1513 clean
::ModuleItem(..) => {
1514 format
!("{}/index.html", item
.name
.as_ref().unwrap())
1517 format
!("{}.{}.html",
1518 shortty(item
).to_static_str(),
1519 *item
.name
.as_ref().unwrap())
1524 fn full_path(cx
: &Context
, item
: &clean
::Item
) -> String
{
1525 let mut s
= cx
.current
.connect("::");
1527 s
.push_str(item
.name
.as_ref().unwrap());
1531 fn shorter
<'a
>(s
: Option
<&'a
str>) -> String
{
1533 Some(s
) => s
.lines().take_while(|line
|{
1534 (*line
).chars().any(|chr
|{
1535 !chr
.is_whitespace()
1537 }).collect
::<Vec
<_
>>().connect("\n"),
1538 None
=> "".to_string()
1543 fn plain_summary_line(s
: Option
<&str>) -> String
{
1544 let line
= shorter(s
).replace("\n", " ");
1545 markdown
::plain_summary_line(&line
[..])
1548 fn document(w
: &mut fmt
::Formatter
, item
: &clean
::Item
) -> fmt
::Result
{
1549 if let Some(s
) = short_stability(item
, true) {
1550 try
!(write
!(w
, "<div class='stability'>{}</div>", s
));
1552 if let Some(s
) = item
.doc_value() {
1553 try
!(write
!(w
, "<div class='docblock'>{}</div>", Markdown(s
)));
1558 fn item_module(w
: &mut fmt
::Formatter
, cx
: &Context
,
1559 item
: &clean
::Item
, items
: &[clean
::Item
]) -> fmt
::Result
{
1560 try
!(document(w
, item
));
1562 let mut indices
= (0..items
.len()).filter(|i
| {
1563 !cx
.ignore_private_item(&items
[*i
])
1564 }).collect
::<Vec
<usize>>();
1566 // the order of item types in the listing
1567 fn reorder(ty
: ItemType
) -> u8 {
1569 ItemType
::ExternCrate
=> 0,
1570 ItemType
::Import
=> 1,
1571 ItemType
::Primitive
=> 2,
1572 ItemType
::Module
=> 3,
1573 ItemType
::Macro
=> 4,
1574 ItemType
::Struct
=> 5,
1575 ItemType
::Enum
=> 6,
1576 ItemType
::Constant
=> 7,
1577 ItemType
::Static
=> 8,
1578 ItemType
::Trait
=> 9,
1579 ItemType
::Function
=> 10,
1580 ItemType
::Typedef
=> 12,
1585 fn cmp(i1
: &clean
::Item
, i2
: &clean
::Item
, idx1
: usize, idx2
: usize) -> Ordering
{
1586 let ty1
= shortty(i1
);
1587 let ty2
= shortty(i2
);
1589 return (reorder(ty1
), idx1
).cmp(&(reorder(ty2
), idx2
))
1591 let s1
= i1
.stability
.as_ref().map(|s
| s
.level
);
1592 let s2
= i2
.stability
.as_ref().map(|s
| s
.level
);
1594 (Some(attr
::Unstable
), Some(attr
::Stable
)) => return Ordering
::Greater
,
1595 (Some(attr
::Stable
), Some(attr
::Unstable
)) => return Ordering
::Less
,
1598 i1
.name
.cmp(&i2
.name
)
1601 indices
.sort_by(|&i1
, &i2
| cmp(&items
[i1
], &items
[i2
], i1
, i2
));
1603 debug
!("{:?}", indices
);
1604 let mut curty
= None
;
1605 for &idx
in &indices
{
1606 let myitem
= &items
[idx
];
1608 let myty
= Some(shortty(myitem
));
1609 if curty
== Some(ItemType
::ExternCrate
) && myty
== Some(ItemType
::Import
) {
1610 // Put `extern crate` and `use` re-exports in the same section.
1612 } else if myty
!= curty
{
1613 if curty
.is_some() {
1614 try
!(write
!(w
, "</table>"));
1617 let (short
, name
) = match myty
.unwrap() {
1618 ItemType
::ExternCrate
|
1619 ItemType
::Import
=> ("reexports", "Reexports"),
1620 ItemType
::Module
=> ("modules", "Modules"),
1621 ItemType
::Struct
=> ("structs", "Structs"),
1622 ItemType
::Enum
=> ("enums", "Enums"),
1623 ItemType
::Function
=> ("functions", "Functions"),
1624 ItemType
::Typedef
=> ("types", "Type Definitions"),
1625 ItemType
::Static
=> ("statics", "Statics"),
1626 ItemType
::Constant
=> ("constants", "Constants"),
1627 ItemType
::Trait
=> ("traits", "Traits"),
1628 ItemType
::Impl
=> ("impls", "Implementations"),
1629 ItemType
::TyMethod
=> ("tymethods", "Type Methods"),
1630 ItemType
::Method
=> ("methods", "Methods"),
1631 ItemType
::StructField
=> ("fields", "Struct Fields"),
1632 ItemType
::Variant
=> ("variants", "Variants"),
1633 ItemType
::Macro
=> ("macros", "Macros"),
1634 ItemType
::Primitive
=> ("primitives", "Primitive Types"),
1635 ItemType
::AssociatedType
=> ("associated-types", "Associated Types"),
1636 ItemType
::AssociatedConst
=> ("associated-consts", "Associated Constants"),
1639 "<h2 id='{id}' class='section-header'>\
1640 <a href=\"#{id}\">{name}</a></h2>\n<table>",
1641 id
= short
, name
= name
));
1644 match myitem
.inner
{
1645 clean
::ExternCrateItem(ref name
, ref src
) => {
1648 try
!(write
!(w
, "<tr><td><code>{}extern crate {} as {};",
1649 VisSpace(myitem
.visibility
),
1654 try
!(write
!(w
, "<tr><td><code>{}extern crate {};",
1655 VisSpace(myitem
.visibility
), name
))
1658 try
!(write
!(w
, "</code></td></tr>"));
1661 clean
::ImportItem(ref import
) => {
1662 try
!(write
!(w
, "<tr><td><code>{}{}</code></td></tr>",
1663 VisSpace(myitem
.visibility
), *import
));
1667 if myitem
.name
.is_none() { continue }
1668 let stab_docs
= if let Some(s
) = short_stability(myitem
, false) {
1674 <tr class='{stab} module-item'>
1675 <td><a class='{class}' href='{href}'
1676 title='{title}'>{name}</a></td>
1677 <td class='docblock short'>
1682 name
= *myitem
.name
.as_ref().unwrap(),
1683 stab_docs
= stab_docs
,
1684 docs
= Markdown(&shorter(myitem
.doc_value())),
1685 class
= shortty(myitem
),
1686 stab
= myitem
.stability_class(),
1687 href
= item_path(myitem
),
1688 title
= full_path(cx
, myitem
)));
1693 write
!(w
, "</table>")
1696 fn short_stability(item
: &clean
::Item
, show_reason
: bool
) -> Option
<String
> {
1697 item
.stability
.as_ref().and_then(|stab
| {
1698 let reason
= if show_reason
&& !stab
.reason
.is_empty() {
1699 format
!(": {}", stab
.reason
)
1703 let text
= if !stab
.deprecated_since
.is_empty() {
1704 let since
= if show_reason
{
1705 format
!(" since {}", Escape(&stab
.deprecated_since
))
1709 format
!("Deprecated{}{}", since
, Markdown(&reason
))
1710 } else if stab
.level
== attr
::Unstable
{
1711 format
!("Unstable{}", Markdown(&reason
))
1715 Some(format
!("<em class='stab {}'>{}</em>",
1716 item
.stability_class(), text
))
1720 struct Initializer
<'a
>(&'a
str);
1722 impl<'a
> fmt
::Display
for Initializer
<'a
> {
1723 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1724 let Initializer(s
) = *self;
1725 if s
.is_empty() { return Ok(()); }
1726 try
!(write
!(f
, "<code> = </code>"));
1727 write
!(f
, "<code>{}</code>", s
)
1731 fn item_constant(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1732 c
: &clean
::Constant
) -> fmt
::Result
{
1733 try
!(write
!(w
, "<pre class='rust const'>{vis}const \
1734 {name}: {typ}{init}</pre>",
1735 vis
= VisSpace(it
.visibility
),
1736 name
= it
.name
.as_ref().unwrap(),
1738 init
= Initializer(&c
.expr
)));
1742 fn item_static(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1743 s
: &clean
::Static
) -> fmt
::Result
{
1744 try
!(write
!(w
, "<pre class='rust static'>{vis}static {mutability}\
1745 {name}: {typ}{init}</pre>",
1746 vis
= VisSpace(it
.visibility
),
1747 mutability
= MutableSpace(s
.mutability
),
1748 name
= it
.name
.as_ref().unwrap(),
1750 init
= Initializer(&s
.expr
)));
1754 fn item_function(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1755 f
: &clean
::Function
) -> fmt
::Result
{
1756 try
!(write
!(w
, "<pre class='rust fn'>{vis}{unsafety}{abi}fn \
1757 {name}{generics}{decl}{where_clause}</pre>",
1758 vis
= VisSpace(it
.visibility
),
1759 unsafety
= UnsafetySpace(f
.unsafety
),
1760 abi
= AbiSpace(f
.abi
),
1761 name
= it
.name
.as_ref().unwrap(),
1762 generics
= f
.generics
,
1763 where_clause
= WhereClause(&f
.generics
),
1768 fn item_trait(w
: &mut fmt
::Formatter
, cx
: &Context
, it
: &clean
::Item
,
1769 t
: &clean
::Trait
) -> fmt
::Result
{
1770 let mut bounds
= String
::new();
1771 if !t
.bounds
.is_empty() {
1772 if !bounds
.is_empty() {
1775 bounds
.push_str(": ");
1776 for (i
, p
) in t
.bounds
.iter().enumerate() {
1777 if i
> 0 { bounds.push_str(" + "); }
1778 bounds
.push_str(&format
!("{}", *p
));
1782 // Output the trait definition
1783 try
!(write
!(w
, "<pre class='rust trait'>{}{}trait {}{}{}{} ",
1784 VisSpace(it
.visibility
),
1785 UnsafetySpace(t
.unsafety
),
1786 it
.name
.as_ref().unwrap(),
1789 WhereClause(&t
.generics
)));
1791 let types
= t
.items
.iter().filter(|m
| {
1792 match m
.inner { clean::AssociatedTypeItem(..) => true, _ => false }
1793 }).collect
::<Vec
<_
>>();
1794 let consts
= t
.items
.iter().filter(|m
| {
1795 match m
.inner { clean::AssociatedConstItem(..) => true, _ => false }
1796 }).collect
::<Vec
<_
>>();
1797 let required
= t
.items
.iter().filter(|m
| {
1798 match m
.inner { clean::TyMethodItem(_) => true, _ => false }
1799 }).collect
::<Vec
<_
>>();
1800 let provided
= t
.items
.iter().filter(|m
| {
1801 match m
.inner { clean::MethodItem(_) => true, _ => false }
1802 }).collect
::<Vec
<_
>>();
1804 if t
.items
.is_empty() {
1805 try
!(write
!(w
, "{{ }}"));
1807 try
!(write
!(w
, "{{\n"));
1809 try
!(write
!(w
, " "));
1810 try
!(render_assoc_item(w
, t
, AssocItemLink
::Anchor
));
1811 try
!(write
!(w
, ";\n"));
1813 if !types
.is_empty() && !consts
.is_empty() {
1814 try
!(w
.write_str("\n"));
1817 try
!(write
!(w
, " "));
1818 try
!(render_assoc_item(w
, t
, AssocItemLink
::Anchor
));
1819 try
!(write
!(w
, ";\n"));
1821 if !consts
.is_empty() && !required
.is_empty() {
1822 try
!(w
.write_str("\n"));
1824 for m
in &required
{
1825 try
!(write
!(w
, " "));
1826 try
!(render_assoc_item(w
, m
, AssocItemLink
::Anchor
));
1827 try
!(write
!(w
, ";\n"));
1829 if !required
.is_empty() && !provided
.is_empty() {
1830 try
!(w
.write_str("\n"));
1832 for m
in &provided
{
1833 try
!(write
!(w
, " "));
1834 try
!(render_assoc_item(w
, m
, AssocItemLink
::Anchor
));
1835 try
!(write
!(w
, " {{ ... }}\n"));
1837 try
!(write
!(w
, "}}"));
1839 try
!(write
!(w
, "</pre>"));
1841 // Trait documentation
1842 try
!(document(w
, it
));
1844 fn trait_item(w
: &mut fmt
::Formatter
, m
: &clean
::Item
)
1846 try
!(write
!(w
, "<h3 id='{ty}.{name}' class='method stab {stab}'><code>",
1848 name
= *m
.name
.as_ref().unwrap(),
1849 stab
= m
.stability_class()));
1850 try
!(render_assoc_item(w
, m
, AssocItemLink
::Anchor
));
1851 try
!(write
!(w
, "</code></h3>"));
1852 try
!(document(w
, m
));
1856 if !types
.is_empty() {
1858 <h2 id='associated-types'>Associated Types</h2>
1859 <div class='methods'>
1862 try
!(trait_item(w
, *t
));
1864 try
!(write
!(w
, "</div>"));
1867 if !consts
.is_empty() {
1869 <h2 id='associated-const'>Associated Constants</h2>
1870 <div class='methods'>
1873 try
!(trait_item(w
, *t
));
1875 try
!(write
!(w
, "</div>"));
1878 // Output the documentation for each function individually
1879 if !required
.is_empty() {
1881 <h2 id='required-methods'>Required Methods</h2>
1882 <div class='methods'>
1884 for m
in &required
{
1885 try
!(trait_item(w
, *m
));
1887 try
!(write
!(w
, "</div>"));
1889 if !provided
.is_empty() {
1891 <h2 id='provided-methods'>Provided Methods</h2>
1892 <div class='methods'>
1894 for m
in &provided
{
1895 try
!(trait_item(w
, *m
));
1897 try
!(write
!(w
, "</div>"));
1900 // If there are methods directly on this trait object, render them here.
1901 try
!(render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
));
1903 let cache
= cache();
1905 <h2 id='implementors'>Implementors</h2>
1906 <ul class='item-list' id='implementors-list'>
1908 match cache
.implementors
.get(&it
.def_id
) {
1909 Some(implementors
) => {
1910 for i
in implementors
{
1911 try
!(writeln
!(w
, "<li><code>impl{} {} for {}{}</code></li>",
1912 i
.generics
, i
.trait_
, i
.for_
, WhereClause(&i
.generics
)));
1917 try
!(write
!(w
, "</ul>"));
1918 try
!(write
!(w
, r
#"<script type="text/javascript" async
1919 src="{root_path}/implementors/{path}/{ty}.{name}.js">
1921 root_path
= repeat("..").take(cx
.current
.len()).collect
::<Vec
<_
>>().connect("/"),
1922 path
= if ast_util
::is_local(it
.def_id
) {
1923 cx
.current
.connect("/")
1925 let path
= &cache
.external_paths
[&it
.def_id
];
1926 path
[..path
.len() - 1].connect("/")
1928 ty
= shortty(it
).to_static_str(),
1929 name
= *it
.name
.as_ref().unwrap()));
1933 fn assoc_const(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1934 ty
: &clean
::Type
, default: Option
<&String
>)
1936 try
!(write
!(w
, "const {}", it
.name
.as_ref().unwrap()));
1937 try
!(write
!(w
, ": {}", ty
));
1938 if let Some(default) = default {
1939 try
!(write
!(w
, " = {}", default));
1944 fn assoc_type(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1945 bounds
: &Vec
<clean
::TyParamBound
>,
1946 default: &Option
<clean
::Type
>)
1948 try
!(write
!(w
, "type {}", it
.name
.as_ref().unwrap()));
1949 if !bounds
.is_empty() {
1950 try
!(write
!(w
, ": {}", TyParamBounds(bounds
)))
1952 if let Some(ref default) = *default {
1953 try
!(write
!(w
, " = {}", default));
1958 fn render_assoc_item(w
: &mut fmt
::Formatter
, meth
: &clean
::Item
,
1959 link
: AssocItemLink
) -> fmt
::Result
{
1960 fn method(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
1961 unsafety
: ast
::Unsafety
, abi
: abi
::Abi
,
1962 g
: &clean
::Generics
, selfty
: &clean
::SelfTy
,
1963 d
: &clean
::FnDecl
, link
: AssocItemLink
) -> fmt
::Result
{
1964 use syntax
::abi
::Abi
;
1966 let name
= it
.name
.as_ref().unwrap();
1967 let anchor
= format
!("#{}.{}", shortty(it
), name
);
1968 let href
= match link
{
1969 AssocItemLink
::Anchor
=> anchor
,
1970 AssocItemLink
::GotoSource(did
) => {
1971 href(did
).map(|p
| format
!("{}{}", p
.0, anchor
)).unwrap_or(anchor
)
1974 write
!(w
, "{}{}fn <a href='{href}' class='fnname'>{name}</a>\
1975 {generics}{decl}{where_clause}",
1977 ast
::Unsafety
::Unsafe
=> "unsafe ",
1981 Abi
::Rust
=> String
::new(),
1982 a
=> format
!("extern {} ", a
.to_string())
1987 decl
= Method(selfty
, d
),
1988 where_clause
= WhereClause(g
))
1991 clean
::TyMethodItem(ref m
) => {
1992 method(w
, meth
, m
.unsafety
, m
.abi
, &m
.generics
, &m
.self_
, &m
.decl
,
1995 clean
::MethodItem(ref m
) => {
1996 method(w
, meth
, m
.unsafety
, m
.abi
, &m
.generics
, &m
.self_
, &m
.decl
,
1999 clean
::AssociatedConstItem(ref ty
, ref default) => {
2000 assoc_const(w
, meth
, ty
, default.as_ref())
2002 clean
::AssociatedTypeItem(ref bounds
, ref default) => {
2003 assoc_type(w
, meth
, bounds
, default)
2005 _
=> panic
!("render_assoc_item called on non-associated-item")
2009 fn item_struct(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2010 s
: &clean
::Struct
) -> fmt
::Result
{
2011 try
!(write
!(w
, "<pre class='rust struct'>"));
2012 try
!(render_attributes(w
, it
));
2013 try
!(render_struct(w
,
2020 try
!(write
!(w
, "</pre>"));
2022 try
!(document(w
, it
));
2023 let mut fields
= s
.fields
.iter().filter(|f
| {
2025 clean
::StructFieldItem(clean
::HiddenStructField
) => false,
2026 clean
::StructFieldItem(clean
::TypedStructField(..)) => true,
2030 if let doctree
::Plain
= s
.struct_type
{
2031 if fields
.peek().is_some() {
2032 try
!(write
!(w
, "<h2 class='fields'>Fields</h2>\n<table>"));
2033 for field
in fields
{
2034 try
!(write
!(w
, "<tr class='stab {stab}'>
2035 <td id='structfield.{name}'>\
2036 <code>{name}</code></td><td>",
2037 stab
= field
.stability_class(),
2038 name
= field
.name
.as_ref().unwrap()));
2039 try
!(document(w
, field
));
2040 try
!(write
!(w
, "</td></tr>"));
2042 try
!(write
!(w
, "</table>"));
2045 render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
)
2048 fn item_enum(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2049 e
: &clean
::Enum
) -> fmt
::Result
{
2050 try
!(write
!(w
, "<pre class='rust enum'>"));
2051 try
!(render_attributes(w
, it
));
2052 try
!(write
!(w
, "{}enum {}{}{}",
2053 VisSpace(it
.visibility
),
2054 it
.name
.as_ref().unwrap(),
2056 WhereClause(&e
.generics
)));
2057 if e
.variants
.is_empty() && !e
.variants_stripped
{
2058 try
!(write
!(w
, " {{}}"));
2060 try
!(write
!(w
, " {{\n"));
2061 for v
in &e
.variants
{
2062 try
!(write
!(w
, " "));
2063 let name
= v
.name
.as_ref().unwrap();
2065 clean
::VariantItem(ref var
) => {
2067 clean
::CLikeVariant
=> try
!(write
!(w
, "{}", name
)),
2068 clean
::TupleVariant(ref tys
) => {
2069 try
!(write
!(w
, "{}(", name
));
2070 for (i
, ty
) in tys
.iter().enumerate() {
2072 try
!(write
!(w
, ", "))
2074 try
!(write
!(w
, "{}", *ty
));
2076 try
!(write
!(w
, ")"));
2078 clean
::StructVariant(ref s
) => {
2079 try
!(render_struct(w
,
2091 try
!(write
!(w
, ",\n"));
2094 if e
.variants_stripped
{
2095 try
!(write
!(w
, " // some variants omitted\n"));
2097 try
!(write
!(w
, "}}"));
2099 try
!(write
!(w
, "</pre>"));
2101 try
!(document(w
, it
));
2102 if !e
.variants
.is_empty() {
2103 try
!(write
!(w
, "<h2 class='variants'>Variants</h2>\n<table>"));
2104 for variant
in &e
.variants
{
2105 try
!(write
!(w
, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
2106 name
= variant
.name
.as_ref().unwrap()));
2107 try
!(document(w
, variant
));
2108 match variant
.inner
{
2109 clean
::VariantItem(ref var
) => {
2111 clean
::StructVariant(ref s
) => {
2112 let fields
= s
.fields
.iter().filter(|f
| {
2114 clean
::StructFieldItem(ref t
) => match *t
{
2115 clean
::HiddenStructField
=> false,
2116 clean
::TypedStructField(..) => true,
2121 try
!(write
!(w
, "<h3 class='fields'>Fields</h3>\n
2123 for field
in fields
{
2124 try
!(write
!(w
, "<tr><td \
2125 id='variant.{v}.field.{f}'>\
2126 <code>{f}</code></td><td>",
2127 v
= variant
.name
.as_ref().unwrap(),
2128 f
= field
.name
.as_ref().unwrap()));
2129 try
!(document(w
, field
));
2130 try
!(write
!(w
, "</td></tr>"));
2132 try
!(write
!(w
, "</table>"));
2139 try
!(write
!(w
, "</td></tr>"));
2141 try
!(write
!(w
, "</table>"));
2144 try
!(render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
));
2148 fn render_attributes(w
: &mut fmt
::Formatter
, it
: &clean
::Item
) -> fmt
::Result
{
2149 for attr
in &it
.attrs
{
2151 clean
::Word(ref s
) if *s
== "must_use" => {
2152 try
!(write
!(w
, "#[{}]\n", s
));
2154 clean
::NameValue(ref k
, ref v
) if *k
== "must_use" => {
2155 try
!(write
!(w
, "#[{} = \"{}\"]\n", k
, v
));
2163 fn render_struct(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2164 g
: Option
<&clean
::Generics
>,
2165 ty
: doctree
::StructType
,
2166 fields
: &[clean
::Item
],
2168 structhead
: bool
) -> fmt
::Result
{
2169 try
!(write
!(w
, "{}{}{}",
2170 VisSpace(it
.visibility
),
2171 if structhead {"struct "}
else {""}
,
2172 it
.name
.as_ref().unwrap()));
2174 Some(g
) => try
!(write
!(w
, "{}{}", *g
, WhereClause(g
))),
2179 try
!(write
!(w
, " {{\n{}", tab
));
2180 let mut fields_stripped
= false;
2181 for field
in fields
{
2183 clean
::StructFieldItem(clean
::HiddenStructField
) => {
2184 fields_stripped
= true;
2186 clean
::StructFieldItem(clean
::TypedStructField(ref ty
)) => {
2187 try
!(write
!(w
, " {}{}: {},\n{}",
2188 VisSpace(field
.visibility
),
2189 field
.name
.as_ref().unwrap(),
2193 _
=> unreachable
!(),
2197 if fields_stripped
{
2198 try
!(write
!(w
, " // some fields omitted\n{}", tab
));
2200 try
!(write
!(w
, "}}"));
2202 doctree
::Tuple
| doctree
::Newtype
=> {
2203 try
!(write
!(w
, "("));
2204 for (i
, field
) in fields
.iter().enumerate() {
2206 try
!(write
!(w
, ", "));
2209 clean
::StructFieldItem(clean
::HiddenStructField
) => {
2210 try
!(write
!(w
, "_"))
2212 clean
::StructFieldItem(clean
::TypedStructField(ref ty
)) => {
2213 try
!(write
!(w
, "{}{}", VisSpace(field
.visibility
), *ty
))
2218 try
!(write
!(w
, ");"));
2221 try
!(write
!(w
, ";"));
2227 #[derive(Copy, Clone)]
2228 enum AssocItemLink
{
2230 GotoSource(ast
::DefId
),
2233 enum AssocItemRender
<'a
> {
2235 DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type }
,
2238 fn render_assoc_items(w
: &mut fmt
::Formatter
,
2240 what
: AssocItemRender
) -> fmt
::Result
{
2242 let v
= match c
.impls
.get(&it
) {
2244 None
=> return Ok(()),
2246 let (non_trait
, traits
): (Vec
<_
>, _
) = v
.iter().partition(|i
| {
2247 i
.impl_
.trait_
.is_none()
2249 if !non_trait
.is_empty() {
2250 let render_header
= match what
{
2251 AssocItemRender
::All
=> {
2252 try
!(write
!(w
, "<h2 id='methods'>Methods</h2>"));
2255 AssocItemRender
::DerefFor { trait_, type_ }
=> {
2256 try
!(write
!(w
, "<h2 id='deref-methods'>Methods from \
2257 {}<Target={}></h2>", trait_
, type_
));
2261 for i
in &non_trait
{
2262 try
!(render_impl(w
, i
, AssocItemLink
::Anchor
, render_header
));
2265 if let AssocItemRender
::DerefFor { .. }
= what
{
2268 if !traits
.is_empty() {
2269 let deref_impl
= traits
.iter().find(|t
| {
2270 match *t
.impl_
.trait_
.as_ref().unwrap() {
2271 clean
::ResolvedPath { did, .. }
=> {
2272 Some(did
) == c
.deref_trait_did
2277 if let Some(impl_
) = deref_impl
{
2278 try
!(render_deref_methods(w
, impl_
));
2280 try
!(write
!(w
, "<h2 id='implementations'>Trait \
2281 Implementations</h2>"));
2282 let (derived
, manual
): (Vec
<_
>, _
) = traits
.iter().partition(|i
| {
2286 let did
= i
.trait_did().unwrap();
2287 try
!(render_impl(w
, i
, AssocItemLink
::GotoSource(did
), true));
2289 if !derived
.is_empty() {
2290 try
!(write
!(w
, "<h3 id='derived_implementations'>\
2291 Derived Implementations \
2294 let did
= i
.trait_did().unwrap();
2295 try
!(render_impl(w
, i
, AssocItemLink
::GotoSource(did
), true));
2302 fn render_deref_methods(w
: &mut fmt
::Formatter
, impl_
: &Impl
) -> fmt
::Result
{
2303 let deref_type
= impl_
.impl_
.trait_
.as_ref().unwrap();
2304 let target
= impl_
.impl_
.items
.iter().filter_map(|item
| {
2306 clean
::TypedefItem(ref t
) => Some(&t
.type_
),
2310 let what
= AssocItemRender
::DerefFor { trait_: deref_type, type_: target }
;
2312 clean
::ResolvedPath { did, .. }
=> render_assoc_items(w
, did
, what
),
2314 if let Some(prim
) = target
.primitive_type() {
2315 if let Some(c
) = cache().primitive_locations
.get(&prim
) {
2316 let did
= ast
::DefId { krate: *c, node: prim.to_node_id() }
;
2317 try
!(render_assoc_items(w
, did
, what
));
2325 fn render_impl(w
: &mut fmt
::Formatter
, i
: &Impl
, link
: AssocItemLink
,
2326 render_header
: bool
) -> fmt
::Result
{
2328 try
!(write
!(w
, "<h3 class='impl'><code>impl{} ",
2330 if let Some(clean
::ImplPolarity
::Negative
) = i
.impl_
.polarity
{
2331 try
!(write
!(w
, "!"));
2333 if let Some(ref ty
) = i
.impl_
.trait_
{
2334 try
!(write
!(w
, "{} for ", *ty
));
2336 try
!(write
!(w
, "{}{}</code></h3>", i
.impl_
.for_
,
2337 WhereClause(&i
.impl_
.generics
)));
2338 if let Some(ref dox
) = i
.dox
{
2339 try
!(write
!(w
, "<div class='docblock'>{}</div>", Markdown(dox
)));
2343 fn doctraititem(w
: &mut fmt
::Formatter
, item
: &clean
::Item
,
2344 link
: AssocItemLink
) -> fmt
::Result
{
2346 clean
::MethodItem(..) | clean
::TyMethodItem(..) => {
2347 try
!(write
!(w
, "<h4 id='method.{}' class='{}'><code>",
2348 *item
.name
.as_ref().unwrap(),
2350 try
!(render_assoc_item(w
, item
, link
));
2351 try
!(write
!(w
, "</code></h4>\n"));
2353 clean
::TypedefItem(ref tydef
) => {
2354 let name
= item
.name
.as_ref().unwrap();
2355 try
!(write
!(w
, "<h4 id='assoc_type.{}' class='{}'><code>",
2358 try
!(write
!(w
, "type {} = {}", name
, tydef
.type_
));
2359 try
!(write
!(w
, "</code></h4>\n"));
2361 clean
::AssociatedConstItem(ref ty
, ref default) => {
2362 let name
= item
.name
.as_ref().unwrap();
2363 try
!(write
!(w
, "<h4 id='assoc_const.{}' class='{}'><code>",
2364 *name
, shortty(item
)));
2365 try
!(assoc_const(w
, item
, ty
, default.as_ref()));
2366 try
!(write
!(w
, "</code></h4>\n"));
2368 clean
::ConstantItem(ref c
) => {
2369 let name
= item
.name
.as_ref().unwrap();
2370 try
!(write
!(w
, "<h4 id='assoc_const.{}' class='{}'><code>",
2371 *name
, shortty(item
)));
2372 try
!(assoc_const(w
, item
, &c
.type_
, Some(&c
.expr
)));
2373 try
!(write
!(w
, "</code></h4>\n"));
2375 clean
::AssociatedTypeItem(ref bounds
, ref default) => {
2376 let name
= item
.name
.as_ref().unwrap();
2377 try
!(write
!(w
, "<h4 id='assoc_type.{}' class='{}'><code>",
2380 try
!(assoc_type(w
, item
, bounds
, default));
2381 try
!(write
!(w
, "</code></h4>\n"));
2383 _
=> panic
!("can't make docs for trait item with name {:?}", item
.name
)
2385 if let AssocItemLink
::Anchor
= link
{
2392 try
!(write
!(w
, "<div class='impl-items'>"));
2393 for trait_item
in i
.impl_
.items
.iter() {
2394 try
!(doctraititem(w
, trait_item
, link
));
2397 fn render_default_items(w
: &mut fmt
::Formatter
,
2400 i
: &clean
::Impl
) -> fmt
::Result
{
2401 for trait_item
in &t
.items
{
2402 let n
= trait_item
.name
.clone();
2403 match i
.items
.iter().find(|m
| { m.name == n }
) {
2404 Some(..) => continue,
2408 try
!(doctraititem(w
, trait_item
, AssocItemLink
::GotoSource(did
)));
2413 // If we've implemented a trait, then also emit documentation for all
2414 // default methods which weren't overridden in the implementation block.
2415 // FIXME: this also needs to be done for associated types, whenever defaults
2417 if let Some(clean
::ResolvedPath { did, .. }
) = i
.impl_
.trait_
{
2418 if let Some(t
) = cache().traits
.get(&did
) {
2419 try
!(render_default_items(w
, did
, t
, &i
.impl_
));
2422 try
!(write
!(w
, "</div>"));
2426 fn item_typedef(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2427 t
: &clean
::Typedef
) -> fmt
::Result
{
2428 try
!(write
!(w
, "<pre class='rust typedef'>type {}{} = {};</pre>",
2429 it
.name
.as_ref().unwrap(),
2436 impl<'a
> fmt
::Display
for Sidebar
<'a
> {
2437 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
2440 let parentlen
= cx
.current
.len() - if it
.is_mod() {1}
else {0}
;
2442 // the sidebar is designed to display sibling functions, modules and
2443 // other miscellaneous informations. since there are lots of sibling
2444 // items (and that causes quadratic growth in large modules),
2445 // we refactor common parts into a shared JavaScript file per module.
2446 // still, we don't move everything into JS because we want to preserve
2447 // as much HTML as possible in order to allow non-JS-enabled browsers
2448 // to navigate the documentation (though slightly inefficiently).
2450 try
!(write
!(fmt
, "<p class='location'>"));
2451 for (i
, name
) in cx
.current
.iter().take(parentlen
).enumerate() {
2453 try
!(write
!(fmt
, "::<wbr>"));
2455 try
!(write
!(fmt
, "<a href='{}index.html'>{}</a>",
2456 &cx
.root_path
[..(cx
.current
.len() - i
- 1) * 3],
2459 try
!(write
!(fmt
, "</p>"));
2461 // sidebar refers to the enclosing module, not this module
2462 let relpath
= if shortty(it
) == ItemType
::Module { "../" }
else { "" }
;
2464 "<script>window.sidebarCurrent = {{\
2469 name
= it
.name
.as_ref().map(|x
| &x
[..]).unwrap_or(""),
2470 ty
= shortty(it
).to_static_str(),
2473 // there is no sidebar-items.js beyond the crate root path
2474 // FIXME maybe dynamic crate loading can be merged here
2476 try
!(write
!(fmt
, "<script defer src=\"{path}sidebar-items.js\"></script>",
2484 impl<'a
> fmt
::Display
for Source
<'a
> {
2485 fn fmt(&self, fmt
: &mut fmt
::Formatter
) -> fmt
::Result
{
2486 let Source(s
) = *self;
2487 let lines
= s
.lines().count();
2489 let mut tmp
= lines
;
2494 try
!(write
!(fmt
, "<pre class=\"line-numbers\">"));
2495 for i
in 1..lines
+ 1 {
2496 try
!(write
!(fmt
, "<span id=\"{0}\">{0:1$}</span>\n", i
, cols
));
2498 try
!(write
!(fmt
, "</pre>"));
2499 try
!(write
!(fmt
, "{}", highlight
::highlight(s
, None
, None
)));
2504 fn item_macro(w
: &mut fmt
::Formatter
, it
: &clean
::Item
,
2505 t
: &clean
::Macro
) -> fmt
::Result
{
2506 try
!(w
.write_str(&highlight
::highlight(&t
.source
,
2512 fn item_primitive(w
: &mut fmt
::Formatter
,
2514 _p
: &clean
::PrimitiveType
) -> fmt
::Result
{
2515 try
!(document(w
, it
));
2516 render_assoc_items(w
, it
.def_id
, AssocItemRender
::All
)
2519 fn get_basic_keywords() -> &'
static str {
2520 "rust, rustlang, rust-lang"
2523 fn make_item_keywords(it
: &clean
::Item
) -> String
{
2524 format
!("{}, {}", get_basic_keywords(), it
.name
.as_ref().unwrap())
2527 fn get_index_search_type(item
: &clean
::Item
,
2528 parent
: Option
<String
>) -> Option
<IndexItemFunctionType
> {
2529 let decl
= match item
.inner
{
2530 clean
::FunctionItem(ref f
) => &f
.decl
,
2531 clean
::MethodItem(ref m
) => &m
.decl
,
2532 clean
::TyMethodItem(ref m
) => &m
.decl
,
2536 let mut inputs
= Vec
::new();
2538 // Consider `self` an argument as well.
2539 if let Some(name
) = parent
{
2540 inputs
.push(Type { name: Some(name.into_ascii_lowercase()) }
);
2543 inputs
.extend(&mut decl
.inputs
.values
.iter().map(|arg
| {
2544 get_index_type(&arg
.type_
)
2547 let output
= match decl
.output
{
2548 clean
::FunctionRetTy
::Return(ref return_type
) => Some(get_index_type(return_type
)),
2552 Some(IndexItemFunctionType { inputs: inputs, output: output }
)
2555 fn get_index_type(clean_type
: &clean
::Type
) -> Type
{
2556 Type { name: get_index_type_name(clean_type).map(|s| s.into_ascii_lowercase()) }
2559 fn get_index_type_name(clean_type
: &clean
::Type
) -> Option
<String
> {
2561 clean
::ResolvedPath { ref path, .. }
=> {
2562 let segments
= &path
.segments
;
2563 Some(segments
[segments
.len() - 1].name
.clone())
2565 clean
::Generic(ref s
) => Some(s
.clone()),
2566 clean
::Primitive(ref p
) => Some(format
!("{:?}", p
)),
2567 clean
::BorrowedRef { ref type_, .. }
=> get_index_type_name(type_
),
2568 // FIXME: add all from clean::Type.
2573 pub fn cache() -> Arc
<Cache
> {
2574 CACHE_KEY
.with(|c
| c
.borrow().clone())