diff --git a/src/doc/complement-cheatsheet.md b/src/doc/complement-cheatsheet.md index 1c3352a829c07..e2dae8c8b52a2 100644 --- a/src/doc/complement-cheatsheet.md +++ b/src/doc/complement-cheatsheet.md @@ -4,7 +4,7 @@ **Int to string** -Use [`ToStr`](../std/to_str/trait.ToStr.html). +Use [`ToStr`](std/to_str/trait.ToStr.html). ~~~ let x: int = 42; @@ -13,8 +13,8 @@ let y: String = x.to_str().to_string(); **String to int** -Use [`FromStr`](../std/from_str/trait.FromStr.html), and its helper function, -[`from_str`](../std/from_str/fn.from_str.html). +Use [`FromStr`](std/from_str/trait.FromStr.html), and its helper function, +[`from_str`](std/from_str/fn.from_str.html). ~~~ let x: Option = from_str("42"); @@ -35,8 +35,8 @@ let y: String = format!("{:X}", x); // uppercase hexadecimal **String to int, in non-base-10** -Use [`FromStrRadix`](../std/num/trait.FromStrRadix.html), and its helper -function, [`from_str_radix`](../std/num/fn.from_str_radix.html). +Use [`FromStrRadix`](std/num/trait.FromStrRadix.html), and its helper +function, [`from_str_radix`](std/num/fn.from_str_radix.html). ~~~ use std::num; @@ -48,7 +48,7 @@ let y: i64 = x.unwrap(); **Vector of Bytes to String** To return a Borrowed String Slice (&str) use the str helper function -[`from_utf8`](../std/str/fn.from_utf8.html). +[`from_utf8`](std/str/fn.from_utf8.html). ~~~ use std::str; @@ -58,7 +58,7 @@ let x: &str = str::from_utf8(bytes).unwrap(); ~~~ To return an Owned String use the str helper function -[`from_utf8_owned`](../std/str/fn.from_utf8_owned.html). +[`from_utf8_owned`](std/str/fn.from_utf8_owned.html). ~~~ use std::str; @@ -68,8 +68,8 @@ let x: Option = let y: String = x.unwrap(); ~~~ -To return a [`MaybeOwned`](../std/str/enum.MaybeOwned.html) use the str helper -function [`from_utf8_lossy`](../std/str/fn.from_utf8_owned.html). +To return a [`MaybeOwned`](std/str/type.MaybeOwned.html) use the str helper +function [`from_utf8_lossy`](std/str/fn.from_utf8_owned.html). This function also replaces non-valid utf-8 sequences with U+FFFD replacement character. @@ -85,11 +85,11 @@ let y = str::from_utf8_lossy(x); ## How do I read from a file? Use -[`File::open`](../std/io/fs/struct.File.html#method.open) +[`File::open`](std/io/fs/struct.File.html#method.open) to create a -[`File`](../std/io/fs/struct.File.html) +[`File`](std/io/fs/struct.File.html) struct, which implements the -[`Reader`](../std/io/trait.Reader.html) +[`Reader`](std/io/trait.Reader.html) trait. ~~~ {.ignore} @@ -103,7 +103,8 @@ let reader : File = File::open(&path).unwrap_or_else(on_error); ## How do I iterate over the lines in a file? -Use the [`lines`](../std/io/trait.Buffer.html#method.lines) method on a [`BufferedReader`](../std/io/buffered/struct.BufferedReader.html). +Use the [`lines`](std/io/trait.Buffer.html#method.lines) method on a +[`BufferedReader`](std/io/struct.BufferedReader.html). ~~~ use std::io::BufferedReader; @@ -121,7 +122,7 @@ for line in reader.lines() { ## How do I search for a substring? -Use the [`find_str`](../std/str/trait.StrSlice.html#tymethod.find_str) method. +Use the [`find_str`](std/str/trait.StrSlice.html#tymethod.find_str) method. ~~~ let str = "Hello, this is some random string"; @@ -132,7 +133,7 @@ let index: Option = str.find_str("rand"); ## How do I get the length of a vector? -The [`Container`](../std/container/trait.Container.html) trait provides the `len` method. +The [`Container`](std/container/trait.Container.html) trait provides the `len` method. ~~~ let u: Vec = vec![0, 1, 2]; @@ -144,7 +145,7 @@ println!("u: {}, v: {}, w: {}", u.len(), v.len(), w.len()); // 3, 4, 5 ## How do I iterate over a vector? -Use the [`iter`](../std/vec/trait.ImmutableVector.html#tymethod.iter) method. +Use the [`iter`](std/slice/trait.ImmutableVector.html#tymethod.iter) method. ~~~ let values: Vec = vec![1, 2, 3, 4, 5]; @@ -153,9 +154,9 @@ for value in values.iter() { // value: &int } ~~~ -(See also [`mut_iter`](../std/vec/trait.MutableVector.html#tymethod.mut_iter) +(See also [`mut_iter`](std/slice/trait.MutableVector.html#tymethod.mut_iter) which yields `&mut int` and -[`move_iter`](../std/vec/trait.OwnedVector.html#tymethod.move_iter) which yields +[`move_iter`](std/slice/trait.OwnedVector.html#tymethod.move_iter) which yields `int` while consuming the `values` vector.) # Type system diff --git a/src/doc/complement-lang-faq.md b/src/doc/complement-lang-faq.md index a357f9ef19594..c03c72ca35fd1 100644 --- a/src/doc/complement-lang-faq.md +++ b/src/doc/complement-lang-faq.md @@ -21,7 +21,7 @@ Some examples that demonstrate different aspects of the language: * The extra library's [json] module. Enums and pattern matching [sprocketnes]: https://github.com/pcwalton/sprocketnes -[hash]: https://github.com/mozilla/rust/blob/master/src/libstd/hash.rs +[hash]: https://github.com/mozilla/rust/blob/master/src/libstd/hash/mod.rs [HashMap]: https://github.com/mozilla/rust/blob/master/src/libcollections/hashmap.rs [json]: https://github.com/mozilla/rust/blob/master/src/libserialize/json.rs @@ -149,6 +149,6 @@ example we were setting RUST_LOG to the name of the hello crate. Multiple paths can be combined to control the exact logging you want to see. For example, when debugging linking in the compiler you might set `RUST_LOG=rustc::metadata::creader,rustc::util::filesearch,rustc::back::rpath` -For a full description see [the language reference][1]. +For a full description see [the logging crate][1]. -[1]:http://doc.rust-lang.org/doc/master/rust.html#logging-system +[1]:log/index.html diff --git a/src/doc/guide-unsafe.md b/src/doc/guide-unsafe.md index 717902e01d5d5..4e1a96710be84 100644 --- a/src/doc/guide-unsafe.md +++ b/src/doc/guide-unsafe.md @@ -499,9 +499,9 @@ shouldn't get triggered. The second of these two functions, `eh_personality`, is used by the failure mechanisms of the compiler. This is often mapped to GCC's personality function -(see the [libstd implementation](../std/rt/unwind/) for more information), but -crates which do not trigger failure can be assured that this function is never -called. +(see the [libstd implementation](std/rt/unwind/index.html) for more +information), but crates which do not trigger failure can be assured that this +function is never called. ## Using libcore @@ -511,7 +511,8 @@ called. With the above techniques, we've got a bare-metal executable running some Rust code. There is a good deal of functionality provided by the standard library, however, that is necessary to be productive in Rust. If the standard library is -not sufficient, then [libcore](../core/) is designed to be used instead. +not sufficient, then [libcore](core/index.html) is designed to be used +instead. The core library has very few dependencies and is much more portable than the standard library itself. Additionally, the core library has most of the diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 7e250e130fac8..511983da4f7f2 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -97,6 +97,7 @@ pub mod arc; pub mod rc; #[cfg(not(test))] +#[doc(hidden)] mod std { pub use core::fmt; pub use core::option; diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs index 51ba01a68aae9..146f29dd9f1da 100644 --- a/src/libcore/bool.rs +++ b/src/libcore/bool.rs @@ -12,6 +12,8 @@ //! //! A `to_bit` conversion function. +#![doc(primitive = "bool")] + use num::{Int, one, zero}; ///////////////////////////////////////////////////////////////////////////// diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 6b0f0b705612e..76ff56a77a48d 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -24,6 +24,7 @@ //! and, as such, should be performed via the `from_u32` function.. #![allow(non_snake_case_functions)] +#![doc(primitive = "char")] use mem::transmute; use option::{None, Option, Some}; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 2ff2dca0c8673..6aa07415e9cc7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -134,10 +134,12 @@ pub mod fmt; // crate. mod should_not_exist; +#[doc(hidden)] mod core { pub use failure; } +#[doc(hidden)] mod std { pub use clone; pub use cmp; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 75d3db596ba5d..cadc874891d20 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,6 +10,8 @@ //! Operations and constants for 32-bits floats (`f32` type) +#![doc(primitive = "f32")] + use intrinsics; use mem; use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d59aad077ccb4..5e19015dd0281 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,6 +10,8 @@ //! Operations and constants for 64-bits floats (`f64` type) +#![doc(primitive = "f64")] + use intrinsics; use mem; use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; diff --git a/src/libcore/num/i16.rs b/src/libcore/num/i16.rs index 957e585e71cdf..b821ff60a730e 100644 --- a/src/libcore/num/i16.rs +++ b/src/libcore/num/i16.rs @@ -10,5 +10,7 @@ //! Operations and constants for signed 16-bits integers (`i16` type) +#![doc(primitive = "i16")] + int_module!(i16, 16) diff --git a/src/libcore/num/i32.rs b/src/libcore/num/i32.rs index cfeb1020f446a..a8cab1f95b0af 100644 --- a/src/libcore/num/i32.rs +++ b/src/libcore/num/i32.rs @@ -10,5 +10,7 @@ //! Operations and constants for signed 32-bits integers (`i32` type) +#![doc(primitive = "i32")] + int_module!(i32, 32) diff --git a/src/libcore/num/i64.rs b/src/libcore/num/i64.rs index 21ae162d4aac6..6009b953bb4db 100644 --- a/src/libcore/num/i64.rs +++ b/src/libcore/num/i64.rs @@ -10,5 +10,7 @@ //! Operations and constants for signed 64-bits integers (`i64` type) +#![doc(primitive = "i64")] + int_module!(i64, 64) diff --git a/src/libcore/num/i8.rs b/src/libcore/num/i8.rs index b9ae13da07588..b3a5557b20c7f 100644 --- a/src/libcore/num/i8.rs +++ b/src/libcore/num/i8.rs @@ -10,5 +10,7 @@ //! Operations and constants for signed 8-bits integers (`i8` type) +#![doc(primitive = "i8")] + int_module!(i8, 8) diff --git a/src/libcore/num/int.rs b/src/libcore/num/int.rs index 4979e9e01d3bf..06d64e73abd49 100644 --- a/src/libcore/num/int.rs +++ b/src/libcore/num/int.rs @@ -10,6 +10,8 @@ //! Operations and constants for architecture-sized signed integers (`int` type) +#![doc(primitive = "int")] + #[cfg(target_word_size = "32")] int_module!(int, 32) #[cfg(target_word_size = "64")] int_module!(int, 64) diff --git a/src/libcore/num/u16.rs b/src/libcore/num/u16.rs index b3c701115c54f..eb4bd427d5166 100644 --- a/src/libcore/num/u16.rs +++ b/src/libcore/num/u16.rs @@ -10,4 +10,6 @@ //! Operations and constants for unsigned 16-bits integers (`u16` type) +#![doc(primitive = "u16")] + uint_module!(u16, i16, 16) diff --git a/src/libcore/num/u32.rs b/src/libcore/num/u32.rs index 46f90dca83333..9522b2e86ac63 100644 --- a/src/libcore/num/u32.rs +++ b/src/libcore/num/u32.rs @@ -10,5 +10,7 @@ //! Operations and constants for unsigned 32-bits integers (`u32` type) +#![doc(primitive = "u32")] + uint_module!(u32, i32, 32) diff --git a/src/libcore/num/u64.rs b/src/libcore/num/u64.rs index bd4333ab5899a..7a654f4bffa0d 100644 --- a/src/libcore/num/u64.rs +++ b/src/libcore/num/u64.rs @@ -10,5 +10,7 @@ //! Operations and constants for unsigned 64-bits integer (`u64` type) +#![doc(primitive = "u64")] + uint_module!(u64, i64, 64) diff --git a/src/libcore/num/u8.rs b/src/libcore/num/u8.rs index 00871a1c8fad1..6a42ce07e5d18 100644 --- a/src/libcore/num/u8.rs +++ b/src/libcore/num/u8.rs @@ -10,5 +10,7 @@ //! Operations and constants for unsigned 8-bits integers (`u8` type) +#![doc(primitive = "u8")] + uint_module!(u8, i8, 8) diff --git a/src/libcore/num/uint.rs b/src/libcore/num/uint.rs index 99ed7e10bf9e3..2f539fff61ae6 100644 --- a/src/libcore/num/uint.rs +++ b/src/libcore/num/uint.rs @@ -10,5 +10,7 @@ //! Operations and constants for architecture-sized unsigned integers (`uint` type) +#![doc(primitive = "uint")] + uint_module!(uint, int, ::int::BITS) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index f3ec95d958247..0762c7458d906 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -234,8 +234,8 @@ //! similar and complementary: they are often employed to indicate a //! lack of a return value; and they are trivially converted between //! each other, so `Result`s are often handled by first converting to -//! `Option` with the [`ok`](enum.Result.html#method.ok) and -//! [`err`](enum.Result.html#method.ok) methods. +//! `Option` with the [`ok`](type.Result.html#method.ok) and +//! [`err`](type.Result.html#method.ok) methods. //! //! Whereas `Option` only indicates the lack of a value, `Result` is //! specifically for error reporting, and carries with it an error diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 9771d766e65fe..8f885dafffa46 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -12,6 +12,8 @@ //! //! For more details `std::slice`. +#![doc(primitive = "slice")] + use mem::transmute; use clone::Clone; use container::Container; diff --git a/src/libcore/str.rs b/src/libcore/str.rs index a19e720446b44..21dbaf705973f 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -12,6 +12,8 @@ //! //! For more details, see std::str +#![doc(primitive = "str")] + use mem; use char; use clone::Clone; diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index 7639700eac9aa..f9a14b1de506f 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -59,6 +59,8 @@ //! assert_eq!(d, (0u32, 0.0f32)); //! ``` +#![doc(primitive = "tuple")] + use clone::Clone; #[cfg(not(test))] use cmp::*; #[cfg(not(test))] use default::Default; diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 2f096346c9bef..65c60f2d3606d 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -62,17 +62,22 @@ fn try_inline_def(cx: &core::DocContext, clean::TraitItem(build_external_trait(tcx, did)) } ast::DefFn(did, style) => { + // If this function is a tuple struct constructor, we just skip it + if csearch::get_tuple_struct_definition_if_ctor(&tcx.sess.cstore, + did).is_some() { + return None + } record_extern_fqn(cx, did, clean::TypeFunction); clean::FunctionItem(build_external_function(tcx, did, style)) } ast::DefStruct(did) => { record_extern_fqn(cx, did, clean::TypeStruct); - ret.extend(build_impls(tcx, did).move_iter()); + ret.extend(build_impls(cx, tcx, did).move_iter()); clean::StructItem(build_struct(tcx, did)) } ast::DefTy(did) => { record_extern_fqn(cx, did, clean::TypeEnum); - ret.extend(build_impls(tcx, did).move_iter()); + ret.extend(build_impls(cx, tcx, did).move_iter()); build_type(tcx, did) } // Assume that the enum type is reexported next to the variant, and @@ -193,7 +198,8 @@ fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum { }) } -fn build_impls(tcx: &ty::ctxt, +fn build_impls(cx: &core::DocContext, + tcx: &ty::ctxt, did: ast::DefId) -> Vec { ty::populate_implementations_for_type_if_necessary(tcx, did); let mut impls = Vec::new(); @@ -205,6 +211,38 @@ fn build_impls(tcx: &ty::ctxt, } } + // If this is the first time we've inlined something from this crate, then + // we inline *all* impls from the crate into this crate. Note that there's + // currently no way for us to filter this based on type, and we likely need + // many impls for a variety of reasons. + // + // Primarily, the impls will be used to populate the documentation for this + // type being inlined, but impls can also be used when generating + // documentation for primitives (no way to find those specifically). + if cx.populated_crate_impls.borrow_mut().insert(did.krate) { + csearch::each_top_level_item_of_crate(&tcx.sess.cstore, + did.krate, + |def, _, _| { + populate_impls(tcx, def, &mut impls) + }); + + fn populate_impls(tcx: &ty::ctxt, + def: decoder::DefLike, + impls: &mut Vec) { + match def { + decoder::DlImpl(did) => impls.push(build_impl(tcx, did)), + decoder::DlDef(ast::DefMod(did)) => { + csearch::each_child_of_item(&tcx.sess.cstore, + did, + |def, _, _| { + populate_impls(tcx, def, impls) + }) + } + _ => {} + } + } + } + impls } @@ -259,7 +297,8 @@ fn build_module(cx: &core::DocContext, tcx: &ty::ctxt, // FIXME: this doesn't handle reexports inside the module itself. // Should they be handled? - csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| { + csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, vis| { + if vis != ast::Public { return } match def { decoder::DlDef(def) => { match try_inline_def(cx, tcx, def) { @@ -267,7 +306,8 @@ fn build_module(cx: &core::DocContext, tcx: &ty::ctxt, None => {} } } - decoder::DlImpl(did) => items.push(build_impl(tcx, did)), + // All impls were inlined above + decoder::DlImpl(..) => {} decoder::DlField => fail!("unimplemented field"), } }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5deadc8867267..856619882c574 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -28,6 +28,7 @@ use rustc::metadata::decoder; use rustc::middle::ty; use std::rc::Rc; +use std::u32; use core; use doctree; @@ -81,6 +82,7 @@ pub struct Crate { pub name: String, pub module: Option, pub externs: Vec<(ast::CrateNum, ExternalCrate)>, + pub primitives: Vec, } impl<'a> Clean for visit_ast::RustdocVisitor<'a> { @@ -92,6 +94,7 @@ impl<'a> Clean for visit_ast::RustdocVisitor<'a> { externs.push((n, meta.clean())); }); + // Figure out the name of this crate let input = driver::FileInput(cx.src.clone()); let t_outputs = driver::build_output_filenames(&input, &None, @@ -100,10 +103,62 @@ impl<'a> Clean for visit_ast::RustdocVisitor<'a> { cx.sess()); let id = link::find_crate_id(self.attrs.as_slice(), t_outputs.out_filestem.as_slice()); + + // Clean the crate, translating the entire libsyntax AST to one that is + // understood by rustdoc. + let mut module = self.module.clean(); + + // Collect all inner modules which are tagged as implementations of + // primitives. + // + // Note that this loop only searches the top-level items of the crate, + // and this is intentional. If we were to search the entire crate for an + // item tagged with `#[doc(primitive)]` then we we would also have to + // search the entirety of external modules for items tagged + // `#[doc(primitive)]`, which is a pretty inefficient process (decoding + // all that metadata unconditionally). + // + // In order to keep the metadata load under control, the + // `#[doc(primitive)]` feature is explicitly designed to only allow the + // primitive tags to show up as the top level items in a crate. + // + // Also note that this does not attempt to deal with modules tagged + // duplicately for the same primitive. This is handled later on when + // rendering by delegating everything to a hash map. + let mut primitives = Vec::new(); + { + let m = match module.inner { + ModuleItem(ref mut m) => m, + _ => unreachable!(), + }; + let mut tmp = Vec::new(); + for child in m.items.iter() { + match child.inner { + ModuleItem(..) => {}, + _ => continue, + } + let prim = match Primitive::find(child.attrs.as_slice()) { + Some(prim) => prim, + None => continue, + }; + primitives.push(prim); + tmp.push(Item { + source: Span::empty(), + name: Some(prim.to_url_str().to_string()), + attrs: child.attrs.clone(), + visibility: Some(ast::Public), + def_id: ast_util::local_def(prim.to_node_id()), + inner: PrimitiveItem(prim), + }); + } + m.items.extend(tmp.move_iter()); + } + Crate { name: id.name.to_string(), - module: Some(self.module.clean()), + module: Some(module), externs: externs, + primitives: primitives, } } } @@ -112,15 +167,35 @@ impl<'a> Clean for visit_ast::RustdocVisitor<'a> { pub struct ExternalCrate { pub name: String, pub attrs: Vec, + pub primitives: Vec, } impl Clean for cstore::crate_metadata { fn clean(&self) -> ExternalCrate { + let mut primitives = Vec::new(); + let cx = super::ctxtkey.get().unwrap(); + match cx.maybe_typed { + core::Typed(ref tcx) => { + csearch::each_top_level_item_of_crate(&tcx.sess.cstore, + self.cnum, + |def, _, _| { + let did = match def { + decoder::DlDef(ast::DefMod(did)) => did, + _ => return + }; + let attrs = inline::load_attrs(tcx, did); + match Primitive::find(attrs.as_slice()) { + Some(prim) => primitives.push(prim), + None => {} + } + }); + } + core::NotTyped(..) => {} + } ExternalCrate { name: self.name.to_string(), - attrs: decoder::get_crate_attributes(self.data()).clean() - .move_iter() - .collect(), + attrs: decoder::get_crate_attributes(self.data()).clean(), + primitives: primitives, } } } @@ -227,6 +302,7 @@ pub enum ItemEnum { /// `static`s from an extern block ForeignStaticItem(Static), MacroItem(Macro), + PrimitiveItem(Primitive), } #[deriving(Clone, Encodable, Decodable)] @@ -400,14 +476,19 @@ impl Clean for ast::TyParamBound { } } -fn external_path(name: &str) -> Path { +fn external_path(name: &str, substs: &ty::substs) -> Path { Path { global: false, segments: vec![PathSegment { name: name.to_string(), - lifetimes: Vec::new(), - types: Vec::new(), - }] + lifetimes: match substs.regions { + ty::ErasedRegions => Vec::new(), + ty::NonerasedRegions(ref v) => { + v.iter().filter_map(|v| v.clean()).collect() + } + }, + types: substs.tps.clean(), + }], } } @@ -418,16 +499,21 @@ impl Clean for ty::BuiltinBound { core::Typed(ref tcx) => tcx, core::NotTyped(_) => return RegionBound, }; + let empty = ty::substs::empty(); let (did, path) = match *self { ty::BoundStatic => return RegionBound, ty::BoundSend => - (tcx.lang_items.send_trait().unwrap(), external_path("Send")), + (tcx.lang_items.send_trait().unwrap(), + external_path("Send", &empty)), ty::BoundSized => - (tcx.lang_items.sized_trait().unwrap(), external_path("Sized")), + (tcx.lang_items.sized_trait().unwrap(), + external_path("Sized", &empty)), ty::BoundCopy => - (tcx.lang_items.copy_trait().unwrap(), external_path("Copy")), + (tcx.lang_items.copy_trait().unwrap(), + external_path("Copy", &empty)), ty::BoundShare => - (tcx.lang_items.share_trait().unwrap(), external_path("Share")), + (tcx.lang_items.share_trait().unwrap(), + external_path("Share", &empty)), }; let fqn = csearch::get_item_path(tcx, did); let fqn = fqn.move_iter().map(|i| i.to_str().to_string()).collect(); @@ -451,7 +537,8 @@ impl Clean for ty::TraitRef { let fqn = csearch::get_item_path(tcx, self.def_id); let fqn = fqn.move_iter().map(|i| i.to_str().to_string()) .collect::>(); - let path = external_path(fqn.last().unwrap().as_slice()); + let path = external_path(fqn.last().unwrap().as_slice(), + &self.substs); cx.external_paths.borrow_mut().get_mut_ref().insert(self.def_id, (fqn, TypeTrait)); TraitBound(ResolvedPath { @@ -519,9 +606,9 @@ impl Clean> for ty::Region { ty::ReStatic => Some(Lifetime("static".to_string())), ty::ReLateBound(_, ty::BrNamed(_, name)) => Some(Lifetime(token::get_name(name).get().to_string())), + ty::ReEarlyBound(_, _, name) => Some(Lifetime(name.clean())), ty::ReLateBound(..) | - ty::ReEarlyBound(..) | ty::ReFree(..) | ty::ReScope(..) | ty::ReInfer(..) | @@ -920,7 +1007,7 @@ pub enum Type { /// For references to self Self(ast::DefId), /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char. - Primitive(ast::PrimTy), + Primitive(Primitive), Closure(Box, Option), Proc(Box), /// extern "ABI" fn @@ -928,10 +1015,6 @@ pub enum Type { Tuple(Vec), Vector(Box), FixedVector(Box, String), - String, - Bool, - /// aka TyNil - Unit, /// aka TyBot Bottom, Unique(Box), @@ -945,6 +1028,19 @@ pub enum Type { // region, raw, other boxes, mutable } +#[deriving(Clone, Encodable, Decodable, PartialEq, TotalEq, Hash)] +pub enum Primitive { + Int, I8, I16, I32, I64, + Uint, U8, U16, U32, U64, + F32, F64, F128, + Char, + Bool, + Nil, + Str, + Slice, + PrimitiveTuple, +} + #[deriving(Clone, Encodable, Decodable)] pub enum TypeKind { TypeEnum, @@ -956,11 +1052,97 @@ pub enum TypeKind { TypeVariant, } +impl Primitive { + fn from_str(s: &str) -> Option { + match s.as_slice() { + "int" => Some(Int), + "i8" => Some(I8), + "i16" => Some(I16), + "i32" => Some(I32), + "i64" => Some(I64), + "uint" => Some(Uint), + "u8" => Some(U8), + "u16" => Some(U16), + "u32" => Some(U32), + "u64" => Some(U64), + "bool" => Some(Bool), + "nil" => Some(Nil), + "char" => Some(Char), + "str" => Some(Str), + "f32" => Some(F32), + "f64" => Some(F64), + "f128" => Some(F128), + "slice" => Some(Slice), + "tuple" => Some(PrimitiveTuple), + _ => None, + } + } + + fn find(attrs: &[Attribute]) -> Option { + for attr in attrs.iter() { + let list = match *attr { + List(ref k, ref l) if k.as_slice() == "doc" => l, + _ => continue, + }; + for sub_attr in list.iter() { + let value = match *sub_attr { + NameValue(ref k, ref v) + if k.as_slice() == "primitive" => v.as_slice(), + _ => continue, + }; + match Primitive::from_str(value) { + Some(p) => return Some(p), + None => {} + } + } + } + return None + } + + pub fn to_str(&self) -> &'static str { + match *self { + Int => "int", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + Uint => "uint", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + F32 => "f32", + F64 => "f64", + F128 => "f128", + Str => "str", + Bool => "bool", + Char => "char", + Nil => "()", + Slice => "slice", + PrimitiveTuple => "tuple", + } + } + + pub fn to_url_str(&self) -> &'static str { + match *self { + Nil => "nil", + other => other.to_str(), + } + } + + /// Creates a rustdoc-specific node id for primitive types. + /// + /// These node ids are generally never used by the AST itself. + pub fn to_node_id(&self) -> ast::NodeId { + u32::MAX - 1 - (*self as u32) + } +} + impl Clean for ast::Ty { fn clean(&self) -> Type { use syntax::ast::*; match self.node { - TyNil => Unit, + TyNil => Primitive(Nil), TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()), TyRptr(ref l, ref m) => BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(), @@ -988,16 +1170,26 @@ impl Clean for ast::Ty { impl Clean for ty::t { fn clean(&self) -> Type { match ty::get(*self).sty { - ty::ty_nil => Unit, ty::ty_bot => Bottom, - ty::ty_bool => Bool, - ty::ty_char => Primitive(ast::TyChar), - ty::ty_int(t) => Primitive(ast::TyInt(t)), - ty::ty_uint(u) => Primitive(ast::TyUint(u)), - ty::ty_float(f) => Primitive(ast::TyFloat(f)), + ty::ty_nil => Primitive(Nil), + ty::ty_bool => Primitive(Bool), + ty::ty_char => Primitive(Char), + ty::ty_int(ast::TyI) => Primitive(Int), + ty::ty_int(ast::TyI8) => Primitive(I8), + ty::ty_int(ast::TyI16) => Primitive(I16), + ty::ty_int(ast::TyI32) => Primitive(I32), + ty::ty_int(ast::TyI64) => Primitive(I64), + ty::ty_uint(ast::TyU) => Primitive(Uint), + ty::ty_uint(ast::TyU8) => Primitive(U8), + ty::ty_uint(ast::TyU16) => Primitive(U16), + ty::ty_uint(ast::TyU32) => Primitive(U32), + ty::ty_uint(ast::TyU64) => Primitive(U64), + ty::ty_float(ast::TyF32) => Primitive(F32), + ty::ty_float(ast::TyF64) => Primitive(F64), + ty::ty_float(ast::TyF128) => Primitive(F128), + ty::ty_str => Primitive(Str), ty::ty_box(t) => Managed(box t.clean()), ty::ty_uniq(t) => Unique(box t.clean()), - ty::ty_str => String, ty::ty_vec(mt, None) => Vector(box mt.ty.clean()), ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(), format!("{}", i)), @@ -1040,22 +1232,13 @@ impl Clean for ty::t { let fqn: Vec = fqn.move_iter().map(|i| { i.to_str().to_string() }).collect(); - let mut path = external_path(fqn.last() - .unwrap() - .to_str() - .as_slice()); let kind = match ty::get(*self).sty { ty::ty_struct(..) => TypeStruct, ty::ty_trait(..) => TypeTrait, _ => TypeEnum, }; - path.segments.get_mut(0).lifetimes = match substs.regions { - ty::ErasedRegions => Vec::new(), - ty::NonerasedRegions(ref v) => { - v.iter().filter_map(|v| v.clean()).collect() - } - }; - path.segments.get_mut(0).types = substs.tps.clean(); + let path = external_path(fqn.last().unwrap().to_str().as_slice(), + substs); cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind)); ResolvedPath { @@ -1747,7 +1930,7 @@ fn resolve_type(path: Path, tpbs: Option>, let tycx = match cx.maybe_typed { core::Typed(ref tycx) => tycx, // If we're extracting tests, this return value doesn't matter. - core::NotTyped(_) => return Bool + core::NotTyped(_) => return Primitive(Bool), }; debug!("searching for {:?} in defmap", id); let def = match tycx.def_map.borrow().find(&id) { @@ -1758,9 +1941,22 @@ fn resolve_type(path: Path, tpbs: Option>, match def { ast::DefSelfTy(i) => return Self(ast_util::local_def(i)), ast::DefPrimTy(p) => match p { - ast::TyStr => return String, - ast::TyBool => return Bool, - _ => return Primitive(p) + ast::TyStr => return Primitive(Str), + ast::TyBool => return Primitive(Bool), + ast::TyChar => return Primitive(Char), + ast::TyInt(ast::TyI) => return Primitive(Int), + ast::TyInt(ast::TyI8) => return Primitive(I8), + ast::TyInt(ast::TyI16) => return Primitive(I16), + ast::TyInt(ast::TyI32) => return Primitive(I32), + ast::TyInt(ast::TyI64) => return Primitive(I64), + ast::TyUint(ast::TyU) => return Primitive(Uint), + ast::TyUint(ast::TyU8) => return Primitive(U8), + ast::TyUint(ast::TyU16) => return Primitive(U16), + ast::TyUint(ast::TyU32) => return Primitive(U32), + ast::TyUint(ast::TyU64) => return Primitive(U64), + ast::TyFloat(ast::TyF32) => return Primitive(F32), + ast::TyFloat(ast::TyF64) => return Primitive(F64), + ast::TyFloat(ast::TyF128) => return Primitive(F128), }, ast::DefTyParam(i, _) => return Generic(i), ast::DefTyParamBinder(i) => return TyParamBinder(i), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 27e39e1235c67..87b19fecb1f20 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -42,6 +42,7 @@ pub struct DocContext { pub external_traits: RefCell>>, pub external_typarams: RefCell>>, pub inlined: RefCell>>, + pub populated_crate_impls: RefCell>, } impl DocContext { @@ -114,6 +115,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet, cfgs: Vec) external_typarams: RefCell::new(Some(HashMap::new())), external_paths: RefCell::new(Some(HashMap::new())), inlined: RefCell::new(Some(HashSet::new())), + populated_crate_impls: RefCell::new(HashSet::new()), }, CrateAnalysis { exported_items: exported_items, public_items: public_items, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 3b3f4378d67ad..41d84deea6f41 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -263,6 +263,53 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool, Ok(()) } +fn primitive_link(f: &mut fmt::Formatter, + prim: clean::Primitive, + name: &str) -> fmt::Result { + let m = cache_key.get().unwrap(); + let mut needs_termination = false; + match m.primitive_locations.find(&prim) { + Some(&ast::LOCAL_CRATE) => { + let loc = current_location_key.get().unwrap(); + let len = if loc.len() == 0 {0} else {loc.len() - 1}; + try!(write!(f, "", + "../".repeat(len), + prim.to_url_str())); + needs_termination = true; + } + Some(&cnum) => { + let path = m.paths.get(&ast::DefId { + krate: cnum, + node: ast::CRATE_NODE_ID, + }); + let loc = match *m.extern_locations.get(&cnum) { + render::Remote(ref s) => Some(s.to_string()), + render::Local => { + let loc = current_location_key.get().unwrap(); + Some("../".repeat(loc.len())) + } + render::Unknown => None, + }; + match loc { + Some(root) => { + try!(write!(f, "", + root, + path.ref0().as_slice().head().unwrap(), + prim.to_url_str())); + needs_termination = true; + } + None => {} + } + } + None => {} + } + try!(write!(f, "{}", name)); + if needs_termination { + try!(write!(f, "")); + } + Ok(()) +} + /// Helper to render type parameters fn tybounds(w: &mut fmt::Formatter, typarams: &Option >) -> fmt::Result { @@ -297,27 +344,7 @@ impl fmt::Show for clean::Type { tybounds(f, typarams) } clean::Self(..) => f.write("Self".as_bytes()), - clean::Primitive(prim) => { - let s = match prim { - ast::TyInt(ast::TyI) => "int", - ast::TyInt(ast::TyI8) => "i8", - ast::TyInt(ast::TyI16) => "i16", - ast::TyInt(ast::TyI32) => "i32", - ast::TyInt(ast::TyI64) => "i64", - ast::TyUint(ast::TyU) => "uint", - ast::TyUint(ast::TyU8) => "u8", - ast::TyUint(ast::TyU16) => "u16", - ast::TyUint(ast::TyU32) => "u32", - ast::TyUint(ast::TyU64) => "u64", - ast::TyFloat(ast::TyF32) => "f32", - ast::TyFloat(ast::TyF64) => "f64", - ast::TyFloat(ast::TyF128) => "f128", - ast::TyStr => "str", - ast::TyBool => "bool", - ast::TyChar => "char", - }; - f.write(s.as_bytes()) - } + clean::Primitive(prim) => primitive_link(f, prim, prim.to_str()), clean::Closure(ref decl, ref region) => { write!(f, "{style}{lifetimes}|{args}|{bounds}\ {arrow, select, yes{ -> {ret}} other{}}", @@ -329,7 +356,7 @@ impl fmt::Show for clean::Type { }, args = decl.decl.inputs, arrow = match decl.decl.output { - clean::Unit => "no", + clean::Primitive(clean::Nil) => "no", _ => "yes", }, ret = decl.decl.output, @@ -379,7 +406,10 @@ impl fmt::Show for clean::Type { ": {}", m.collect::>().connect(" + ")) }, - arrow = match decl.decl.output { clean::Unit => "no", _ => "yes" }, + arrow = match decl.decl.output { + clean::Primitive(clean::Nil) => "no", + _ => "yes", + }, ret = decl.decl.output) } clean::BareFunction(ref decl) => { @@ -394,22 +424,16 @@ impl fmt::Show for clean::Type { decl.decl) } clean::Tuple(ref typs) => { - try!(f.write("(".as_bytes())); - for (i, typ) in typs.iter().enumerate() { - if i > 0 { - try!(f.write(", ".as_bytes())) - } - try!(write!(f, "{}", *typ)); - } - f.write(")".as_bytes()) + primitive_link(f, clean::PrimitiveTuple, + format!("({:#})", typs).as_slice()) + } + clean::Vector(ref t) => { + primitive_link(f, clean::Slice, format!("[{}]", **t).as_slice()) } - clean::Vector(ref t) => write!(f, "[{}]", **t), clean::FixedVector(ref t, ref s) => { - write!(f, "[{}, ..{}]", **t, *s) + primitive_link(f, clean::Slice, + format!("[{}, ..{}]", **t, *s).as_slice()) } - clean::String => f.write("str".as_bytes()), - clean::Bool => f.write("bool".as_bytes()), - clean::Unit => f.write("()".as_bytes()), clean::Bottom => f.write("!".as_bytes()), clean::Unique(ref t) => write!(f, "~{}", **t), clean::Managed(ref t) => write!(f, "@{}", **t), @@ -454,7 +478,10 @@ impl fmt::Show for clean::FnDecl { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "({args}){arrow, select, yes{ -> {ret}} other{}}", args = self.inputs, - arrow = match self.output { clean::Unit => "no", _ => "yes" }, + arrow = match self.output { + clean::Primitive(clean::Nil) => "no", + _ => "yes" + }, ret = self.output) } } @@ -490,7 +517,10 @@ impl<'a> fmt::Show for Method<'a> { write!(f, "({args}){arrow, select, yes{ -> {ret}} other{}}", args = args, - arrow = match d.output { clean::Unit => "no", _ => "yes" }, + arrow = match d.output { + clean::Primitive(clean::Nil) => "no", + _ => "yes" + }, ret = d.output) } } diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 0f000f4e5aea1..f36c81f8f8d8d 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -37,6 +37,7 @@ pub enum ItemType { ForeignFunction = 13, ForeignStatic = 14, Macro = 15, + Primitive = 16, } impl ItemType { @@ -58,6 +59,7 @@ impl ItemType { ForeignFunction => "ffi", ForeignStatic => "ffs", Macro => "macro", + Primitive => "primitive", } } } @@ -92,6 +94,7 @@ pub fn shortty(item: &clean::Item) -> ItemType { clean::ForeignFunctionItem(..) => ForeignFunction, clean::ForeignStaticItem(..) => ForeignStatic, clean::MacroItem(..) => Macro, + clean::PrimitiveItem(..) => Primitive, } } diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index f4a8541c6d22b..80653878247fa 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -130,3 +130,17 @@ r##" fn nonestr<'a>(s: &'a str) -> &'a str { if s == "" { "none" } else { s } } + +pub fn redirect(dst: &mut io::Writer, url: &str) -> io::IoResult<()> { + write!(dst, +r##" + + + + + + +"##, + url = url, + ) +} diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 22619bdbf8517..16becde164ff3 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -70,7 +70,7 @@ use html::markdown; pub struct Context { /// Current hierarchy of components leading down to what's currently being /// rendered - pub current: Vec , + pub current: Vec, /// String representation of how to get back to the root path of the 'doc/' /// folder in terms of a relative URL. pub root_path: String, @@ -90,6 +90,10 @@ pub struct Context { /// the source files are present in the html rendering, then this will be /// `true`. pub include_sources: bool, + /// A flag, which when turned off, will render pages which redirect to the + /// real location of an item. This is used to allow external links to + /// publicly reused items to redirect to the right location. + pub render_redirect_pages: bool, } /// Indicates where an external crate can be found. @@ -102,13 +106,11 @@ pub enum ExternalLocation { Unknown, } -/// Different ways an implementor of a trait can be rendered. -pub enum Implementor { - /// Paths are displayed specially by omitting the `impl XX for` cruft - PathType(clean::Type), - /// This is the generic representation of a trait implementor, used for - /// primitive types and otherwise non-path types. - OtherType(clean::Generics, /* trait */ clean::Type, /* for */ clean::Type), +/// Metadata about an implementor of a trait. +pub struct Implementor { + generics: clean::Generics, + trait_: clean::Type, + for_: clean::Type, } /// This cache is used to store information about the `clean::Crate` being @@ -159,6 +161,9 @@ pub struct Cache { /// Cache of where external crate documentation can be found. pub extern_locations: HashMap, + /// Cache of where documentation for primitives can be found. + pub primitive_locations: HashMap, + /// Set of definitions which have been inlined from external crates. pub inlined: HashSet, @@ -226,9 +231,12 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { krate: krate.name.clone(), }, include_sources: true, + render_redirect_pages: false, }; try!(mkdir(&cx.dst)); + // Crawl the crate attributes looking for attributes which control how we're + // going to emit HTML match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) { Some(attrs) => { for attr in attrs.iter() { @@ -281,6 +289,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { parent_stack: Vec::new(), search_index: Vec::new(), extern_locations: HashMap::new(), + primitive_locations: HashMap::new(), privmod: false, public_items: public_items, orphan_methods: Vec::new(), @@ -297,19 +306,58 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { cache.stack.push(krate.name.clone()); krate = cache.fold_crate(krate); + // Cache where all our extern crates are located + for &(n, ref e) in krate.externs.iter() { + cache.extern_locations.insert(n, extern_location(e, &cx.dst)); + let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID }; + cache.paths.insert(did, (vec![e.name.to_string()], item_type::Module)); + } + + // Cache where all known primitives have their documentation located. + // + // Favor linking to as local extern as possible, so iterate all crates in + // reverse topological order. + for &(n, ref e) in krate.externs.iter().rev() { + for &prim in e.primitives.iter() { + cache.primitive_locations.insert(prim, n); + } + } + for &prim in krate.primitives.iter() { + cache.primitive_locations.insert(prim, ast::LOCAL_CRATE); + } + + // Build our search index + let index = try!(build_index(&krate, &mut cache)); + + // Freeze the cache now that the index has been built. Put an Arc into TLS + // for future parallelization opportunities + let cache = Arc::new(cache); + cache_key.replace(Some(cache.clone())); + current_location_key.replace(Some(Vec::new())); + + try!(write_shared(&cx, &krate, &*cache, index)); + let krate = try!(render_sources(&mut cx, krate)); + + // And finally render the whole crate's documentation + cx.krate(krate) +} + +fn build_index(krate: &clean::Crate, cache: &mut Cache) -> io::IoResult { + // Build the search index from the collected metadata let mut nodeid_to_pathid = HashMap::new(); let mut pathid_to_nodeid = Vec::new(); { - let Cache { search_index: ref mut index, - orphan_methods: ref meths, paths: ref mut paths, ..} = cache; + let Cache { ref mut search_index, + ref orphan_methods, + ref mut paths, .. } = *cache; // Attach all orphan methods to the type's definition if the type // has since been learned. - for &(pid, ref item) in meths.iter() { + for &(pid, ref item) in orphan_methods.iter() { let did = ast_util::local_def(pid); match paths.find(&did) { Some(&(ref fqp, _)) => { - index.push(IndexItem { + search_index.push(IndexItem { ty: shortty(item), name: item.name.clone().unwrap(), path: fqp.slice_to(fqp.len() - 1).connect("::") @@ -324,7 +372,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { // Reduce `NodeId` in paths into smaller sequential numbers, // and prune the paths that do not appear in the index. - for item in index.iter() { + for item in search_index.iter() { match item.parent { Some(nodeid) => { if !nodeid_to_pathid.contains_key(&nodeid) { @@ -339,189 +387,181 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { assert_eq!(nodeid_to_pathid.len(), pathid_to_nodeid.len()); } - // Publish the search index - let index = { - let mut w = MemWriter::new(); - try!(write!(&mut w, r#"searchIndex['{}'] = \{"items":["#, krate.name)); - - let mut lastpath = "".to_string(); - for (i, item) in cache.search_index.iter().enumerate() { - // Omit the path if it is same to that of the prior item. - let path; - if lastpath.as_slice() == item.path.as_slice() { - path = ""; - } else { - lastpath = item.path.to_string(); - path = item.path.as_slice(); - }; + // Collect the index into a string + let mut w = MemWriter::new(); + try!(write!(&mut w, r#"searchIndex['{}'] = \{"items":["#, krate.name)); - if i > 0 { - try!(write!(&mut w, ",")); - } - try!(write!(&mut w, r#"[{:u},"{}","{}",{}"#, - item.ty, item.name, path, - item.desc.to_json().to_str())); - match item.parent { - Some(nodeid) => { - let pathid = *nodeid_to_pathid.find(&nodeid).unwrap(); - try!(write!(&mut w, ",{}", pathid)); - } - None => {} + let mut lastpath = "".to_string(); + for (i, item) in cache.search_index.iter().enumerate() { + // Omit the path if it is same to that of the prior item. + let path; + if lastpath.as_slice() == item.path.as_slice() { + path = ""; + } else { + lastpath = item.path.to_string(); + path = item.path.as_slice(); + }; + + if i > 0 { + try!(write!(&mut w, ",")); + } + try!(write!(&mut w, r#"[{:u},"{}","{}",{}"#, + item.ty, item.name, path, + item.desc.to_json().to_str())); + match item.parent { + Some(nodeid) => { + let pathid = *nodeid_to_pathid.find(&nodeid).unwrap(); + try!(write!(&mut w, ",{}", pathid)); } - try!(write!(&mut w, "]")); + None => {} } + try!(write!(&mut w, "]")); + } - try!(write!(&mut w, r#"],"paths":["#)); + try!(write!(&mut w, r#"],"paths":["#)); - for (i, &did) in pathid_to_nodeid.iter().enumerate() { - let &(ref fqp, short) = cache.paths.find(&did).unwrap(); - if i > 0 { - try!(write!(&mut w, ",")); - } - try!(write!(&mut w, r#"[{:u},"{}"]"#, - short, *fqp.last().unwrap())); + for (i, &did) in pathid_to_nodeid.iter().enumerate() { + let &(ref fqp, short) = cache.paths.find(&did).unwrap(); + if i > 0 { + try!(write!(&mut w, ",")); } + try!(write!(&mut w, r#"[{:u},"{}"]"#, + short, *fqp.last().unwrap())); + } - try!(write!(&mut w, r"]\};")); + try!(write!(&mut w, r"]\};")); - str::from_utf8(w.unwrap().as_slice()).unwrap().to_string() - }; + Ok(str::from_utf8(w.unwrap().as_slice()).unwrap().to_string()) +} +fn write_shared(cx: &Context, + krate: &clean::Crate, + cache: &Cache, + search_index: String) -> io::IoResult<()> { // Write out the shared files. Note that these are shared among all rustdoc // docs placed in the output directory, so this needs to be a synchronized // operation with respect to all other rustdocs running around. - { - try!(mkdir(&cx.dst)); - let _lock = ::flock::Lock::new(&cx.dst.join(".lock")); - - // Add all the static files. These may already exist, but we just - // overwrite them anyway to make sure that they're fresh and up-to-date. - try!(write(cx.dst.join("jquery.js"), - include_bin!("static/jquery-2.1.0.min.js"))); - try!(write(cx.dst.join("main.js"), include_bin!("static/main.js"))); - try!(write(cx.dst.join("main.css"), include_bin!("static/main.css"))); - try!(write(cx.dst.join("normalize.css"), - include_bin!("static/normalize.css"))); - try!(write(cx.dst.join("FiraSans-Regular.woff"), - include_bin!("static/FiraSans-Regular.woff"))); - try!(write(cx.dst.join("FiraSans-Medium.woff"), - include_bin!("static/FiraSans-Medium.woff"))); - try!(write(cx.dst.join("Heuristica-Regular.woff"), - include_bin!("static/Heuristica-Regular.woff"))); - try!(write(cx.dst.join("Heuristica-Italic.woff"), - include_bin!("static/Heuristica-Italic.woff"))); - try!(write(cx.dst.join("Heuristica-Bold.woff"), - include_bin!("static/Heuristica-Bold.woff"))); - - fn collect(path: &Path, krate: &str, - key: &str) -> io::IoResult> { - let mut ret = Vec::new(); - if path.exists() { - for line in BufferedReader::new(File::open(path)).lines() { - let line = try!(line); - if !line.as_slice().starts_with(key) { - continue - } - if line.as_slice().starts_with( - format!("{}['{}']", key, krate).as_slice()) { - continue - } - ret.push(line.to_string()); + try!(mkdir(&cx.dst)); + let _lock = ::flock::Lock::new(&cx.dst.join(".lock")); + + // Add all the static files. These may already exist, but we just + // overwrite them anyway to make sure that they're fresh and up-to-date. + try!(write(cx.dst.join("jquery.js"), + include_bin!("static/jquery-2.1.0.min.js"))); + try!(write(cx.dst.join("main.js"), include_bin!("static/main.js"))); + try!(write(cx.dst.join("main.css"), include_bin!("static/main.css"))); + try!(write(cx.dst.join("normalize.css"), + include_bin!("static/normalize.css"))); + try!(write(cx.dst.join("FiraSans-Regular.woff"), + include_bin!("static/FiraSans-Regular.woff"))); + try!(write(cx.dst.join("FiraSans-Medium.woff"), + include_bin!("static/FiraSans-Medium.woff"))); + try!(write(cx.dst.join("Heuristica-Regular.woff"), + include_bin!("static/Heuristica-Regular.woff"))); + try!(write(cx.dst.join("Heuristica-Italic.woff"), + include_bin!("static/Heuristica-Italic.woff"))); + try!(write(cx.dst.join("Heuristica-Bold.woff"), + include_bin!("static/Heuristica-Bold.woff"))); + + fn collect(path: &Path, krate: &str, + key: &str) -> io::IoResult> { + let mut ret = Vec::new(); + if path.exists() { + for line in BufferedReader::new(File::open(path)).lines() { + let line = try!(line); + if !line.as_slice().starts_with(key) { + continue } - } - return Ok(ret); - } - - // Update the search index - let dst = cx.dst.join("search-index.js"); - let all_indexes = try!(collect(&dst, krate.name.as_slice(), - "searchIndex")); - let mut w = try!(File::create(&dst)); - try!(writeln!(&mut w, r"var searchIndex = \{\};")); - try!(writeln!(&mut w, "{}", index)); - for index in all_indexes.iter() { - try!(writeln!(&mut w, "{}", *index)); - } - try!(writeln!(&mut w, "initSearch(searchIndex);")); - - // Update the list of all implementors for traits - let dst = cx.dst.join("implementors"); - try!(mkdir(&dst)); - for (&did, imps) in cache.implementors.iter() { - if ast_util::is_local(did) { continue } - let &(ref remote_path, remote_item_type) = cache.paths.get(&did); - - let mut mydst = dst.clone(); - for part in remote_path.slice_to(remote_path.len() - 1).iter() { - mydst.push(part.as_slice()); - try!(mkdir(&mydst)); - } - mydst.push(format!("{}.{}.js", - remote_item_type.to_static_str(), - *remote_path.get(remote_path.len() - 1))); - let all_implementors = try!(collect(&mydst, krate.name.as_slice(), - "implementors")); - - try!(mkdir(&mydst.dir_path())); - let mut f = BufferedWriter::new(try!(File::create(&mydst))); - try!(writeln!(&mut f, r"(function() \{var implementors = \{\};")); - - for implementor in all_implementors.iter() { - try!(writeln!(&mut f, "{}", *implementor)); - } - - try!(write!(&mut f, r"implementors['{}'] = \{", krate.name)); - for imp in imps.iter() { - let &(ref path, item_type) = match *imp { - PathType(clean::ResolvedPath { did, .. }) => { - cache.paths.get(&did) - } - PathType(..) | OtherType(..) => continue, - }; - try!(write!(&mut f, r#"{}:"#, *path.get(path.len() - 1))); - try!(write!(&mut f, r#""{}"#, - path.slice_to(path.len() - 1).connect("/"))); - try!(write!(&mut f, r#"/{}.{}.html","#, - item_type.to_static_str(), - *path.get(path.len() - 1))); - } - try!(writeln!(&mut f, r"\};")); - try!(writeln!(&mut f, "{}", r" - if (window.register_implementors) { - window.register_implementors(implementors); - } else { - window.pending_implementors = implementors; + if line.as_slice().starts_with( + format!("{}['{}']", key, krate).as_slice()) { + continue } - ")); - try!(writeln!(&mut f, r"\})()")); + ret.push(line.to_string()); + } } + return Ok(ret); } - // Render all source files (this may turn into a giant no-op) - { - info!("emitting source files"); - let dst = cx.dst.join("src"); - try!(mkdir(&dst)); - let dst = dst.join(krate.name.as_slice()); - try!(mkdir(&dst)); - let mut folder = SourceCollector { - dst: dst, - seen: HashSet::new(), - cx: &mut cx, - }; - // skip all invalid spans - folder.seen.insert("".to_string()); - krate = folder.fold_crate(krate); + // Update the search index + let dst = cx.dst.join("search-index.js"); + let all_indexes = try!(collect(&dst, krate.name.as_slice(), + "searchIndex")); + let mut w = try!(File::create(&dst)); + try!(writeln!(&mut w, r"var searchIndex = \{\};")); + try!(writeln!(&mut w, "{}", search_index)); + for index in all_indexes.iter() { + try!(writeln!(&mut w, "{}", *index)); } + try!(writeln!(&mut w, "initSearch(searchIndex);")); + + // Update the list of all implementors for traits + let dst = cx.dst.join("implementors"); + try!(mkdir(&dst)); + for (&did, imps) in cache.implementors.iter() { + // Private modules can leak through to this phase of rustdoc, which + // could contain implementations for otherwise private types. In some + // rare cases we could find an implementation for an item which wasn't + // indexed, so we just skip this step in that case. + // + // FIXME: this is a vague explanation for why this can't be a `get`, in + // theory it should be... + let &(ref remote_path, remote_item_type) = match cache.paths.find(&did) { + Some(p) => p, + None => continue, + }; - for &(n, ref e) in krate.externs.iter() { - cache.extern_locations.insert(n, extern_location(e, &cx.dst)); - let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID }; - cache.paths.insert(did, (vec![e.name.to_string()], item_type::Module)); + let mut mydst = dst.clone(); + for part in remote_path.slice_to(remote_path.len() - 1).iter() { + mydst.push(part.as_slice()); + try!(mkdir(&mydst)); + } + mydst.push(format!("{}.{}.js", + remote_item_type.to_static_str(), + *remote_path.get(remote_path.len() - 1))); + let all_implementors = try!(collect(&mydst, krate.name.as_slice(), + "implementors")); + + try!(mkdir(&mydst.dir_path())); + let mut f = BufferedWriter::new(try!(File::create(&mydst))); + try!(writeln!(&mut f, r"(function() \{var implementors = \{\};")); + + for implementor in all_implementors.iter() { + try!(write!(&mut f, "{}", *implementor)); + } + + try!(write!(&mut f, r"implementors['{}'] = [", krate.name)); + for imp in imps.iter() { + try!(write!(&mut f, r#""impl{} {} for {}","#, + imp.generics, imp.trait_, imp.for_)); + } + try!(writeln!(&mut f, r"];")); + try!(writeln!(&mut f, "{}", r" + if (window.register_implementors) { + window.register_implementors(implementors); + } else { + window.pending_implementors = implementors; + } + ")); + try!(writeln!(&mut f, r"\})()")); } + Ok(()) +} - // And finally render the whole crate's documentation - cx.krate(krate, cache) +fn render_sources(cx: &mut Context, + krate: clean::Crate) -> io::IoResult { + info!("emitting source files"); + let dst = cx.dst.join("src"); + try!(mkdir(&dst)); + let dst = dst.join(krate.name.as_slice()); + try!(mkdir(&dst)); + let mut folder = SourceCollector { + dst: dst, + seen: HashSet::new(), + cx: cx, + }; + // skip all invalid spans + folder.seen.insert("".to_string()); + Ok(folder.fold_crate(krate)) } /// Writes the entire contents of a string to a destination, not attempting to @@ -718,16 +758,11 @@ impl DocFolder for Cache { let v = self.implementors.find_or_insert_with(did, |_| { Vec::new() }); - match i.for_ { - clean::ResolvedPath{..} => { - v.unshift(PathType(i.for_.clone())); - } - _ => { - v.push(OtherType(i.generics.clone(), - i.trait_.get_ref().clone(), - i.for_.clone())); - } - } + v.push(Implementor { + generics: i.generics.clone(), + trait_: i.trait_.get_ref().clone(), + for_: i.for_.clone(), + }); } Some(..) | None => {} } @@ -803,7 +838,7 @@ impl DocFolder for Cache { clean::StructItem(..) | clean::EnumItem(..) | clean::TypedefItem(..) | clean::TraitItem(..) | clean::FunctionItem(..) | clean::ModuleItem(..) | - clean::ForeignFunctionItem(..) => { + clean::ForeignFunctionItem(..) if !self.privmod => { // Reexported items mean that the same id can show up twice // in the rustdoc ast that we're looking at. We know, // however, that a reexported item doesn't show up in the @@ -820,7 +855,7 @@ impl DocFolder for Cache { } // link variants to their parent enum because pages aren't emitted // for each variant - clean::VariantItem(..) => { + clean::VariantItem(..) if !self.privmod => { let mut stack = self.stack.clone(); stack.pop(); self.paths.insert(item.def_id, (stack, item_type::Enum)); @@ -852,41 +887,66 @@ impl DocFolder for Cache { Some(item) => { match item { clean::Item{ attrs, inner: clean::ImplItem(i), .. } => { - match i.for_ { - clean::ResolvedPath { did, .. } => { + use clean::{Primitive, Vector, ResolvedPath, BorrowedRef}; + use clean::{FixedVector, Slice, Tuple, PrimitiveTuple}; + + // extract relevant documentation for this impl + let dox = match attrs.move_iter().find(|a| { + match *a { + clean::NameValue(ref x, _) + if "doc" == x.as_slice() => { + true + } + _ => false + } + }) { + Some(clean::NameValue(_, dox)) => Some(dox), + Some(..) | None => None, + }; + + // Figure out the id of this impl. This may map to a + // primitive rather than always to a struct/enum. + let did = match i.for_ { + ResolvedPath { did, .. } => Some(did), + + // References to primitives are picked up as well to + // recognize implementations for &str, this may not + // be necessary in a DST world. + Primitive(p) | + BorrowedRef { type_: box Primitive(p), ..} => + { + Some(ast_util::local_def(p.to_node_id())) + } + + // In a DST world, we may only need + // Vector/FixedVector, but for now we also pick up + // borrowed references + Vector(..) | FixedVector(..) | + BorrowedRef{ type_: box Vector(..), .. } | + BorrowedRef{ type_: box FixedVector(..), .. } => + { + Some(ast_util::local_def(Slice.to_node_id())) + } + + Tuple(..) => { + let id = PrimitiveTuple.to_node_id(); + Some(ast_util::local_def(id)) + } + + _ => None, + }; + + match did { + Some(did) => { let v = self.impls.find_or_insert_with(did, |_| { Vec::new() }); - // extract relevant documentation for this impl - match attrs.move_iter().find(|a| { - match *a { - clean::NameValue(ref x, _) - if "doc" == x.as_slice() => { - true - } - _ => false - } - }) { - Some(clean::NameValue(_, dox)) => { - v.push((i, Some(dox))); - } - Some(..) | None => { - v.push((i, None)); - } - } + v.push((i, dox)); } - _ => {} + None => {} } None } - // Private modules may survive the strip-private pass if - // they contain impls for public types, but those will get - // stripped here - clean::Item { inner: clean::ModuleItem(ref m), - visibility, .. } - if (m.items.len() == 0 && - item.doc_value().is_none()) || - visibility != Some(ast::Public) => None, i => Some(i), } @@ -941,16 +1001,13 @@ impl Context { /// /// This currently isn't parallelized, but it'd be pretty easy to add /// parallelization to this function. - fn krate(self, mut krate: clean::Crate, cache: Cache) -> io::IoResult<()> { + fn krate(self, mut krate: clean::Crate) -> io::IoResult<()> { let mut item = match krate.module.take() { Some(i) => i, None => return Ok(()) }; item.name = Some(krate.name); - // using a rwarc makes this parallelizable in the future - cache_key.replace(Some(Arc::new(cache))); - let mut work = vec!((self, item)); loop { match work.pop() { @@ -970,7 +1027,7 @@ impl Context { /// The rendering driver uses this closure to queue up more work. fn item(&mut self, item: clean::Item, f: |&mut Context, clean::Item|) -> io::IoResult<()> { - fn render(w: io::File, cx: &mut Context, it: &clean::Item, + fn render(w: io::File, cx: &Context, it: &clean::Item, pushname: bool) -> io::IoResult<()> { info!("Rendering an item to {}", w.path().display()); // A little unfortunate that this is done like this, but it sure @@ -997,9 +1054,24 @@ impl Context { // of the pain by using a buffered writer instead of invoking the // write sycall all the time. let mut writer = BufferedWriter::new(w); - try!(layout::render(&mut writer as &mut Writer, &cx.layout, &page, - &Sidebar{ cx: cx, item: it }, - &Item{ cx: cx, item: it })); + if !cx.render_redirect_pages { + try!(layout::render(&mut writer, &cx.layout, &page, + &Sidebar{ cx: cx, item: it }, + &Item{ cx: cx, item: it })); + } else { + let mut url = "../".repeat(cx.current.len()); + match cache_key.get().unwrap().paths.find(&it.def_id) { + Some(&(ref names, _)) => { + for name in names.slice_to(names.len() - 1).iter() { + url.push_str(name.as_slice()); + url.push_str("/"); + } + url.push_str(item_path(it).as_slice()); + try!(layout::redirect(&mut writer, url.as_slice())); + } + None => {} + } + } writer.flush() } @@ -1007,6 +1079,17 @@ impl Context { // modules are special because they add a namespace. We also need to // recurse into the items of the module as well. clean::ModuleItem(..) => { + // Private modules may survive the strip-private pass if they + // contain impls for public types. These modules can also + // contain items such as publicly reexported structures. + // + // External crates will provide links to these structures, so + // these modules are recursed into, but not rendered normally (a + // flag on the context). + if !self.render_redirect_pages { + self.render_redirect_pages = ignore_private_module(&item); + } + let name = item.name.get_ref().to_string(); let mut item = Some(item); self.recurse(name, |this| { @@ -1120,17 +1203,21 @@ impl<'a> fmt::Show for Item<'a> { clean::TraitItem(..) => try!(write!(fmt, "Trait ")), clean::StructItem(..) => try!(write!(fmt, "Struct ")), clean::EnumItem(..) => try!(write!(fmt, "Enum ")), + clean::PrimitiveItem(..) => try!(write!(fmt, "Primitive Type ")), _ => {} } - let cur = self.cx.current.as_slice(); - let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() }; - for (i, component) in cur.iter().enumerate().take(amt) { - let mut trail = String::new(); - for _ in range(0, cur.len() - i - 1) { - trail.push_str("../"); + let is_primitive = match self.item.inner { + clean::PrimitiveItem(..) => true, + _ => false, + }; + if !is_primitive { + let cur = self.cx.current.as_slice(); + let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() }; + for (i, component) in cur.iter().enumerate().take(amt) { + try!(write!(fmt, "{}::", + "../".repeat(cur.len() - i - 1), + component.as_slice())); } - try!(write!(fmt, "{}::", - trail, component.as_slice())); } try!(write!(fmt, "{}", shortty(self.item), self.item.name.get_ref().as_slice())); @@ -1155,7 +1242,7 @@ impl<'a> fmt::Show for Item<'a> { // [src] link in the downstream documentation will actually come back to // this page, and this link will be auto-clicked. The `id` attribute is // used to find the link to auto-click. - if self.cx.include_sources { + if self.cx.include_sources && !is_primitive { match self.href() { Some(l) => { try!(write!(fmt, @@ -1179,6 +1266,7 @@ impl<'a> fmt::Show for Item<'a> { clean::EnumItem(ref e) => item_enum(fmt, self.item, e), clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t), clean::MacroItem(ref m) => item_macro(fmt, self.item, m), + clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p), _ => Ok(()) } } @@ -1234,8 +1322,9 @@ fn document(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result { fn item_module(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item, items: &[clean::Item]) -> fmt::Result { try!(document(w, item)); - debug!("{:?}", items); - let mut indices = Vec::from_fn(items.len(), |i| i); + let mut indices = range(0, items.len()).filter(|i| { + !ignore_private_module(&items[*i]) + }).collect::>(); fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering { if shortty(i1) == shortty(i2) { @@ -1251,6 +1340,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } (&clean::ViewItemItem(..), _) => Less, (_, &clean::ViewItemItem(..)) => Greater, + (&clean::PrimitiveItem(..), _) => Less, + (_, &clean::PrimitiveItem(..)) => Greater, (&clean::ModuleItem(..), _) => Less, (_, &clean::ModuleItem(..)) => Greater, (&clean::MacroItem(..), _) => Less, @@ -1275,7 +1366,6 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, } } - debug!("{:?}", indices); indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2)); debug!("{:?}", indices); @@ -1306,6 +1396,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, clean::ForeignFunctionItem(..) => ("ffi-fns", "Foreign Functions"), clean::ForeignStaticItem(..) => ("ffi-statics", "Foreign Statics"), clean::MacroItem(..) => ("macros", "Macros"), + clean::PrimitiveItem(..) => ("primitives", "Primitive Types"), }; try!(write!(w, "

\ @@ -1322,8 +1413,13 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, if s.len() == 0 { return Ok(()); } try!(write!(f, " = ")); if s.contains("\n") { - write!(f, "[definition]", - item.href()) + match item.href() { + Some(url) => { + write!(f, "[definition]", + url) + } + None => Ok(()), + } } else { write!(f, "{}", s.as_slice()) } @@ -1473,34 +1569,33 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "")); } - match cache_key.get().unwrap().implementors.find(&it.def_id) { + let cache = cache_key.get().unwrap(); + try!(write!(w, " +

Implementors

+
    + ")); + match cache.implementors.find(&it.def_id) { Some(implementors) => { - try!(write!(w, " -

    Implementors

    -
      - ")); for i in implementors.iter() { - match *i { - PathType(ref ty) => { - try!(write!(w, "
    • {}
    • ", *ty)); - } - OtherType(ref generics, ref trait_, ref for_) => { - try!(write!(w, "
    • impl{} {} for {}
    • ", - *generics, *trait_, *for_)); - } - } + try!(writeln!(w, "
    • impl{} {} for {}
    • ", + i.generics, i.trait_, i.for_)); } - try!(write!(w, "
    ")); - try!(write!(w, r#""#, - cx.current.iter().map(|_| "..") - .collect::>().connect("/"), - cx.current.connect("/"), - shortty(it).to_static_str(), - *it.name.get_ref())); } None => {} } + try!(write!(w, "
")); + try!(write!(w, r#""#, + root_path = Vec::from_elem(cx.current.len(), "..").connect("/"), + path = if ast_util::is_local(it.def_id) { + cx.current.connect("/") + } else { + let path = cache.external_paths.get(&it.def_id); + path.slice_to(path.len() - 1).connect("/") + }, + ty = shortty(it).to_static_str(), + name = *it.name.get_ref())); Ok(()) } @@ -1879,8 +1974,11 @@ impl<'a> fmt::Show for Sidebar<'a> { try!(write!(w, "

{}

", short, longty)); for item in items.iter() { let curty = shortty(cur).to_static_str(); - let class = if cur.name.get_ref() == item && - short == curty { "current" } else { "" }; + let class = if cur.name.get_ref() == item && short == curty { + "current" + } else { + "" + }; try!(write!(w, " fmt::Show for Sidebar<'a> { fn build_sidebar(m: &clean::Module) -> HashMap> { let mut map = HashMap::new(); for item in m.items.iter() { + if ignore_private_module(item) { continue } + let short = shortty(item).to_static_str(); let myname = match item.name { None => continue, @@ -1951,3 +2051,20 @@ fn item_macro(w: &mut fmt::Formatter, it: &clean::Item, try!(w.write(highlight::highlight(t.source.as_slice(), Some("macro")).as_bytes())); document(w, it) } + +fn item_primitive(w: &mut fmt::Formatter, + it: &clean::Item, + _p: &clean::Primitive) -> fmt::Result { + try!(document(w, it)); + render_methods(w, it) +} + +fn ignore_private_module(it: &clean::Item) -> bool { + match it.inner { + clean::ModuleItem(ref m) => { + (m.items.len() == 0 && it.doc_value().is_none()) || + it.visibility != Some(ast::Public) + } + _ => false, + } +} diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 2fb824653d3db..6c9bc793582b6 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -527,7 +527,8 @@ "variant", "ffi", "ffs", - "macro"]; + "macro", + "primitive"]; function itemTypeFromName(typename) { for (var i = 0; i < itemTypes.length; ++i) { @@ -658,15 +659,13 @@ var list = $('#implementors-list'); var libs = Object.getOwnPropertyNames(imp); for (var i = 0; i < libs.length; i++) { - var structs = Object.getOwnPropertyNames(imp[libs[i]]); + if (libs[i] == currentCrate) continue; + var structs = imp[libs[i]]; for (var j = 0; j < structs.length; j++) { - console.log(i, structs[j]); - var path = rootPath + imp[libs[i]][structs[j]]; - var klass = path.contains("type.") ? "type" : "struct"; - var link = $('').text(structs[j]) - .attr('href', path) - .attr('class', klass); - var code = $('').append(link); + var code = $('').append(structs[j]); + $.each(code.find('a'), function(idx, a) { + $(a).attr('href', rootPath + $(a).attr('href')); + }); var li = $('
  • ').append(code); list.append(li); } diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index efb0689404a5d..7176ad1a6c151 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -67,11 +67,22 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult { fn fold_item(&mut self, i: Item) -> Option { match i.inner { clean::ImplItem(clean::Impl{ - for_: clean::ResolvedPath{ did, .. }, .. + for_: clean::ResolvedPath{ did, .. }, + ref trait_, .. }) => { + // Impls for stripped types don't need to exist if self.stripped.contains(&did.node) { return None; } + // Impls of stripped traits also don't need to exist + match *trait_ { + Some(clean::ResolvedPath { did, .. }) => { + if self.stripped.contains(&did.node) { + return None + } + } + _ => {} + } } _ => {} } @@ -161,6 +172,9 @@ impl<'a> fold::DocFolder for Stripper<'a> { // tymethods/macros have no control over privacy clean::MacroItem(..) | clean::TyMethodItem(..) => {} + + // Primitives are never stripped + clean::PrimitiveItem(..) => {} } let fastreturn = match i.inner { diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index e5fc8f1f1a178..c1f61de9be2f7 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -79,6 +79,7 @@ pub fn run(input: &str, external_traits: RefCell::new(None), external_typarams: RefCell::new(None), inlined: RefCell::new(None), + populated_crate_impls: RefCell::new(HashSet::new()), }; super::ctxtkey.replace(Some(ctx)); diff --git a/src/librustuv/homing.rs b/src/librustuv/homing.rs index 5bb9c70f04795..4f565de6791d4 100644 --- a/src/librustuv/homing.rs +++ b/src/librustuv/homing.rs @@ -82,6 +82,7 @@ pub fn local_id() -> uint { } } +#[doc(hidden)] pub trait HomingIO { fn home<'r>(&'r mut self) -> &'r mut HomeHandle; diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index b7bd3705bf20b..bbf1458da216e 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -12,6 +12,7 @@ #![allow(missing_doc)] #![allow(unsigned_negate)] +#![doc(primitive = "f32")] use prelude::*; diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index e7b29c733ec0f..cfa8534160bae 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -11,6 +11,7 @@ //! Operations and constants for 64-bits floats (`f64` type) #![allow(missing_doc)] +#![doc(primitive = "f64")] use prelude::*; diff --git a/src/libstd/num/i16.rs b/src/libstd/num/i16.rs index e0c5d93f28abc..cfa0662e2256d 100644 --- a/src/libstd/num/i16.rs +++ b/src/libstd/num/i16.rs @@ -10,6 +10,8 @@ //! Operations and constants for signed 16-bits integers (`i16` type) +#![doc(primitive = "i16")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/i32.rs b/src/libstd/num/i32.rs index 6938689f47d70..3c656b20ee524 100644 --- a/src/libstd/num/i32.rs +++ b/src/libstd/num/i32.rs @@ -10,6 +10,8 @@ //! Operations and constants for signed 32-bits integers (`i32` type) +#![doc(primitive = "i32")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/i64.rs b/src/libstd/num/i64.rs index 4be43876105cb..857f78efc9cfd 100644 --- a/src/libstd/num/i64.rs +++ b/src/libstd/num/i64.rs @@ -10,6 +10,8 @@ //! Operations and constants for signed 64-bits integers (`i64` type) +#![doc(primitive = "i64")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/i8.rs b/src/libstd/num/i8.rs index b0459ca46f1af..a939c1d6b7629 100644 --- a/src/libstd/num/i8.rs +++ b/src/libstd/num/i8.rs @@ -10,6 +10,8 @@ //! Operations and constants for signed 8-bits integers (`i8` type) +#![doc(primitive = "i8")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/int.rs b/src/libstd/num/int.rs index 774b0d7d8cf64..415d11b3145b3 100644 --- a/src/libstd/num/int.rs +++ b/src/libstd/num/int.rs @@ -10,6 +10,8 @@ //! Operations and constants for architecture-sized signed integers (`int` type) +#![doc(primitive = "int")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/u16.rs b/src/libstd/num/u16.rs index 5200fbd7a3b4b..3b018414be2d4 100644 --- a/src/libstd/num/u16.rs +++ b/src/libstd/num/u16.rs @@ -10,6 +10,8 @@ //! Operations and constants for unsigned 16-bits integers (`u16` type) +#![doc(primitive = "u16")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/u32.rs b/src/libstd/num/u32.rs index 18cdb9e7e87d2..980129431095d 100644 --- a/src/libstd/num/u32.rs +++ b/src/libstd/num/u32.rs @@ -10,6 +10,8 @@ //! Operations and constants for unsigned 32-bits integers (`u32` type) +#![doc(primitive = "u32")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/u64.rs b/src/libstd/num/u64.rs index 7c17d2cd0bdb3..b3a8bfc20df15 100644 --- a/src/libstd/num/u64.rs +++ b/src/libstd/num/u64.rs @@ -10,6 +10,8 @@ //! Operations and constants for unsigned 64-bits integer (`u64` type) +#![doc(primitive = "u64")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/u8.rs b/src/libstd/num/u8.rs index 05d86fba40e80..d72049d253302 100644 --- a/src/libstd/num/u8.rs +++ b/src/libstd/num/u8.rs @@ -10,6 +10,8 @@ //! Operations and constants for unsigned 8-bits integers (`u8` type) +#![doc(primitive = "u8")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/num/uint.rs b/src/libstd/num/uint.rs index ac38f74093180..1f43ad8af3398 100644 --- a/src/libstd/num/uint.rs +++ b/src/libstd/num/uint.rs @@ -10,6 +10,8 @@ //! Operations and constants for architecture-sized unsigned integers (`uint` type) +#![doc(primitive = "uint")] + use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::strconv; diff --git a/src/libstd/slice.rs b/src/libstd/slice.rs index 1433270346e76..430629a1f88f1 100644 --- a/src/libstd/slice.rs +++ b/src/libstd/slice.rs @@ -97,6 +97,8 @@ There are a number of free functions that create or take vectors, for example: */ +#![doc(primitive = "slice")] + use mem::transmute; use clone::Clone; use cmp::{TotalOrd, Ordering, Less, Greater}; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index a35b4e7a151a0..11b9d0e85ff25 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -65,6 +65,8 @@ is the same as `&[u8]`. */ +#![doc(primitive = "str")] + use char::Char; use char; use clone::Clone; diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs index e2290129dc8b4..aecfe935d30fb 100644 --- a/src/libsyntax/ext/deriving/generic/mod.rs +++ b/src/libsyntax/ext/deriving/generic/mod.rs @@ -288,7 +288,7 @@ pub enum SubstructureFields<'a> { /** non-matching variants of the enum, [(variant index, ast::Variant, - [field span, field ident, fields])] (i.e. all fields for self are in the + [field span, field ident, fields])] \(i.e. all fields for self are in the first tuple, for other1 are in the second tuple, etc.) */ EnumNonMatching(&'a [(uint, P, Vec<(Span, Option, @Expr)> )]),