1 // Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Rustdoc's HTML Rendering module
13 //! This modules contains the bulk of the logic necessary for rendering a
14 //! rustdoc `clean::Crate` instance to a set of static HTML pages. This
15 //! rendering process is largely driven by the `format!` syntax extension to
16 //! perform all I/O into files and streams.
18 //! The rendering process is largely driven by the `Context` and `Cache`
19 //! structures. The cache is pre-populated by crawling the crate in question,
20 //! and then it is shared among the various rendering threads. The cache is meant
21 //! to be a fairly large structure not implementing `Clone` (because it's shared
22 //! among threads). The context, however, should be a lightweight structure. This
23 //! is cloned per-thread and contains information about what is currently being
26 //! In order to speed up rendering (mostly because of markdown rendering), the
27 //! rendering process has been parallelized. This parallelization is only
28 //! exposed through the `crate` method on the context, and then also from the
29 //! fact that the shared cache is stored in TLS (and must be accessed as such).
31 //! In addition to rendering the crate itself, this module is also responsible
32 //! for creating the corresponding search index and source file renderings.
33 //! These threads are not parallelized (they haven't been a bottleneck yet), and
34 //! both occur before the crate is rendered.
35 pub use self::ExternalLocation::*;
37 use std::ascii::AsciiExt;
38 use std::cell::RefCell;
39 use std::cmp::Ordering;
40 use std::collections::{BTreeMap, HashMap, HashSet};
41 use std::default::Default;
43 use std::fmt::{self, Display, Formatter};
44 use std::fs::{self, File};
45 use std::io::prelude::*;
46 use std::io::{self, BufWriter, BufReader};
47 use std::iter::repeat;
49 use std::path::{PathBuf, Path};
53 use externalfiles::ExternalHtml;
55 use serialize::json::{self, ToJson};
56 use syntax::{abi, ast};
57 use rustc::middle::cstore::LOCAL_CRATE;
58 use rustc::middle::def_id::{CRATE_DEF_INDEX, DefId};
59 use rustc::middle::privacy::AccessLevels;
60 use rustc::middle::stability;
63 use clean::{self, SelfTy};
66 use html::escape::Escape;
67 use html::format::{ConstnessSpace};
68 use html::format::{TyParamBounds, WhereClause, href, AbiSpace};
69 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
70 use html::item_type::ItemType;
71 use html::markdown::{self, Markdown};
72 use html::{highlight, layout};
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>,
111 /// The base-URL of the issue tracker for when an item has been tagged with
113 pub issue_tracker_base_url: Option<String>,
116 /// Indicates where an external crate can be found.
117 pub enum ExternalLocation {
118 /// Remote URL root of the external crate
120 /// This external crate can be found in the local doc/ folder
122 /// The external crate could not be found.
126 /// Metadata about an implementor of a trait.
127 pub struct Implementor {
129 pub stability: Option<clean::Stability>,
130 pub impl_: clean::Impl,
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<DefId> {
143 self.impl_.trait_.as_ref().and_then(|tr| {
144 if let clean::ResolvedPath { did, .. } = *tr {Some(did)} else {None}
155 impl error::Error for Error {
156 fn description(&self) -> &str {
157 self.error.description()
161 impl Display for Error {
162 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
163 write!(f, "\"{}\": {}", self.file.display(), self.error)
168 pub fn new(e: io::Error, file: &Path) -> Error {
170 file: file.to_path_buf(),
176 macro_rules! try_err {
177 ($e:expr, $file:expr) => ({
180 Err(e) => return Err(Error::new(e, $file)),
185 /// This cache is used to store information about the `clean::Crate` being
186 /// rendered in order to provide more useful documentation. This contains
187 /// information like all implementors of a trait, all traits a type implements,
188 /// documentation for all known traits, etc.
190 /// This structure purposefully does not implement `Clone` because it's intended
191 /// to be a fairly large and expensive structure to clone. Instead this adheres
192 /// to `Send` so it may be stored in a `Arc` instance and shared among the various
193 /// rendering threads.
196 /// Mapping of typaram ids to the name of the type parameter. This is used
197 /// when pretty-printing a type (so pretty printing doesn't have to
198 /// painfully maintain a context like this)
199 pub typarams: HashMap<DefId, String>,
201 /// Maps a type id to all known implementations for that type. This is only
202 /// recognized for intra-crate `ResolvedPath` types, and is used to print
203 /// out extra documentation on the page of an enum/struct.
205 /// The values of the map are a list of implementations and documentation
206 /// found on that implementation.
207 pub impls: HashMap<DefId, Vec<Impl>>,
209 /// Maintains a mapping of local crate node ids to the fully qualified name
210 /// and "short type description" of that node. This is used when generating
211 /// URLs when a type is being linked to. External paths are not located in
212 /// this map because the `External` type itself has all the information
214 pub paths: HashMap<DefId, (Vec<String>, ItemType)>,
216 /// Similar to `paths`, but only holds external paths. This is only used for
217 /// generating explicit hyperlinks to other crates.
218 pub external_paths: HashMap<DefId, Vec<String>>,
220 /// This map contains information about all known traits of this crate.
221 /// Implementations of a crate should inherit the documentation of the
222 /// parent trait if no extra documentation is specified, and default methods
223 /// should show up in documentation about trait implementations.
224 pub traits: HashMap<DefId, clean::Trait>,
226 /// When rendering traits, it's often useful to be able to list all
227 /// implementors of the trait, and this mapping is exactly, that: a mapping
228 /// of trait ids to the list of known implementors of the trait
229 pub implementors: HashMap<DefId, Vec<Implementor>>,
231 /// Cache of where external crate documentation can be found.
232 pub extern_locations: HashMap<ast::CrateNum, (String, ExternalLocation)>,
234 /// Cache of where documentation for primitives can be found.
235 pub primitive_locations: HashMap<clean::PrimitiveType, ast::CrateNum>,
237 /// Set of definitions which have been inlined from external crates.
238 pub inlined: HashSet<DefId>,
240 // Private fields only used when initially crawling a crate to build a cache
243 parent_stack: Vec<DefId>,
244 search_index: Vec<IndexItem>,
247 access_levels: AccessLevels<DefId>,
248 deref_trait_did: Option<DefId>,
250 // In rare case where a structure is defined in one module but implemented
251 // in another, if the implementing module is parsed before defining module,
252 // then the fully qualified name of the structure isn't presented in `paths`
253 // yet when its implementation methods are being indexed. Caches such methods
254 // and their parent id here and indexes them at the end of crate parsing.
255 orphan_methods: Vec<(DefId, clean::Item)>,
258 /// Helper struct to render all source code to HTML pages
259 struct SourceCollector<'a> {
262 /// Processed source-file paths
263 seen: HashSet<String>,
264 /// Root destination to place all HTML output into
268 /// Wrapper struct to render the source code of a file. This will do things like
269 /// adding line numbers to the left-hand side.
270 struct Source<'a>(&'a str);
272 // Helper structs for rendering items/sidebars and carrying along contextual
275 #[derive(Copy, Clone)]
278 item: &'a clean::Item,
281 struct Sidebar<'a> { cx: &'a Context, item: &'a clean::Item, }
283 /// Struct representing one entry in the JS search index. These are all emitted
284 /// by hand to a large JS file at the end of cache-creation.
290 parent: Option<DefId>,
291 search_type: Option<IndexItemFunctionType>,
294 /// A type used for the search index.
296 name: Option<String>,
299 impl fmt::Display for Type {
300 /// Formats type as {name: $name}.
301 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
302 // Wrapping struct fmt should never call us when self.name is None,
303 // but just to be safe we write `null` in that case.
305 Some(ref n) => write!(f, "{{\"name\":\"{}\"}}", n),
306 None => write!(f, "null")
311 /// Full type of functions/methods in the search index.
312 struct IndexItemFunctionType {
317 impl fmt::Display for IndexItemFunctionType {
318 /// Formats a full fn type as a JSON {inputs: [Type], outputs: Type/null}.
319 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320 // If we couldn't figure out a type, just write `null`.
321 if self.inputs.iter().any(|ref i| i.name.is_none()) ||
322 (self.output.is_some() && self.output.as_ref().unwrap().name.is_none()) {
323 return write!(f, "null")
326 let inputs: Vec<String> = self.inputs.iter().map(|ref t| {
329 try!(write!(f, "{{\"inputs\":[{}],\"output\":", inputs.join(",")));
332 Some(ref t) => try!(write!(f, "{}", t)),
333 None => try!(write!(f, "null"))
336 Ok(try!(write!(f, "}}")))
340 // TLS keys used to carry information around during rendering.
342 thread_local!(static CACHE_KEY: RefCell<Arc<Cache>> = Default::default());
343 thread_local!(pub static CURRENT_LOCATION_KEY: RefCell<Vec<String>> =
344 RefCell::new(Vec::new()));
345 thread_local!(static USED_ID_MAP: RefCell<HashMap<String, usize>> =
346 RefCell::new(init_ids()));
348 fn init_ids() -> HashMap<String, usize> {
364 "derived_implementations"
365 ].into_iter().map(|id| (String::from(*id), 1)).collect::<HashMap<_, _>>()
368 /// This method resets the local table of used ID attributes. This is typically
369 /// used at the beginning of rendering an entire HTML page to reset from the
370 /// previous state (if any).
372 USED_ID_MAP.with(|s| *s.borrow_mut() = init_ids());
375 pub fn derive_id(candidate: String) -> String {
376 USED_ID_MAP.with(|map| {
377 let id = match map.borrow_mut().get_mut(&candidate) {
380 let id = format!("{}-{}", candidate, *a);
386 map.borrow_mut().insert(id.clone(), 1);
391 /// Generates the documentation for `crate` into the directory `dst`
392 pub fn run(mut krate: clean::Crate,
393 external_html: &ExternalHtml,
395 passes: HashSet<String>) -> Result<(), Error> {
396 let src_root = match krate.src.parent() {
397 Some(p) => p.to_path_buf(),
398 None => PathBuf::new(),
400 let mut cx = Context {
405 root_path: String::new(),
406 layout: layout::Layout {
407 logo: "".to_string(),
408 favicon: "".to_string(),
409 external_html: external_html.clone(),
410 krate: krate.name.clone(),
411 playground_url: "".to_string(),
413 include_sources: true,
414 render_redirect_pages: false,
415 issue_tracker_base_url: None,
418 try_err!(mkdir(&cx.dst), &cx.dst);
420 // Crawl the crate attributes looking for attributes which control how we're
421 // going to emit HTML
422 let default: &[_] = &[];
423 match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) {
427 clean::NameValue(ref x, ref s)
428 if "html_favicon_url" == *x => {
429 cx.layout.favicon = s.to_string();
431 clean::NameValue(ref x, ref s)
432 if "html_logo_url" == *x => {
433 cx.layout.logo = s.to_string();
435 clean::NameValue(ref x, ref s)
436 if "html_playground_url" == *x => {
437 cx.layout.playground_url = s.to_string();
438 markdown::PLAYGROUND_KRATE.with(|slot| {
439 if slot.borrow().is_none() {
440 let name = krate.name.clone();
441 *slot.borrow_mut() = Some(Some(name));
445 clean::NameValue(ref x, ref s)
446 if "issue_tracker_base_url" == *x => {
447 cx.issue_tracker_base_url = Some(s.to_string());
450 if "html_no_source" == *x => {
451 cx.include_sources = false;
460 // Crawl the crate to build various caches used for the output
461 let analysis = ::ANALYSISKEY.with(|a| a.clone());
462 let analysis = analysis.borrow();
463 let access_levels = analysis.as_ref().map(|a| a.access_levels.clone());
464 let access_levels = access_levels.unwrap_or(Default::default());
465 let paths: HashMap<DefId, (Vec<String>, ItemType)> =
466 analysis.as_ref().map(|a| {
467 let paths = a.external_paths.borrow_mut().take().unwrap();
468 paths.into_iter().map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t)))).collect()
469 }).unwrap_or(HashMap::new());
470 let mut cache = Cache {
471 impls: HashMap::new(),
472 external_paths: paths.iter().map(|(&k, v)| (k, v.0.clone()))
475 implementors: HashMap::new(),
477 parent_stack: Vec::new(),
478 search_index: Vec::new(),
479 extern_locations: HashMap::new(),
480 primitive_locations: HashMap::new(),
481 remove_priv: cx.passes.contains("strip-private"),
483 access_levels: access_levels,
484 orphan_methods: Vec::new(),
485 traits: mem::replace(&mut krate.external_traits, HashMap::new()),
486 deref_trait_did: analysis.as_ref().and_then(|a| a.deref_trait_did),
487 typarams: analysis.as_ref().map(|a| {
488 a.external_typarams.borrow_mut().take().unwrap()
489 }).unwrap_or(HashMap::new()),
490 inlined: analysis.as_ref().map(|a| {
491 a.inlined.borrow_mut().take().unwrap()
492 }).unwrap_or(HashSet::new()),
495 // Cache where all our extern crates are located
496 for &(n, ref e) in &krate.externs {
497 cache.extern_locations.insert(n, (e.name.clone(),
498 extern_location(e, &cx.dst)));
499 let did = DefId { krate: n, index: CRATE_DEF_INDEX };
500 cache.paths.insert(did, (vec![e.name.to_string()], ItemType::Module));
503 // Cache where all known primitives have their documentation located.
505 // Favor linking to as local extern as possible, so iterate all crates in
506 // reverse topological order.
507 for &(n, ref e) in krate.externs.iter().rev() {
508 for &prim in &e.primitives {
509 cache.primitive_locations.insert(prim, n);
512 for &prim in &krate.primitives {
513 cache.primitive_locations.insert(prim, LOCAL_CRATE);
516 cache.stack.push(krate.name.clone());
517 krate = cache.fold_crate(krate);
519 // Build our search index
520 let index = build_index(&krate, &mut cache);
522 // Freeze the cache now that the index has been built. Put an Arc into TLS
523 // for future parallelization opportunities
524 let cache = Arc::new(cache);
525 CACHE_KEY.with(|v| *v.borrow_mut() = cache.clone());
526 CURRENT_LOCATION_KEY.with(|s| s.borrow_mut().clear());
528 try!(write_shared(&cx, &krate, &*cache, index));
529 let krate = try!(render_sources(&mut cx, krate));
531 // And finally render the whole crate's documentation
535 fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String {
536 // Build the search index from the collected metadata
537 let mut nodeid_to_pathid = HashMap::new();
538 let mut pathid_to_nodeid = Vec::new();
540 let Cache { ref mut search_index,
542 ref mut paths, .. } = *cache;
544 // Attach all orphan methods to the type's definition if the type
545 // has since been learned.
546 for &(did, ref item) in orphan_methods {
547 match paths.get(&did) {
548 Some(&(ref fqp, _)) => {
549 // Needed to determine `self` type.
550 let parent_basename = Some(fqp[fqp.len() - 1].clone());
551 search_index.push(IndexItem {
553 name: item.name.clone().unwrap(),
554 path: fqp[..fqp.len() - 1].join("::"),
555 desc: shorter(item.doc_value()),
557 search_type: get_index_search_type(&item, parent_basename),
564 // Reduce `NodeId` in paths into smaller sequential numbers,
565 // and prune the paths that do not appear in the index.
566 for item in search_index.iter() {
569 if !nodeid_to_pathid.contains_key(&nodeid) {
570 let pathid = pathid_to_nodeid.len();
571 nodeid_to_pathid.insert(nodeid, pathid);
572 pathid_to_nodeid.push(nodeid);
578 assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len());
581 // Collect the index into a string
582 let mut w = io::Cursor::new(Vec::new());
583 write!(&mut w, r#"searchIndex['{}'] = {{"items":["#, krate.name).unwrap();
585 let mut lastpath = "".to_string();
586 for (i, item) in cache.search_index.iter().enumerate() {
587 // Omit the path if it is same to that of the prior item.
589 if lastpath == item.path {
592 lastpath = item.path.to_string();
597 write!(&mut w, ",").unwrap();
599 write!(&mut w, r#"[{},"{}","{}",{}"#,
600 item.ty as usize, item.name, path,
601 item.desc.to_json().to_string()).unwrap();
604 let pathid = *nodeid_to_pathid.get(&nodeid).unwrap();
605 write!(&mut w, ",{}", pathid).unwrap();
607 None => write!(&mut w, ",null").unwrap()
609 match item.search_type {
610 Some(ref t) => write!(&mut w, ",{}", t).unwrap(),
611 None => write!(&mut w, ",null").unwrap()
613 write!(&mut w, "]").unwrap();
616 write!(&mut w, r#"],"paths":["#).unwrap();
618 for (i, &did) in pathid_to_nodeid.iter().enumerate() {
619 let &(ref fqp, short) = cache.paths.get(&did).unwrap();
621 write!(&mut w, ",").unwrap();
623 write!(&mut w, r#"[{},"{}"]"#,
624 short as usize, *fqp.last().unwrap()).unwrap();
627 write!(&mut w, "]}};").unwrap();
629 String::from_utf8(w.into_inner()).unwrap()
632 fn write_shared(cx: &Context,
633 krate: &clean::Crate,
635 search_index: String) -> Result<(), Error> {
636 // Write out the shared files. Note that these are shared among all rustdoc
637 // docs placed in the output directory, so this needs to be a synchronized
638 // operation with respect to all other rustdocs running around.
639 try_err!(mkdir(&cx.dst), &cx.dst);
640 let _lock = ::flock::Lock::new(&cx.dst.join(".lock"));
642 // Add all the static files. These may already exist, but we just
643 // overwrite them anyway to make sure that they're fresh and up-to-date.
644 try!(write(cx.dst.join("jquery.js"),
645 include_bytes!("static/jquery-2.1.4.min.js")));
646 try!(write(cx.dst.join("main.js"),
647 include_bytes!("static/main.js")));
648 try!(write(cx.dst.join("playpen.js"),
649 include_bytes!("static/playpen.js")));
650 try!(write(cx.dst.join("rustdoc.css"),
651 include_bytes!("static/rustdoc.css")));
652 try!(write(cx.dst.join("main.css"),
653 include_bytes!("static/styles/main.css")));
654 try!(write(cx.dst.join("normalize.css"),
655 include_bytes!("static/normalize.css")));
656 try!(write(cx.dst.join("FiraSans-Regular.woff"),
657 include_bytes!("static/FiraSans-Regular.woff")));
658 try!(write(cx.dst.join("FiraSans-Medium.woff"),
659 include_bytes!("static/FiraSans-Medium.woff")));
660 try!(write(cx.dst.join("FiraSans-LICENSE.txt"),
661 include_bytes!("static/FiraSans-LICENSE.txt")));
662 try!(write(cx.dst.join("Heuristica-Italic.woff"),
663 include_bytes!("static/Heuristica-Italic.woff")));
664 try!(write(cx.dst.join("Heuristica-LICENSE.txt"),
665 include_bytes!("static/Heuristica-LICENSE.txt")));
666 try!(write(cx.dst.join("SourceSerifPro-Regular.woff"),
667 include_bytes!("static/SourceSerifPro-Regular.woff")));
668 try!(write(cx.dst.join("SourceSerifPro-Bold.woff"),
669 include_bytes!("static/SourceSerifPro-Bold.woff")));
670 try!(write(cx.dst.join("SourceSerifPro-LICENSE.txt"),
671 include_bytes!("static/SourceSerifPro-LICENSE.txt")));
672 try!(write(cx.dst.join("SourceCodePro-Regular.woff"),
673 include_bytes!("static/SourceCodePro-Regular.woff")));
674 try!(write(cx.dst.join("SourceCodePro-Semibold.woff"),
675 include_bytes!("static/SourceCodePro-Semibold.woff")));
676 try!(write(cx.dst.join("SourceCodePro-LICENSE.txt"),
677 include_bytes!("static/SourceCodePro-LICENSE.txt")));
678 try!(write(cx.dst.join("LICENSE-MIT.txt"),
679 include_bytes!("static/LICENSE-MIT.txt")));
680 try!(write(cx.dst.join("LICENSE-APACHE.txt"),
681 include_bytes!("static/LICENSE-APACHE.txt")));
682 try!(write(cx.dst.join("COPYRIGHT.txt"),
683 include_bytes!("static/COPYRIGHT.txt")));
685 fn collect(path: &Path, krate: &str,
686 key: &str) -> io::Result<Vec<String>> {
687 let mut ret = Vec::new();
689 for line in BufReader::new(try!(File::open(path))).lines() {
690 let line = try!(line);
691 if !line.starts_with(key) {
694 if line.starts_with(&format!("{}['{}']", key, krate)) {
697 ret.push(line.to_string());
703 // Update the search index
704 let dst = cx.dst.join("search-index.js");
705 let all_indexes = try_err!(collect(&dst, &krate.name, "searchIndex"), &dst);
706 let mut w = try_err!(File::create(&dst), &dst);
707 try_err!(writeln!(&mut w, "var searchIndex = {{}};"), &dst);
708 try_err!(writeln!(&mut w, "{}", search_index), &dst);
709 for index in &all_indexes {
710 try_err!(writeln!(&mut w, "{}", *index), &dst);
712 try_err!(writeln!(&mut w, "initSearch(searchIndex);"), &dst);
714 // Update the list of all implementors for traits
715 let dst = cx.dst.join("implementors");
716 try_err!(mkdir(&dst), &dst);
717 for (&did, imps) in &cache.implementors {
718 // Private modules can leak through to this phase of rustdoc, which
719 // could contain implementations for otherwise private types. In some
720 // rare cases we could find an implementation for an item which wasn't
721 // indexed, so we just skip this step in that case.
723 // FIXME: this is a vague explanation for why this can't be a `get`, in
724 // theory it should be...
725 let &(ref remote_path, remote_item_type) = match cache.paths.get(&did) {
730 let mut mydst = dst.clone();
731 for part in &remote_path[..remote_path.len() - 1] {
733 try_err!(mkdir(&mydst), &mydst);
735 mydst.push(&format!("{}.{}.js",
736 remote_item_type.to_static_str(),
737 remote_path[remote_path.len() - 1]));
738 let all_implementors = try_err!(collect(&mydst, &krate.name,
742 try_err!(mkdir(mydst.parent().unwrap()),
743 &mydst.parent().unwrap().to_path_buf());
744 let mut f = BufWriter::new(try_err!(File::create(&mydst), &mydst));
745 try_err!(writeln!(&mut f, "(function() {{var implementors = {{}};"), &mydst);
747 for implementor in &all_implementors {
748 try_err!(write!(&mut f, "{}", *implementor), &mydst);
751 try_err!(write!(&mut f, r"implementors['{}'] = [", krate.name), &mydst);
753 // If the trait and implementation are in the same crate, then
754 // there's no need to emit information about it (there's inlining
755 // going on). If they're in different crates then the crate defining
756 // the trait will be interested in our implementation.
757 if imp.def_id.krate == did.krate { continue }
758 try_err!(write!(&mut f, r#""{}","#, imp.impl_), &mydst);
760 try_err!(writeln!(&mut f, r"];"), &mydst);
761 try_err!(writeln!(&mut f, "{}", r"
762 if (window.register_implementors) {
763 window.register_implementors(implementors);
765 window.pending_implementors = implementors;
768 try_err!(writeln!(&mut f, r"}})()"), &mydst);
773 fn render_sources(cx: &mut Context,
774 krate: clean::Crate) -> Result<clean::Crate, Error> {
775 info!("emitting source files");
776 let dst = cx.dst.join("src");
777 try_err!(mkdir(&dst), &dst);
778 let dst = dst.join(&krate.name);
779 try_err!(mkdir(&dst), &dst);
780 let mut folder = SourceCollector {
782 seen: HashSet::new(),
785 // skip all invalid spans
786 folder.seen.insert("".to_string());
787 Ok(folder.fold_crate(krate))
790 /// Writes the entire contents of a string to a destination, not attempting to
791 /// catch any errors.
792 fn write(dst: PathBuf, contents: &[u8]) -> Result<(), Error> {
793 Ok(try_err!(try_err!(File::create(&dst), &dst).write_all(contents), &dst))
796 /// Makes a directory on the filesystem, failing the thread if an error occurs and
797 /// skipping if the directory already exists.
798 fn mkdir(path: &Path) -> io::Result<()> {
806 /// Returns a documentation-level item type from the item.
807 fn shortty(item: &clean::Item) -> ItemType {
808 ItemType::from_item(item)
811 /// Takes a path to a source file and cleans the path to it. This canonicalizes
812 /// things like ".." to components which preserve the "top down" hierarchy of a
813 /// static HTML tree. Each component in the cleaned path will be passed as an
814 /// argument to `f`. The very last component of the path (ie the file name) will
815 /// be passed to `f` if `keep_filename` is true, and ignored otherwise.
816 // FIXME (#9639): The closure should deal with &[u8] instead of &str
817 // FIXME (#9639): This is too conservative, rejecting non-UTF-8 paths
818 fn clean_srcpath<F>(src_root: &Path, p: &Path, keep_filename: bool, mut f: F) where
821 // make it relative, if possible
822 let p = p.strip_prefix(src_root).unwrap_or(p);
824 let mut iter = p.iter().map(|x| x.to_str().unwrap()).peekable();
825 while let Some(c) = iter.next() {
826 if !keep_filename && iter.peek().is_none() {
838 /// Attempts to find where an external crate is located, given that we're
839 /// rendering in to the specified source destination.
840 fn extern_location(e: &clean::ExternalCrate, dst: &Path) -> ExternalLocation {
841 // See if there's documentation generated into the local directory
842 let local_location = dst.join(&e.name);
843 if local_location.is_dir() {
847 // Failing that, see if there's an attribute specifying where to find this
849 for attr in &e.attrs {
851 clean::List(ref x, ref list) if "doc" == *x => {
854 clean::NameValue(ref x, ref s)
855 if "html_root_url" == *x => {
856 if s.ends_with("/") {
857 return Remote(s.to_string());
859 return Remote(format!("{}/", s));
869 // Well, at least we tried.
873 impl<'a> DocFolder for SourceCollector<'a> {
874 fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
875 // If we're including source files, and we haven't seen this file yet,
876 // then we need to render it out to the filesystem
877 if self.cx.include_sources && !self.seen.contains(&item.source.filename) {
879 // If it turns out that we couldn't read this file, then we probably
880 // can't read any of the files (generating html output from json or
881 // something like that), so just don't include sources for the
882 // entire crate. The other option is maintaining this mapping on a
883 // per-file basis, but that's probably not worth it...
885 .include_sources = match self.emit_source(&item.source .filename) {
888 println!("warning: source code was requested to be rendered, \
889 but processing `{}` had an error: {}",
890 item.source.filename, e);
891 println!(" skipping rendering of source code");
895 self.seen.insert(item.source.filename.clone());
898 self.fold_item_recur(item)
902 impl<'a> SourceCollector<'a> {
903 /// Renders the given filename into its corresponding HTML source file.
904 fn emit_source(&mut self, filename: &str) -> io::Result<()> {
905 let p = PathBuf::from(filename);
907 // If we couldn't open this file, then just returns because it
908 // probably means that it's some standard library macro thing and we
909 // can't have the source to it anyway.
910 let mut contents = Vec::new();
911 match File::open(&p).and_then(|mut f| f.read_to_end(&mut contents)) {
913 // macros from other libraries get special filenames which we can
915 Err(..) if filename.starts_with("<") &&
916 filename.ends_with("macros>") => return Ok(()),
917 Err(e) => return Err(e)
919 let contents = str::from_utf8(&contents).unwrap();
921 // Remove the utf-8 BOM if any
922 let contents = if contents.starts_with("\u{feff}") {
928 // Create the intermediate directories
929 let mut cur = self.dst.clone();
930 let mut root_path = String::from("../../");
931 clean_srcpath(&self.cx.src_root, &p, false, |component| {
933 mkdir(&cur).unwrap();
934 root_path.push_str("../");
937 let mut fname = p.file_name().expect("source has no filename")
940 cur.push(&fname[..]);
941 let mut w = BufWriter::new(try!(File::create(&cur)));
942 let title = format!("{} -- source", cur.file_name().unwrap()
944 let desc = format!("Source to the Rust file `{}`.", filename);
945 let page = layout::Page {
948 root_path: &root_path,
950 keywords: get_basic_keywords(),
952 try!(layout::render(&mut w, &self.cx.layout,
953 &page, &(""), &Source(contents)));
959 impl DocFolder for Cache {
960 fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
961 // If this is a private module, we don't want it in the search index.
962 let orig_privmod = match item.inner {
963 clean::ModuleItem(..) => {
964 let prev = self.privmod;
965 self.privmod = prev || (self.remove_priv && item.visibility != Some(hir::Public));
971 // Register any generics to their corresponding string. This is used
972 // when pretty-printing types
974 clean::StructItem(ref s) => self.generics(&s.generics),
975 clean::EnumItem(ref e) => self.generics(&e.generics),
976 clean::FunctionItem(ref f) => self.generics(&f.generics),
977 clean::TypedefItem(ref t, _) => self.generics(&t.generics),
978 clean::TraitItem(ref t) => self.generics(&t.generics),
979 clean::ImplItem(ref i) => self.generics(&i.generics),
980 clean::TyMethodItem(ref i) => self.generics(&i.generics),
981 clean::MethodItem(ref i) => self.generics(&i.generics),
982 clean::ForeignFunctionItem(ref f) => self.generics(&f.generics),
986 // Propagate a trait methods' documentation to all implementors of the
988 if let clean::TraitItem(ref t) = item.inner {
989 self.traits.insert(item.def_id, t.clone());
992 // Collect all the implementors of traits.
993 if let clean::ImplItem(ref i) = item.inner {
995 Some(clean::ResolvedPath{ did, .. }) => {
996 self.implementors.entry(did).or_insert(vec![]).push(Implementor {
998 stability: item.stability.clone(),
1002 Some(..) | None => {}
1006 // Index this method for searching later on
1007 if let Some(ref s) = item.name {
1008 let (parent, is_method) = match item.inner {
1009 clean::AssociatedTypeItem(..) |
1010 clean::AssociatedConstItem(..) |
1011 clean::TyMethodItem(..) |
1012 clean::StructFieldItem(..) |
1013 clean::VariantItem(..) => {
1014 ((Some(*self.parent_stack.last().unwrap()),
1015 Some(&self.stack[..self.stack.len() - 1])),
1018 clean::MethodItem(..) => {
1019 if self.parent_stack.is_empty() {
1020 ((None, None), false)
1022 let last = self.parent_stack.last().unwrap();
1024 let path = match self.paths.get(&did) {
1025 Some(&(_, ItemType::Trait)) =>
1026 Some(&self.stack[..self.stack.len() - 1]),
1027 // The current stack not necessarily has correlation
1028 // for where the type was defined. On the other
1029 // hand, `paths` always has the right
1030 // information if present.
1031 Some(&(ref fqp, ItemType::Struct)) |
1032 Some(&(ref fqp, ItemType::Enum)) =>
1033 Some(&fqp[..fqp.len() - 1]),
1034 Some(..) => Some(&*self.stack),
1037 ((Some(*last), path), true)
1040 clean::TypedefItem(_, true) => {
1041 // skip associated types in impls
1042 ((None, None), false)
1044 _ => ((None, Some(&*self.stack)), false)
1046 let hidden_field = match item.inner {
1047 clean::StructFieldItem(clean::HiddenStructField) => true,
1052 (parent, Some(path)) if is_method || (!self.privmod && !hidden_field) => {
1053 // Needed to determine `self` type.
1054 let parent_basename = self.parent_stack.first().and_then(|parent| {
1055 match self.paths.get(parent) {
1056 Some(&(ref fqp, _)) => Some(fqp[fqp.len() - 1].clone()),
1061 if item.def_id.index != CRATE_DEF_INDEX {
1062 self.search_index.push(IndexItem {
1064 name: s.to_string(),
1065 path: path.join("::").to_string(),
1066 desc: shorter(item.doc_value()),
1068 search_type: get_index_search_type(&item, parent_basename),
1072 (Some(parent), None) if is_method || (!self.privmod && !hidden_field)=> {
1073 if parent.is_local() {
1074 // We have a parent, but we don't know where they're
1075 // defined yet. Wait for later to index this item.
1076 self.orphan_methods.push((parent, item.clone()))
1083 // Keep track of the fully qualified path for this item.
1084 let pushed = if item.name.is_some() {
1085 let n = item.name.as_ref().unwrap();
1087 self.stack.push(n.to_string());
1092 clean::StructItem(..) | clean::EnumItem(..) |
1093 clean::TypedefItem(..) | clean::TraitItem(..) |
1094 clean::FunctionItem(..) | clean::ModuleItem(..) |
1095 clean::ForeignFunctionItem(..) if !self.privmod => {
1096 // Reexported items mean that the same id can show up twice
1097 // in the rustdoc ast that we're looking at. We know,
1098 // however, that a reexported item doesn't show up in the
1099 // `public_items` map, so we can skip inserting into the
1100 // paths map if there was already an entry present and we're
1101 // not a public item.
1103 !self.paths.contains_key(&item.def_id) ||
1104 !item.def_id.is_local() ||
1105 self.access_levels.is_public(item.def_id)
1107 self.paths.insert(item.def_id,
1108 (self.stack.clone(), shortty(&item)));
1111 // link variants to their parent enum because pages aren't emitted
1113 clean::VariantItem(..) if !self.privmod => {
1114 let mut stack = self.stack.clone();
1116 self.paths.insert(item.def_id, (stack, ItemType::Enum));
1119 clean::PrimitiveItem(..) if item.visibility.is_some() => {
1120 self.paths.insert(item.def_id, (self.stack.clone(),
1127 // Maintain the parent stack
1128 let parent_pushed = match item.inner {
1129 clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => {
1130 self.parent_stack.push(item.def_id);
1133 clean::ImplItem(ref i) => {
1135 clean::ResolvedPath{ did, .. } => {
1136 self.parent_stack.push(did);
1140 match t.primitive_type() {
1142 let did = DefId::local(prim.to_def_index());
1143 self.parent_stack.push(did);
1154 // Once we've recursively found all the generics, then hoard off all the
1155 // implementations elsewhere
1156 let ret = match self.fold_item_recur(item) {
1159 clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
1160 // extract relevant documentation for this impl
1161 let dox = match attrs.into_iter().find(|a| {
1163 clean::NameValue(ref x, _)
1170 Some(clean::NameValue(_, dox)) => Some(dox),
1171 Some(..) | None => None,
1174 // Figure out the id of this impl. This may map to a
1175 // primitive rather than always to a struct/enum.
1176 let did = match i.for_ {
1177 clean::ResolvedPath { did, .. } |
1178 clean::BorrowedRef {
1179 type_: box clean::ResolvedPath { did, .. }, ..
1185 t.primitive_type().and_then(|t| {
1186 self.primitive_locations.get(&t).map(|n| {
1187 let id = t.to_def_index();
1188 DefId { krate: *n, index: id }
1194 if let Some(did) = did {
1195 self.impls.entry(did).or_insert(vec![]).push(Impl {
1198 stability: item.stability.clone(),
1211 if pushed { self.stack.pop().unwrap(); }
1212 if parent_pushed { self.parent_stack.pop().unwrap(); }
1213 self.privmod = orig_privmod;
1219 fn generics(&mut self, generics: &clean::Generics) {
1220 for typ in &generics.type_params {
1221 self.typarams.insert(typ.did, typ.name.clone());
1227 /// Recurse in the directory structure and change the "root path" to make
1228 /// sure it always points to the top (relatively)
1229 fn recurse<T, F>(&mut self, s: String, f: F) -> T where
1230 F: FnOnce(&mut Context) -> T,
1233 panic!("Unexpected empty destination: {:?}", self.current);
1235 let prev = self.dst.clone();
1237 self.root_path.push_str("../");
1238 self.current.push(s);
1240 info!("Recursing into {}", self.dst.display());
1242 mkdir(&self.dst).unwrap();
1245 info!("Recursed; leaving {}", self.dst.display());
1247 // Go back to where we were at
1249 let len = self.root_path.len();
1250 self.root_path.truncate(len - 3);
1251 self.current.pop().unwrap();
1256 /// Main method for rendering a crate.
1258 /// This currently isn't parallelized, but it'd be pretty easy to add
1259 /// parallelization to this function.
1260 fn krate(self, mut krate: clean::Crate) -> Result<(), Error> {
1261 let mut item = match krate.module.take() {
1263 None => return Ok(())
1265 item.name = Some(krate.name);
1267 // render the crate documentation
1268 let mut work = vec!((self, item));
1271 Some((mut cx, item)) => try!(cx.item(item, |cx, item| {
1272 work.push((cx.clone(), item));
1281 /// Non-parallelized version of rendering an item. This will take the input
1282 /// item, render its contents, and then invoke the specified closure with
1283 /// all sub-items which need to be rendered.
1285 /// The rendering driver uses this closure to queue up more work.
1286 fn item<F>(&mut self, item: clean::Item, mut f: F) -> Result<(), Error> where
1287 F: FnMut(&mut Context, clean::Item),
1289 fn render(w: File, cx: &Context, it: &clean::Item,
1290 pushname: bool) -> io::Result<()> {
1291 // A little unfortunate that this is done like this, but it sure
1292 // does make formatting *a lot* nicer.
1293 CURRENT_LOCATION_KEY.with(|slot| {
1294 *slot.borrow_mut() = cx.current.clone();
1297 let mut title = cx.current.join("::");
1299 if !title.is_empty() {
1300 title.push_str("::");
1302 title.push_str(it.name.as_ref().unwrap());
1304 title.push_str(" - Rust");
1305 let tyname = shortty(it).to_static_str();
1306 let is_crate = match it.inner {
1307 clean::ModuleItem(clean::Module { items: _, is_crate: true }) => true,
1310 let desc = if is_crate {
1311 format!("API documentation for the Rust `{}` crate.",
1314 format!("API documentation for the Rust `{}` {} in crate `{}`.",
1315 it.name.as_ref().unwrap(), tyname, cx.layout.krate)
1317 let keywords = make_item_keywords(it);
1318 let page = layout::Page {
1320 root_path: &cx.root_path,
1323 keywords: &keywords,
1328 // We have a huge number of calls to write, so try to alleviate some
1329 // of the pain by using a buffered writer instead of invoking the
1330 // write syscall all the time.
1331 let mut writer = BufWriter::new(w);
1332 if !cx.render_redirect_pages {
1333 try!(layout::render(&mut writer, &cx.layout, &page,
1334 &Sidebar{ cx: cx, item: it },
1335 &Item{ cx: cx, item: it }));
1337 let mut url = repeat("../").take(cx.current.len())
1338 .collect::<String>();
1339 match cache().paths.get(&it.def_id) {
1340 Some(&(ref names, _)) => {
1341 for name in &names[..names.len() - 1] {
1345 url.push_str(&item_path(it));
1346 try!(layout::redirect(&mut writer, &url));
1354 // Private modules may survive the strip-private pass if they
1355 // contain impls for public types. These modules can also
1356 // contain items such as publicly reexported structures.
1358 // External crates will provide links to these structures, so
1359 // these modules are recursed into, but not rendered normally (a
1360 // flag on the context).
1361 if !self.render_redirect_pages {
1362 self.render_redirect_pages = self.ignore_private_item(&item);
1366 // modules are special because they add a namespace. We also need to
1367 // recurse into the items of the module as well.
1368 clean::ModuleItem(..) => {
1369 let name = item.name.as_ref().unwrap().to_string();
1370 let mut item = Some(item);
1371 self.recurse(name, |this| {
1372 let item = item.take().unwrap();
1373 let joint_dst = this.dst.join("index.html");
1374 let dst = try_err!(File::create(&joint_dst), &joint_dst);
1375 try_err!(render(dst, this, &item, false), &joint_dst);
1377 let m = match item.inner {
1378 clean::ModuleItem(m) => m,
1382 // render sidebar-items.js used throughout this module
1384 let items = this.build_sidebar_items(&m);
1385 let js_dst = this.dst.join("sidebar-items.js");
1386 let mut js_out = BufWriter::new(try_err!(File::create(&js_dst), &js_dst));
1387 try_err!(write!(&mut js_out, "initSidebarItems({});",
1388 json::as_json(&items)), &js_dst);
1391 for item in m.items {
1398 // Things which don't have names (like impls) don't get special
1399 // pages dedicated to them.
1400 _ if item.name.is_some() => {
1401 let joint_dst = self.dst.join(&item_path(&item));
1403 let dst = try_err!(File::create(&joint_dst), &joint_dst);
1404 try_err!(render(dst, self, &item, true), &joint_dst);
1412 fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc>> {
1413 // BTreeMap instead of HashMap to get a sorted output
1414 let mut map = BTreeMap::new();
1415 for item in &m.items {
1416 if self.ignore_private_item(item) { continue }
1418 let short = shortty(item).to_static_str();
1419 let myname = match item.name {
1421 Some(ref s) => s.to_string(),
1423 let short = short.to_string();
1424 map.entry(short).or_insert(vec![])
1425 .push((myname, Some(plain_summary_line(item.doc_value()))));
1428 for (_, items) in &mut map {
1434 fn ignore_private_item(&self, it: &clean::Item) -> bool {
1436 clean::ModuleItem(ref m) => {
1437 (m.items.is_empty() &&
1438 it.doc_value().is_none() &&
1439 it.visibility != Some(hir::Public)) ||
1440 (self.passes.contains("strip-private") && it.visibility != Some(hir::Public))
1442 clean::PrimitiveItem(..) => it.visibility != Some(hir::Public),
1449 fn ismodule(&self) -> bool {
1450 match self.item.inner {
1451 clean::ModuleItem(..) => true, _ => false
1455 /// Generate a url appropriate for an `href` attribute back to the source of
1458 /// The url generated, when clicked, will redirect the browser back to the
1459 /// original source code.
1461 /// If `None` is returned, then a source link couldn't be generated. This
1462 /// may happen, for example, with externally inlined items where the source
1463 /// of their crate documentation isn't known.
1464 fn href(&self, cx: &Context) -> Option<String> {
1465 let href = if self.item.source.loline == self.item.source.hiline {
1466 format!("{}", self.item.source.loline)
1468 format!("{}-{}", self.item.source.loline, self.item.source.hiline)
1471 // First check to see if this is an imported macro source. In this case
1472 // we need to handle it specially as cross-crate inlined macros have...
1474 let imported_macro_from = match self.item.inner {
1475 clean::MacroItem(ref m) => m.imported_from.as_ref(),
1478 if let Some(krate) = imported_macro_from {
1479 let cache = cache();
1480 let root = cache.extern_locations.values().find(|&&(ref n, _)| {
1483 let root = match root {
1484 Some(&Remote(ref s)) => s.to_string(),
1485 Some(&Local) => self.cx.root_path.clone(),
1486 None | Some(&Unknown) => return None,
1488 Some(format!("{root}/{krate}/macro.{name}.html?gotomacrosrc=1",
1491 name = self.item.name.as_ref().unwrap()))
1493 // If this item is part of the local crate, then we're guaranteed to
1494 // know the span, so we plow forward and generate a proper url. The url
1495 // has anchors for the line numbers that we're linking to.
1496 } else if self.item.def_id.is_local() {
1497 let mut path = Vec::new();
1498 clean_srcpath(&cx.src_root, Path::new(&self.item.source.filename),
1500 path.push(component.to_string());
1502 Some(format!("{root}src/{krate}/{path}.html#{href}",
1503 root = self.cx.root_path,
1504 krate = self.cx.layout.krate,
1505 path = path.join("/"),
1508 // If this item is not part of the local crate, then things get a little
1509 // trickier. We don't actually know the span of the external item, but
1510 // we know that the documentation on the other end knows the span!
1512 // In this case, we generate a link to the *documentation* for this type
1513 // in the original crate. There's an extra URL parameter which says that
1514 // we want to go somewhere else, and the JS on the destination page will
1515 // pick it up and instantly redirect the browser to the source code.
1517 // If we don't know where the external documentation for this crate is
1518 // located, then we return `None`.
1520 let cache = cache();
1521 let path = &cache.external_paths[&self.item.def_id];
1522 let root = match cache.extern_locations[&self.item.def_id.krate] {
1523 (_, Remote(ref s)) => s.to_string(),
1524 (_, Local) => self.cx.root_path.clone(),
1525 (_, Unknown) => return None,
1527 Some(format!("{root}{path}/{file}?gotosrc={goto}",
1529 path = path[..path.len() - 1].join("/"),
1530 file = item_path(self.item),
1531 goto = self.item.def_id.index.as_usize()))
1537 impl<'a> fmt::Display for Item<'a> {
1538 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1539 // Write the breadcrumb trail header for the top
1540 try!(write!(fmt, "\n<h1 class='fqn'><span class='in-band'>"));
1541 match self.item.inner {
1542 clean::ModuleItem(ref m) => if m.is_crate {
1543 try!(write!(fmt, "Crate "));
1545 try!(write!(fmt, "Module "));
1547 clean::FunctionItem(..) => try!(write!(fmt, "Function ")),
1548 clean::TraitItem(..) => try!(write!(fmt, "Trait ")),
1549 clean::StructItem(..) => try!(write!(fmt, "Struct ")),
1550 clean::EnumItem(..) => try!(write!(fmt, "Enum ")),
1551 clean::PrimitiveItem(..) => try!(write!(fmt, "Primitive Type ")),
1554 let is_primitive = match self.item.inner {
1555 clean::PrimitiveItem(..) => true,
1559 let cur = &self.cx.current;
1560 let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() };
1561 for (i, component) in cur.iter().enumerate().take(amt) {
1562 try!(write!(fmt, "<a href='{}index.html'>{}</a>::<wbr>",
1563 repeat("../").take(cur.len() - i - 1)
1564 .collect::<String>(),
1568 try!(write!(fmt, "<a class='{}' href=''>{}</a>",
1569 shortty(self.item), self.item.name.as_ref().unwrap()));
1571 try!(write!(fmt, "</span>")); // in-band
1572 try!(write!(fmt, "<span class='out-of-band'>"));
1574 r##"<span id='render-detail'>
1575 <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs">
1576 [<span class='inner'>−</span>]
1582 // When this item is part of a `pub use` in a downstream crate, the
1583 // [src] link in the downstream documentation will actually come back to
1584 // this page, and this link will be auto-clicked. The `id` attribute is
1585 // used to find the link to auto-click.
1586 if self.cx.include_sources && !is_primitive {
1587 match self.href(self.cx) {
1589 try!(write!(fmt, "<a id='src-{}' class='srclink' \
1590 href='{}' title='{}'>[src]</a>",
1591 self.item.def_id.index.as_usize(), l, "goto source code"));
1597 try!(write!(fmt, "</span>")); // out-of-band
1599 try!(write!(fmt, "</h1>\n"));
1601 match self.item.inner {
1602 clean::ModuleItem(ref m) => {
1603 item_module(fmt, self.cx, self.item, &m.items)
1605 clean::FunctionItem(ref f) | clean::ForeignFunctionItem(ref f) =>
1606 item_function(fmt, self.cx, self.item, f),
1607 clean::TraitItem(ref t) => item_trait(fmt, self.cx, self.item, t),
1608 clean::StructItem(ref s) => item_struct(fmt, self.cx, self.item, s),
1609 clean::EnumItem(ref e) => item_enum(fmt, self.cx, self.item, e),
1610 clean::TypedefItem(ref t, _) => item_typedef(fmt, self.cx, self.item, t),
1611 clean::MacroItem(ref m) => item_macro(fmt, self.cx, self.item, m),
1612 clean::PrimitiveItem(ref p) => item_primitive(fmt, self.cx, self.item, p),
1613 clean::StaticItem(ref i) | clean::ForeignStaticItem(ref i) =>
1614 item_static(fmt, self.cx, self.item, i),
1615 clean::ConstantItem(ref c) => item_constant(fmt, self.cx, self.item, c),
1621 fn item_path(item: &clean::Item) -> String {
1623 clean::ModuleItem(..) => {
1624 format!("{}/index.html", item.name.as_ref().unwrap())
1627 format!("{}.{}.html",
1628 shortty(item).to_static_str(),
1629 *item.name.as_ref().unwrap())
1634 fn full_path(cx: &Context, item: &clean::Item) -> String {
1635 let mut s = cx.current.join("::");
1637 s.push_str(item.name.as_ref().unwrap());
1641 fn shorter<'a>(s: Option<&'a str>) -> String {
1643 Some(s) => s.lines().take_while(|line|{
1644 (*line).chars().any(|chr|{
1645 !chr.is_whitespace()
1647 }).collect::<Vec<_>>().join("\n"),
1648 None => "".to_string()
1653 fn plain_summary_line(s: Option<&str>) -> String {
1654 let line = shorter(s).replace("\n", " ");
1655 markdown::plain_summary_line(&line[..])
1658 fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
1659 if let Some(s) = short_stability(item, cx, true) {
1660 try!(write!(w, "<div class='stability'>{}</div>", s));
1662 if let Some(s) = item.doc_value() {
1663 try!(write!(w, "<div class='docblock'>{}</div>", Markdown(s)));
1668 fn item_module(w: &mut fmt::Formatter, cx: &Context,
1669 item: &clean::Item, items: &[clean::Item]) -> fmt::Result {
1670 try!(document(w, cx, item));
1672 let mut indices = (0..items.len()).filter(|i| {
1673 !cx.ignore_private_item(&items[*i])
1674 }).collect::<Vec<usize>>();
1676 // the order of item types in the listing
1677 fn reorder(ty: ItemType) -> u8 {
1679 ItemType::ExternCrate => 0,
1680 ItemType::Import => 1,
1681 ItemType::Primitive => 2,
1682 ItemType::Module => 3,
1683 ItemType::Macro => 4,
1684 ItemType::Struct => 5,
1685 ItemType::Enum => 6,
1686 ItemType::Constant => 7,
1687 ItemType::Static => 8,
1688 ItemType::Trait => 9,
1689 ItemType::Function => 10,
1690 ItemType::Typedef => 12,
1695 fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: usize, idx2: usize) -> Ordering {
1696 let ty1 = shortty(i1);
1697 let ty2 = shortty(i2);
1699 return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2))
1701 let s1 = i1.stability.as_ref().map(|s| s.level);
1702 let s2 = i2.stability.as_ref().map(|s| s.level);
1704 (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater,
1705 (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less,
1708 i1.name.cmp(&i2.name)
1711 indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
1713 debug!("{:?}", indices);
1714 let mut curty = None;
1715 for &idx in &indices {
1716 let myitem = &items[idx];
1718 let myty = Some(shortty(myitem));
1719 if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) {
1720 // Put `extern crate` and `use` re-exports in the same section.
1722 } else if myty != curty {
1723 if curty.is_some() {
1724 try!(write!(w, "</table>"));
1727 let (short, name) = match myty.unwrap() {
1728 ItemType::ExternCrate |
1729 ItemType::Import => ("reexports", "Reexports"),
1730 ItemType::Module => ("modules", "Modules"),
1731 ItemType::Struct => ("structs", "Structs"),
1732 ItemType::Enum => ("enums", "Enums"),
1733 ItemType::Function => ("functions", "Functions"),
1734 ItemType::Typedef => ("types", "Type Definitions"),
1735 ItemType::Static => ("statics", "Statics"),
1736 ItemType::Constant => ("constants", "Constants"),
1737 ItemType::Trait => ("traits", "Traits"),
1738 ItemType::Impl => ("impls", "Implementations"),
1739 ItemType::TyMethod => ("tymethods", "Type Methods"),
1740 ItemType::Method => ("methods", "Methods"),
1741 ItemType::StructField => ("fields", "Struct Fields"),
1742 ItemType::Variant => ("variants", "Variants"),
1743 ItemType::Macro => ("macros", "Macros"),
1744 ItemType::Primitive => ("primitives", "Primitive Types"),
1745 ItemType::AssociatedType => ("associated-types", "Associated Types"),
1746 ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
1748 try!(write!(w, "<h2 id='{id}' class='section-header'>\
1749 <a href=\"#{id}\">{name}</a></h2>\n<table>",
1750 id = derive_id(short.to_owned()), name = name));
1753 match myitem.inner {
1754 clean::ExternCrateItem(ref name, ref src) => {
1757 try!(write!(w, "<tr><td><code>{}extern crate {} as {};",
1758 VisSpace(myitem.visibility),
1763 try!(write!(w, "<tr><td><code>{}extern crate {};",
1764 VisSpace(myitem.visibility), name))
1767 try!(write!(w, "</code></td></tr>"));
1770 clean::ImportItem(ref import) => {
1771 try!(write!(w, "<tr><td><code>{}{}</code></td></tr>",
1772 VisSpace(myitem.visibility), *import));
1776 if myitem.name.is_none() { continue }
1777 let stab_docs = if let Some(s) = short_stability(myitem, cx, false) {
1783 <tr class='{stab} module-item'>
1784 <td><a class='{class}' href='{href}'
1785 title='{title}'>{name}</a></td>
1786 <td class='docblock short'>
1791 name = *myitem.name.as_ref().unwrap(),
1792 stab_docs = stab_docs,
1793 docs = Markdown(&shorter(myitem.doc_value())),
1794 class = shortty(myitem),
1795 stab = myitem.stability_class(),
1796 href = item_path(myitem),
1797 title = full_path(cx, myitem)));
1802 write!(w, "</table>")
1805 fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Option<String> {
1806 let mut result = item.stability.as_ref().and_then(|stab| {
1807 let reason = if show_reason && !stab.reason.is_empty() {
1808 format!(": {}", stab.reason)
1812 let text = if !stab.deprecated_since.is_empty() {
1813 let since = if show_reason {
1814 format!(" since {}", Escape(&stab.deprecated_since))
1818 format!("Deprecated{}{}", since, Markdown(&reason))
1819 } else if stab.level == stability::Unstable {
1820 let unstable_extra = if show_reason {
1821 match (!stab.feature.is_empty(), &cx.issue_tracker_base_url, stab.issue) {
1822 (true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
1823 format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
1824 Escape(&stab.feature), tracker_url, issue_no, issue_no),
1825 (false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
1826 format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
1829 format!(" (<code>{}</code>)", Escape(&stab.feature)),
1835 format!("Unstable{}{}", unstable_extra, Markdown(&reason))
1839 Some(format!("<em class='stab {}'>{}</em>",
1840 item.stability_class(), text))
1843 if result.is_none() {
1844 result = item.deprecation.as_ref().and_then(|depr| {
1845 let note = if show_reason && !depr.note.is_empty() {
1846 format!(": {}", depr.note)
1850 let since = if show_reason && !depr.since.is_empty() {
1851 format!(" since {}", Escape(&depr.since))
1856 let text = format!("Deprecated{}{}", since, Markdown(¬e));
1857 Some(format!("<em class='stab deprecated'>{}</em>", text))
1864 struct Initializer<'a>(&'a str);
1866 impl<'a> fmt::Display for Initializer<'a> {
1867 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1868 let Initializer(s) = *self;
1869 if s.is_empty() { return Ok(()); }
1870 try!(write!(f, "<code> = </code>"));
1871 write!(f, "<code>{}</code>", s)
1875 fn item_constant(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1876 c: &clean::Constant) -> fmt::Result {
1877 try!(write!(w, "<pre class='rust const'>{vis}const \
1878 {name}: {typ}{init}</pre>",
1879 vis = VisSpace(it.visibility),
1880 name = it.name.as_ref().unwrap(),
1882 init = Initializer(&c.expr)));
1886 fn item_static(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1887 s: &clean::Static) -> fmt::Result {
1888 try!(write!(w, "<pre class='rust static'>{vis}static {mutability}\
1889 {name}: {typ}{init}</pre>",
1890 vis = VisSpace(it.visibility),
1891 mutability = MutableSpace(s.mutability),
1892 name = it.name.as_ref().unwrap(),
1894 init = Initializer(&s.expr)));
1898 fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1899 f: &clean::Function) -> fmt::Result {
1900 try!(write!(w, "<pre class='rust fn'>{vis}{constness}{unsafety}{abi}fn \
1901 {name}{generics}{decl}{where_clause}</pre>",
1902 vis = VisSpace(it.visibility),
1903 constness = ConstnessSpace(f.constness),
1904 unsafety = UnsafetySpace(f.unsafety),
1905 abi = AbiSpace(f.abi),
1906 name = it.name.as_ref().unwrap(),
1907 generics = f.generics,
1908 where_clause = WhereClause(&f.generics),
1913 fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
1914 t: &clean::Trait) -> fmt::Result {
1915 let mut bounds = String::new();
1916 if !t.bounds.is_empty() {
1917 if !bounds.is_empty() {
1920 bounds.push_str(": ");
1921 for (i, p) in t.bounds.iter().enumerate() {
1922 if i > 0 { bounds.push_str(" + "); }
1923 bounds.push_str(&format!("{}", *p));
1927 // Output the trait definition
1928 try!(write!(w, "<pre class='rust trait'>{}{}trait {}{}{}{} ",
1929 VisSpace(it.visibility),
1930 UnsafetySpace(t.unsafety),
1931 it.name.as_ref().unwrap(),
1934 WhereClause(&t.generics)));
1936 let types = t.items.iter().filter(|m| {
1937 match m.inner { clean::AssociatedTypeItem(..) => true, _ => false }
1938 }).collect::<Vec<_>>();
1939 let consts = t.items.iter().filter(|m| {
1940 match m.inner { clean::AssociatedConstItem(..) => true, _ => false }
1941 }).collect::<Vec<_>>();
1942 let required = t.items.iter().filter(|m| {
1943 match m.inner { clean::TyMethodItem(_) => true, _ => false }
1944 }).collect::<Vec<_>>();
1945 let provided = t.items.iter().filter(|m| {
1946 match m.inner { clean::MethodItem(_) => true, _ => false }
1947 }).collect::<Vec<_>>();
1949 if t.items.is_empty() {
1950 try!(write!(w, "{{ }}"));
1952 try!(write!(w, "{{\n"));
1954 try!(write!(w, " "));
1955 try!(render_assoc_item(w, t, AssocItemLink::Anchor));
1956 try!(write!(w, ";\n"));
1958 if !types.is_empty() && !consts.is_empty() {
1959 try!(w.write_str("\n"));
1962 try!(write!(w, " "));
1963 try!(render_assoc_item(w, t, AssocItemLink::Anchor));
1964 try!(write!(w, ";\n"));
1966 if !consts.is_empty() && !required.is_empty() {
1967 try!(w.write_str("\n"));
1969 for m in &required {
1970 try!(write!(w, " "));
1971 try!(render_assoc_item(w, m, AssocItemLink::Anchor));
1972 try!(write!(w, ";\n"));
1974 if !required.is_empty() && !provided.is_empty() {
1975 try!(w.write_str("\n"));
1977 for m in &provided {
1978 try!(write!(w, " "));
1979 try!(render_assoc_item(w, m, AssocItemLink::Anchor));
1980 try!(write!(w, " {{ ... }}\n"));
1982 try!(write!(w, "}}"));
1984 try!(write!(w, "</pre>"));
1986 // Trait documentation
1987 try!(document(w, cx, it));
1989 fn trait_item(w: &mut fmt::Formatter, cx: &Context, m: &clean::Item)
1991 let name = m.name.as_ref().unwrap();
1992 let id = derive_id(format!("{}.{}", shortty(m), name));
1993 try!(write!(w, "<h3 id='{id}' class='method stab {stab}'><code>",
1995 stab = m.stability_class()));
1996 try!(render_assoc_item(w, m, AssocItemLink::Anchor));
1997 try!(write!(w, "</code></h3>"));
1998 try!(document(w, cx, m));
2002 if !types.is_empty() {
2004 <h2 id='associated-types'>Associated Types</h2>
2005 <div class='methods'>
2008 try!(trait_item(w, cx, *t));
2010 try!(write!(w, "</div>"));
2013 if !consts.is_empty() {
2015 <h2 id='associated-const'>Associated Constants</h2>
2016 <div class='methods'>
2019 try!(trait_item(w, cx, *t));
2021 try!(write!(w, "</div>"));
2024 // Output the documentation for each function individually
2025 if !required.is_empty() {
2027 <h2 id='required-methods'>Required Methods</h2>
2028 <div class='methods'>
2030 for m in &required {
2031 try!(trait_item(w, cx, *m));
2033 try!(write!(w, "</div>"));
2035 if !provided.is_empty() {
2037 <h2 id='provided-methods'>Provided Methods</h2>
2038 <div class='methods'>
2040 for m in &provided {
2041 try!(trait_item(w, cx, *m));
2043 try!(write!(w, "</div>"));
2046 // If there are methods directly on this trait object, render them here.
2047 try!(render_assoc_items(w, cx, it.def_id, AssocItemRender::All));
2049 let cache = cache();
2051 <h2 id='implementors'>Implementors</h2>
2052 <ul class='item-list' id='implementors-list'>
2054 match cache.implementors.get(&it.def_id) {
2055 Some(implementors) => {
2056 for i in implementors {
2057 try!(writeln!(w, "<li><code>{}</code></li>", i.impl_));
2062 try!(write!(w, "</ul>"));
2063 try!(write!(w, r#"<script type="text/javascript" async
2064 src="{root_path}/implementors/{path}/{ty}.{name}.js">
2066 root_path = vec![".."; cx.current.len()].join("/"),
2067 path = if it.def_id.is_local() {
2068 cx.current.join("/")
2070 let path = &cache.external_paths[&it.def_id];
2071 path[..path.len() - 1].join("/")
2073 ty = shortty(it).to_static_str(),
2074 name = *it.name.as_ref().unwrap()));
2078 fn assoc_const(w: &mut fmt::Formatter, it: &clean::Item,
2079 ty: &clean::Type, default: Option<&String>)
2081 try!(write!(w, "const {}", it.name.as_ref().unwrap()));
2082 try!(write!(w, ": {}", ty));
2083 if let Some(default) = default {
2084 try!(write!(w, " = {}", default));
2089 fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
2090 bounds: &Vec<clean::TyParamBound>,
2091 default: &Option<clean::Type>)
2093 try!(write!(w, "type {}", it.name.as_ref().unwrap()));
2094 if !bounds.is_empty() {
2095 try!(write!(w, ": {}", TyParamBounds(bounds)))
2097 if let Some(ref default) = *default {
2098 try!(write!(w, " = {}", default));
2103 fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
2104 link: AssocItemLink) -> fmt::Result {
2105 fn method(w: &mut fmt::Formatter,
2107 unsafety: hir::Unsafety,
2108 constness: hir::Constness,
2110 g: &clean::Generics,
2111 selfty: &clean::SelfTy,
2113 link: AssocItemLink)
2115 use syntax::abi::Abi;
2117 let name = it.name.as_ref().unwrap();
2118 let anchor = format!("#{}.{}", shortty(it), name);
2119 let href = match link {
2120 AssocItemLink::Anchor => anchor,
2121 AssocItemLink::GotoSource(did) => {
2122 href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
2125 write!(w, "{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
2126 {generics}{decl}{where_clause}",
2127 ConstnessSpace(constness),
2128 UnsafetySpace(unsafety),
2130 Abi::Rust => String::new(),
2131 a => format!("extern {} ", a.to_string())
2136 decl = Method(selfty, d),
2137 where_clause = WhereClause(g))
2140 clean::TyMethodItem(ref m) => {
2141 method(w, meth, m.unsafety, hir::Constness::NotConst,
2142 m.abi, &m.generics, &m.self_, &m.decl, link)
2144 clean::MethodItem(ref m) => {
2145 method(w, meth, m.unsafety, m.constness,
2146 m.abi, &m.generics, &m.self_, &m.decl,
2149 clean::AssociatedConstItem(ref ty, ref default) => {
2150 assoc_const(w, meth, ty, default.as_ref())
2152 clean::AssociatedTypeItem(ref bounds, ref default) => {
2153 assoc_type(w, meth, bounds, default)
2155 _ => panic!("render_assoc_item called on non-associated-item")
2159 fn item_struct(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
2160 s: &clean::Struct) -> fmt::Result {
2161 try!(write!(w, "<pre class='rust struct'>"));
2162 try!(render_attributes(w, it));
2163 try!(render_struct(w,
2170 try!(write!(w, "</pre>"));
2172 try!(document(w, cx, it));
2173 let mut fields = s.fields.iter().filter(|f| {
2175 clean::StructFieldItem(clean::HiddenStructField) => false,
2176 clean::StructFieldItem(clean::TypedStructField(..)) => true,
2180 if let doctree::Plain = s.struct_type {
2181 if fields.peek().is_some() {
2182 try!(write!(w, "<h2 class='fields'>Fields</h2>\n<table>"));
2183 for field in fields {
2184 try!(write!(w, "<tr class='stab {stab}'>
2185 <td id='structfield.{name}'>\
2186 <code>{name}</code></td><td>",
2187 stab = field.stability_class(),
2188 name = field.name.as_ref().unwrap()));
2189 try!(document(w, cx, field));
2190 try!(write!(w, "</td></tr>"));
2192 try!(write!(w, "</table>"));
2195 render_assoc_items(w, cx, it.def_id, AssocItemRender::All)
2198 fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
2199 e: &clean::Enum) -> fmt::Result {
2200 try!(write!(w, "<pre class='rust enum'>"));
2201 try!(render_attributes(w, it));
2202 try!(write!(w, "{}enum {}{}{}",
2203 VisSpace(it.visibility),
2204 it.name.as_ref().unwrap(),
2206 WhereClause(&e.generics)));
2207 if e.variants.is_empty() && !e.variants_stripped {
2208 try!(write!(w, " {{}}"));
2210 try!(write!(w, " {{\n"));
2211 for v in &e.variants {
2212 try!(write!(w, " "));
2213 let name = v.name.as_ref().unwrap();
2215 clean::VariantItem(ref var) => {
2217 clean::CLikeVariant => try!(write!(w, "{}", name)),
2218 clean::TupleVariant(ref tys) => {
2219 try!(write!(w, "{}(", name));
2220 for (i, ty) in tys.iter().enumerate() {
2222 try!(write!(w, ", "))
2224 try!(write!(w, "{}", *ty));
2226 try!(write!(w, ")"));
2228 clean::StructVariant(ref s) => {
2229 try!(render_struct(w,
2241 try!(write!(w, ",\n"));
2244 if e.variants_stripped {
2245 try!(write!(w, " // some variants omitted\n"));
2247 try!(write!(w, "}}"));
2249 try!(write!(w, "</pre>"));
2251 try!(document(w, cx, it));
2252 if !e.variants.is_empty() {
2253 try!(write!(w, "<h2 class='variants'>Variants</h2>\n<table>"));
2254 for variant in &e.variants {
2255 try!(write!(w, "<tr><td id='variant.{name}'><code>{name}</code></td><td>",
2256 name = variant.name.as_ref().unwrap()));
2257 try!(document(w, cx, variant));
2258 match variant.inner {
2259 clean::VariantItem(ref var) => {
2261 clean::StructVariant(ref s) => {
2262 let fields = s.fields.iter().filter(|f| {
2264 clean::StructFieldItem(ref t) => match *t {
2265 clean::HiddenStructField => false,
2266 clean::TypedStructField(..) => true,
2271 try!(write!(w, "<h3 class='fields'>Fields</h3>\n
2273 for field in fields {
2274 try!(write!(w, "<tr><td \
2275 id='variant.{v}.field.{f}'>\
2276 <code>{f}</code></td><td>",
2277 v = variant.name.as_ref().unwrap(),
2278 f = field.name.as_ref().unwrap()));
2279 try!(document(w, cx, field));
2280 try!(write!(w, "</td></tr>"));
2282 try!(write!(w, "</table>"));
2289 try!(write!(w, "</td></tr>"));
2291 try!(write!(w, "</table>"));
2294 try!(render_assoc_items(w, cx, it.def_id, AssocItemRender::All));
2298 fn render_attributes(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result {
2299 for attr in &it.attrs {
2301 clean::Word(ref s) if *s == "must_use" => {
2302 try!(write!(w, "#[{}]\n", s));
2304 clean::NameValue(ref k, ref v) if *k == "must_use" => {
2305 try!(write!(w, "#[{} = \"{}\"]\n", k, v));
2313 fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
2314 g: Option<&clean::Generics>,
2315 ty: doctree::StructType,
2316 fields: &[clean::Item],
2318 structhead: bool) -> fmt::Result {
2319 try!(write!(w, "{}{}{}",
2320 VisSpace(it.visibility),
2321 if structhead {"struct "} else {""},
2322 it.name.as_ref().unwrap()));
2324 Some(g) => try!(write!(w, "{}{}", *g, WhereClause(g))),
2329 try!(write!(w, " {{\n{}", tab));
2330 let mut fields_stripped = false;
2331 for field in fields {
2333 clean::StructFieldItem(clean::HiddenStructField) => {
2334 fields_stripped = true;
2336 clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
2337 try!(write!(w, " {}{}: {},\n{}",
2338 VisSpace(field.visibility),
2339 field.name.as_ref().unwrap(),
2343 _ => unreachable!(),
2347 if fields_stripped {
2348 try!(write!(w, " // some fields omitted\n{}", tab));
2350 try!(write!(w, "}}"));
2352 doctree::Tuple | doctree::Newtype => {
2353 try!(write!(w, "("));
2354 for (i, field) in fields.iter().enumerate() {
2356 try!(write!(w, ", "));
2359 clean::StructFieldItem(clean::HiddenStructField) => {
2360 try!(write!(w, "_"))
2362 clean::StructFieldItem(clean::TypedStructField(ref ty)) => {
2363 try!(write!(w, "{}{}", VisSpace(field.visibility), *ty))
2368 try!(write!(w, ");"));
2371 try!(write!(w, ";"));
2377 #[derive(Copy, Clone)]
2378 enum AssocItemLink {
2383 enum AssocItemRender<'a> {
2385 DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
2388 fn render_assoc_items(w: &mut fmt::Formatter,
2391 what: AssocItemRender) -> fmt::Result {
2393 let v = match c.impls.get(&it) {
2395 None => return Ok(()),
2397 let (non_trait, traits): (Vec<_>, _) = v.iter().partition(|i| {
2398 i.impl_.trait_.is_none()
2400 if !non_trait.is_empty() {
2401 let render_header = match what {
2402 AssocItemRender::All => {
2403 try!(write!(w, "<h2 id='methods'>Methods</h2>"));
2406 AssocItemRender::DerefFor { trait_, type_ } => {
2407 try!(write!(w, "<h2 id='deref-methods'>Methods from \
2408 {}<Target={}></h2>", trait_, type_));
2412 for i in &non_trait {
2413 try!(render_impl(w, cx, i, AssocItemLink::Anchor, render_header));
2416 if let AssocItemRender::DerefFor { .. } = what {
2419 if !traits.is_empty() {
2420 let deref_impl = traits.iter().find(|t| {
2421 match *t.impl_.trait_.as_ref().unwrap() {
2422 clean::ResolvedPath { did, .. } => {
2423 Some(did) == c.deref_trait_did
2428 if let Some(impl_) = deref_impl {
2429 try!(render_deref_methods(w, cx, impl_));
2431 try!(write!(w, "<h2 id='implementations'>Trait \
2432 Implementations</h2>"));
2433 let (derived, manual): (Vec<_>, Vec<&Impl>) = traits.iter().partition(|i| {
2437 let did = i.trait_did().unwrap();
2438 try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true));
2440 if !derived.is_empty() {
2441 try!(write!(w, "<h3 id='derived_implementations'>\
2442 Derived Implementations \
2445 let did = i.trait_did().unwrap();
2446 try!(render_impl(w, cx, i, AssocItemLink::GotoSource(did), true));
2453 fn render_deref_methods(w: &mut fmt::Formatter, cx: &Context, impl_: &Impl) -> fmt::Result {
2454 let deref_type = impl_.impl_.trait_.as_ref().unwrap();
2455 let target = impl_.impl_.items.iter().filter_map(|item| {
2457 clean::TypedefItem(ref t, true) => Some(&t.type_),
2460 }).next().expect("Expected associated type binding");
2461 let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
2463 clean::ResolvedPath { did, .. } => render_assoc_items(w, cx, did, what),
2465 if let Some(prim) = target.primitive_type() {
2466 if let Some(c) = cache().primitive_locations.get(&prim) {
2467 let did = DefId { krate: *c, index: prim.to_def_index() };
2468 try!(render_assoc_items(w, cx, did, what));
2476 // Render_header is false when we are rendering a `Deref` impl and true
2477 // otherwise. If render_header is false, we will avoid rendering static
2478 // methods, since they are not accessible for the type implementing `Deref`
2479 fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLink,
2480 render_header: bool) -> fmt::Result {
2482 try!(write!(w, "<h3 class='impl'><code>{}</code></h3>", i.impl_));
2483 if let Some(ref dox) = i.dox {
2484 try!(write!(w, "<div class='docblock'>{}</div>", Markdown(dox)));
2488 fn doctraititem(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item,
2489 link: AssocItemLink, render_static: bool) -> fmt::Result {
2490 let name = item.name.as_ref().unwrap();
2492 clean::MethodItem(..) | clean::TyMethodItem(..) => {
2493 // Only render when the method is not static or we allow static methods
2494 if !is_static_method(item) || render_static {
2495 let id = derive_id(format!("method.{}", name));
2496 try!(write!(w, "<h4 id='{}' class='{}'><code>", id, shortty(item)));
2497 try!(render_assoc_item(w, item, link));
2498 try!(write!(w, "</code></h4>\n"));
2501 clean::TypedefItem(ref tydef, _) => {
2502 let id = derive_id(format!("assoc_type.{}", name));
2503 try!(write!(w, "<h4 id='{}' class='{}'><code>", id, shortty(item)));
2504 try!(write!(w, "type {} = {}", name, tydef.type_));
2505 try!(write!(w, "</code></h4>\n"));
2507 clean::AssociatedConstItem(ref ty, ref default) => {
2508 let id = derive_id(format!("assoc_const.{}", name));
2509 try!(write!(w, "<h4 id='{}' class='{}'><code>", id, shortty(item)));
2510 try!(assoc_const(w, item, ty, default.as_ref()));
2511 try!(write!(w, "</code></h4>\n"));
2513 clean::ConstantItem(ref c) => {
2514 let id = derive_id(format!("assoc_const.{}", name));
2515 try!(write!(w, "<h4 id='{}' class='{}'><code>", id, shortty(item)));
2516 try!(assoc_const(w, item, &c.type_, Some(&c.expr)));
2517 try!(write!(w, "</code></h4>\n"));
2519 clean::AssociatedTypeItem(ref bounds, ref default) => {
2520 let id = derive_id(format!("assoc_type.{}", name));
2521 try!(write!(w, "<h4 id='{}' class='{}'><code>", id, shortty(item)));
2522 try!(assoc_type(w, item, bounds, default));
2523 try!(write!(w, "</code></h4>\n"));
2525 _ => panic!("can't make docs for trait item with name {:?}", item.name)
2528 return if let AssocItemLink::Anchor = link {
2529 if is_static_method(item) && !render_static {
2532 document(w, cx, item)
2538 fn is_static_method(item: &clean::Item) -> bool {
2540 clean::MethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
2541 clean::TyMethodItem(ref method) => method.self_ == SelfTy::SelfStatic,
2547 try!(write!(w, "<div class='impl-items'>"));
2548 for trait_item in &i.impl_.items {
2549 try!(doctraititem(w, cx, trait_item, link, render_header));
2552 fn render_default_items(w: &mut fmt::Formatter,
2557 render_static: bool) -> fmt::Result {
2558 for trait_item in &t.items {
2559 let n = trait_item.name.clone();
2560 match i.items.iter().find(|m| { m.name == n }) {
2561 Some(..) => continue,
2565 try!(doctraititem(w, cx, trait_item, AssocItemLink::GotoSource(did), render_static));
2570 // If we've implemented a trait, then also emit documentation for all
2571 // default methods which weren't overridden in the implementation block.
2572 // FIXME: this also needs to be done for associated types, whenever defaults
2574 if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
2575 if let Some(t) = cache().traits.get(&did) {
2576 try!(render_default_items(w, cx, did, t, &i.impl_, render_header));
2580 try!(write!(w, "</div>"));
2584 fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
2585 t: &clean::Typedef) -> fmt::Result {
2586 try!(write!(w, "<pre class='rust typedef'>type {}{}{where_clause} = {type_};</pre>",
2587 it.name.as_ref().unwrap(),
2589 where_clause = WhereClause(&t.generics),
2595 impl<'a> fmt::Display for Sidebar<'a> {
2596 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2599 let parentlen = cx.current.len() - if it.is_mod() {1} else {0};
2601 // the sidebar is designed to display sibling functions, modules and
2602 // other miscellaneous informations. since there are lots of sibling
2603 // items (and that causes quadratic growth in large modules),
2604 // we refactor common parts into a shared JavaScript file per module.
2605 // still, we don't move everything into JS because we want to preserve
2606 // as much HTML as possible in order to allow non-JS-enabled browsers
2607 // to navigate the documentation (though slightly inefficiently).
2609 try!(write!(fmt, "<p class='location'>"));
2610 for (i, name) in cx.current.iter().take(parentlen).enumerate() {
2612 try!(write!(fmt, "::<wbr>"));
2614 try!(write!(fmt, "<a href='{}index.html'>{}</a>",
2615 &cx.root_path[..(cx.current.len() - i - 1) * 3],
2618 try!(write!(fmt, "</p>"));
2620 // sidebar refers to the enclosing module, not this module
2621 let relpath = if shortty(it) == ItemType::Module { "../" } else { "" };
2623 "<script>window.sidebarCurrent = {{\
2628 name = it.name.as_ref().map(|x| &x[..]).unwrap_or(""),
2629 ty = shortty(it).to_static_str(),
2632 // there is no sidebar-items.js beyond the crate root path
2633 // FIXME maybe dynamic crate loading can be merged here
2635 try!(write!(fmt, "<script defer src=\"{path}sidebar-items.js\"></script>",
2643 impl<'a> fmt::Display for Source<'a> {
2644 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2645 let Source(s) = *self;
2646 let lines = s.lines().count();
2648 let mut tmp = lines;
2653 try!(write!(fmt, "<pre class=\"line-numbers\">"));
2654 for i in 1..lines + 1 {
2655 try!(write!(fmt, "<span id=\"{0}\">{0:1$}</span>\n", i, cols));
2657 try!(write!(fmt, "</pre>"));
2658 try!(write!(fmt, "{}", highlight::highlight(s, None, None)));
2663 fn item_macro(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
2664 t: &clean::Macro) -> fmt::Result {
2665 try!(w.write_str(&highlight::highlight(&t.source,
2671 fn item_primitive(w: &mut fmt::Formatter, cx: &Context,
2673 _p: &clean::PrimitiveType) -> fmt::Result {
2674 try!(document(w, cx, it));
2675 render_assoc_items(w, cx, it.def_id, AssocItemRender::All)
2678 fn get_basic_keywords() -> &'static str {
2679 "rust, rustlang, rust-lang"
2682 fn make_item_keywords(it: &clean::Item) -> String {
2683 format!("{}, {}", get_basic_keywords(), it.name.as_ref().unwrap())
2686 fn get_index_search_type(item: &clean::Item,
2687 parent: Option<String>) -> Option<IndexItemFunctionType> {
2688 let decl = match item.inner {
2689 clean::FunctionItem(ref f) => &f.decl,
2690 clean::MethodItem(ref m) => &m.decl,
2691 clean::TyMethodItem(ref m) => &m.decl,
2695 let mut inputs = Vec::new();
2697 // Consider `self` an argument as well.
2698 if let Some(name) = parent {
2699 inputs.push(Type { name: Some(name.to_ascii_lowercase()) });
2702 inputs.extend(&mut decl.inputs.values.iter().map(|arg| {
2703 get_index_type(&arg.type_)
2706 let output = match decl.output {
2707 clean::FunctionRetTy::Return(ref return_type) => Some(get_index_type(return_type)),
2711 Some(IndexItemFunctionType { inputs: inputs, output: output })
2714 fn get_index_type(clean_type: &clean::Type) -> Type {
2715 Type { name: get_index_type_name(clean_type).map(|s| s.to_ascii_lowercase()) }
2718 fn get_index_type_name(clean_type: &clean::Type) -> Option<String> {
2720 clean::ResolvedPath { ref path, .. } => {
2721 let segments = &path.segments;
2722 Some(segments[segments.len() - 1].name.clone())
2724 clean::Generic(ref s) => Some(s.clone()),
2725 clean::Primitive(ref p) => Some(format!("{:?}", p)),
2726 clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
2727 // FIXME: add all from clean::Type.
2732 pub fn cache() -> Arc<Cache> {
2733 CACHE_KEY.with(|c| c.borrow().clone())
2738 fn test_unique_id() {
2739 let input = ["foo", "examples", "examples", "method.into_iter","examples",
2740 "method.into_iter", "foo", "main", "search", "methods",
2741 "examples", "method.into_iter", "assoc_type.Item", "assoc_type.Item"];
2742 let expected = ["foo", "examples", "examples-1", "method.into_iter", "examples-2",
2743 "method.into_iter-1", "foo-1", "main-1", "search-1", "methods-1",
2744 "examples-3", "method.into_iter-2", "assoc_type.Item", "assoc_type.Item-1"];
2747 let actual: Vec<String> = input.iter().map(|s| derive_id(s.to_string())).collect();
2748 assert_eq!(&actual[..], expected);