提交 4e0b9369 编写于 作者: B bors

auto merge of #14513 : alexcrichton/rust/rustdoc-primitives, r=huonw

This is currently rebased on top of #14478, but that's just to preemptively avoid rebase conflicts and to provide a better preview. This can land independently of that PR.

This change crates a dedicated page in rustdoc for primitive types to outline everything you can do with them (at least in a basic way).

* Preview - http://people.mozilla.org/~acrichton/doc/
* Exhibit A - http://people.mozilla.org/~acrichton/doc/std/#primitives
* Exhibit B - http://people.mozilla.org/~acrichton/doc/std/primitive.str.html
* Exhibit C - http://people.mozilla.org/~acrichton/doc/std/primitive.slice.html

Please don't hesitate to be nitpickity, it's easy to overlook a thing here or there!
......@@ -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<int> = 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<String> =
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<uint> = 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<u32> = 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<int> = 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
......
......@@ -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
......@@ -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
......
......@@ -97,6 +97,7 @@
pub mod rc;
#[cfg(not(test))]
#[doc(hidden)]
mod std {
pub use core::fmt;
pub use core::option;
......
......@@ -12,6 +12,8 @@
//!
//! A `to_bit` conversion function.
#![doc(primitive = "bool")]
use num::{Int, one, zero};
/////////////////////////////////////////////////////////////////////////////
......
......@@ -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};
......
......@@ -134,10 +134,12 @@
// crate.
mod should_not_exist;
#[doc(hidden)]
mod core {
pub use failure;
}
#[doc(hidden)]
mod std {
pub use clone;
pub use cmp;
......
......@@ -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};
......
......@@ -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};
......
......@@ -10,5 +10,7 @@
//! Operations and constants for signed 16-bits integers (`i16` type)
#![doc(primitive = "i16")]
int_module!(i16, 16)
......@@ -10,5 +10,7 @@
//! Operations and constants for signed 32-bits integers (`i32` type)
#![doc(primitive = "i32")]
int_module!(i32, 32)
......@@ -10,5 +10,7 @@
//! Operations and constants for signed 64-bits integers (`i64` type)
#![doc(primitive = "i64")]
int_module!(i64, 64)
......@@ -10,5 +10,7 @@
//! Operations and constants for signed 8-bits integers (`i8` type)
#![doc(primitive = "i8")]
int_module!(i8, 8)
......@@ -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)
......@@ -10,4 +10,6 @@
//! Operations and constants for unsigned 16-bits integers (`u16` type)
#![doc(primitive = "u16")]
uint_module!(u16, i16, 16)
......@@ -10,5 +10,7 @@
//! Operations and constants for unsigned 32-bits integers (`u32` type)
#![doc(primitive = "u32")]
uint_module!(u32, i32, 32)
......@@ -10,5 +10,7 @@
//! Operations and constants for unsigned 64-bits integer (`u64` type)
#![doc(primitive = "u64")]
uint_module!(u64, i64, 64)
......@@ -10,5 +10,7 @@
//! Operations and constants for unsigned 8-bits integers (`u8` type)
#![doc(primitive = "u8")]
uint_module!(u8, i8, 8)
......@@ -10,5 +10,7 @@
//! Operations and constants for architecture-sized unsigned integers (`uint` type)
#![doc(primitive = "uint")]
uint_module!(uint, int, ::int::BITS)
......@@ -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
......
......@@ -12,6 +12,8 @@
//!
//! For more details `std::slice`.
#![doc(primitive = "slice")]
use mem::transmute;
use clone::Clone;
use container::Container;
......
......@@ -12,6 +12,8 @@
//!
//! For more details, see std::str
#![doc(primitive = "str")]
use mem;
use char;
use clone::Clone;
......
......@@ -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;
......
......@@ -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<clean::Item> {
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<clean::Item>) {
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"),
}
});
......
......@@ -28,6 +28,7 @@
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<Item>,
pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
pub primitives: Vec<Primitive>,
}
impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
......@@ -92,6 +94,7 @@ fn clean(&self) -> Crate {
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 @@ fn clean(&self) -> Crate {
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 @@ fn clean(&self) -> Crate {
pub struct ExternalCrate {
pub name: String,
pub attrs: Vec<Attribute>,
pub primitives: Vec<Primitive>,
}
impl Clean<ExternalCrate> 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 @@ fn clean(&self) -> 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 @@ fn clean(&self) -> TyParamBound {
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 @@ fn clean(&self) -> TyParamBound {
let fqn = csearch::get_item_path(tcx, self.def_id);
let fqn = fqn.move_iter().map(|i| i.to_str().to_string())
.collect::<Vec<String>>();
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 @@ fn clean(&self) -> Option<Lifetime> {
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<ClosureDecl>, Option<Lifetime>),
Proc(Box<ClosureDecl>),
/// extern "ABI" fn
......@@ -928,10 +1015,6 @@ pub enum Type {
Tuple(Vec<Type>),
Vector(Box<Type>),
FixedVector(Box<Type>, String),
String,
Bool,
/// aka TyNil
Unit,
/// aka TyBot
Bottom,
Unique(Box<Type>),
......@@ -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<Primitive> {
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<Primitive> {
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<Type> 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 @@ fn clean(&self) -> Type {
impl Clean<Type> 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 @@ fn clean(&self) -> Type {
let fqn: Vec<String> = 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<Vec<TyParamBound>>,
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<Vec<TyParamBound>>,
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),
......
......@@ -42,6 +42,7 @@ pub struct DocContext {
pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
}
impl DocContext {
......@@ -114,6 +115,7 @@ fn get_ast_and_resolve(cpath: &Path, libs: HashSet<Path>, cfgs: Vec<String>)
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,
......
......@@ -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, "<a href='{}primitive.{}.html'>",
"../".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, "<a href='{}{}/primitive.{}.html'>",
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, "</a>"));
}
Ok(())
}
/// Helper to render type parameters
fn tybounds(w: &mut fmt::Formatter,
typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result {
......@@ -297,27 +344,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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{ -&gt; {ret}} other{}}",
......@@ -329,7 +356,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
},
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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
": {}",
m.collect::<Vec<String>>().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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
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{ -&gt; {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 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,
"({args}){arrow, select, yes{ -&gt; {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)
}
}
......
......@@ -37,6 +37,7 @@ pub enum ItemType {
ForeignFunction = 13,
ForeignStatic = 14,
Macro = 15,
Primitive = 16,
}
impl ItemType {
......@@ -58,6 +59,7 @@ pub fn to_static_str(&self) -> &'static str {
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,
}
}
......@@ -130,3 +130,17 @@ pub fn render<T: fmt::Show, S: fmt::Show>(
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##"<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="refresh" content="0;URL={url}">
</head>
<body>
</body>
</html>"##,
url = url,
)
}
......@@ -70,7 +70,7 @@
pub struct Context {
/// Current hierarchy of components leading down to what's currently being
/// rendered
pub current: Vec<String> ,
pub current: Vec<String>,
/// 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<ast::CrateNum, ExternalLocation>,
/// Cache of where documentation for primitives can be found.
pub primitive_locations: HashMap<clean::Primitive, ast::CrateNum>,
/// Set of definitions which have been inlined from external crates.
pub inlined: HashSet<ast::DefId>,
......@@ -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<String> {
// 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<Vec<String>> {
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<Vec<String>> {
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<clean::Crate> {
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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
}
// 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 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
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 @@ fn recurse<T>(&mut self, s: String, f: |&mut Context| -> T) -> T {
///
/// 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 @@ fn krate(self, mut krate: clean::Crate, cache: Cache) -> io::IoResult<()> {
/// 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 @@ fn render(w: io::File, cx: &mut Context, it: &clean::Item,
// 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 @@ fn render(w: io::File, cx: &mut Context, it: &clean::Item,
// 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 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
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, "<a href='{}index.html'>{}</a>::",
"../".repeat(cur.len() - i - 1),
component.as_slice()));
}
try!(write!(fmt, "<a href='{}index.html'>{}</a>::",
trail, component.as_slice()));
}
try!(write!(fmt, "<a class='{}' href=''>{}</a>",
shortty(self.item), self.item.name.get_ref().as_slice()));
......@@ -1155,7 +1242,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
// [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 @@ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
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::<Vec<uint>>();
fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
if shortty(i1) == shortty(i2) {
......@@ -1251,6 +1340,8 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
}
(&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 cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
}
}
debug!("{:?}", indices);
indices.sort_by(|&i1, &i2| cmp(&items[i1], &items[i2], i1, i2));
debug!("{:?}", indices);
......@@ -1306,6 +1396,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, idx1: uint, idx2: uint) -> Ordering {
clean::ForeignFunctionItem(..) => ("ffi-fns", "Foreign Functions"),
clean::ForeignStaticItem(..) => ("ffi-statics", "Foreign Statics"),
clean::MacroItem(..) => ("macros", "Macros"),
clean::PrimitiveItem(..) => ("primitives", "Primitive Types"),
};
try!(write!(w,
"<h2 id='{id}' class='section-header'>\
......@@ -1322,8 +1413,13 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if s.len() == 0 { return Ok(()); }
try!(write!(f, "<code> = </code>"));
if s.contains("\n") {
write!(f, "<a href='{}'>[definition]</a>",
item.href())
match item.href() {
Some(url) => {
write!(f, "<a href='{}'>[definition]</a>",
url)
}
None => Ok(()),
}
} else {
write!(f, "<code>{}</code>", s.as_slice())
}
......@@ -1473,34 +1569,33 @@ fn meth(w: &mut fmt::Formatter, m: &clean::TraitMethod) -> fmt::Result {
try!(write!(w, "</div>"));
}
match cache_key.get().unwrap().implementors.find(&it.def_id) {
let cache = cache_key.get().unwrap();
try!(write!(w, "
<h2 id='implementors'>Implementors</h2>
<ul class='item-list' id='implementors-list'>
"));
match cache.implementors.find(&it.def_id) {
Some(implementors) => {
try!(write!(w, "
<h2 id='implementors'>Implementors</h2>
<ul class='item-list' id='implementors-list'>
"));
for i in implementors.iter() {
match *i {
PathType(ref ty) => {
try!(write!(w, "<li><code>{}</code></li>", *ty));
}
OtherType(ref generics, ref trait_, ref for_) => {
try!(write!(w, "<li><code>impl{} {} for {}</code></li>",
*generics, *trait_, *for_));
}
}
try!(writeln!(w, "<li><code>impl{} {} for {}</code></li>",
i.generics, i.trait_, i.for_));
}
try!(write!(w, "</ul>"));
try!(write!(w, r#"<script type="text/javascript" async
src="{}/implementors/{}/{}.{}.js"></script>"#,
cx.current.iter().map(|_| "..")
.collect::<Vec<&str>>().connect("/"),
cx.current.connect("/"),
shortty(it).to_static_str(),
*it.name.get_ref()));
}
None => {}
}
try!(write!(w, "</ul>"));
try!(write!(w, r#"<script type="text/javascript" async
src="{root_path}/implementors/{path}/{ty}.{name}.js">
</script>"#,
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 @@ fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
try!(write!(w, "<div class='block {}'><h2>{}</h2>", 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, "<a class='{ty} {class}' href='{curty, select,
mod{../}
other{}
......@@ -1911,6 +2009,8 @@ fn block(w: &mut fmt::Formatter, short: &str, longty: &str,
fn build_sidebar(m: &clean::Module) -> HashMap<String, Vec<String>> {
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,
}
}
......@@ -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 = $('<a>').text(structs[j])
.attr('href', path)
.attr('class', klass);
var code = $('<code>').append(link);
var code = $('<code>').append(structs[j]);
$.each(code.find('a'), function(idx, a) {
$(a).attr('href', rootPath + $(a).attr('href'));
});
var li = $('<li>').append(code);
list.append(li);
}
......
......@@ -67,11 +67,22 @@ impl<'a> fold::DocFolder for ImplStripper<'a> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
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 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
// tymethods/macros have no control over privacy
clean::MacroItem(..) | clean::TyMethodItem(..) => {}
// Primitives are never stripped
clean::PrimitiveItem(..) => {}
}
let fastreturn = match i.inner {
......
......@@ -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));
......
......@@ -82,6 +82,7 @@ pub fn local_id() -> uint {
}
}
#[doc(hidden)]
pub trait HomingIO {
fn home<'r>(&'r mut self) -> &'r mut HomeHandle;
......
......@@ -12,6 +12,7 @@
#![allow(missing_doc)]
#![allow(unsigned_negate)]
#![doc(primitive = "f32")]
use prelude::*;
......
......@@ -11,6 +11,7 @@
//! Operations and constants for 64-bits floats (`f64` type)
#![allow(missing_doc)]
#![doc(primitive = "f64")]
use prelude::*;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
......
......@@ -97,6 +97,8 @@
*/
#![doc(primitive = "slice")]
use mem::transmute;
use clone::Clone;
use cmp::{TotalOrd, Ordering, Less, Greater};
......
......@@ -65,6 +65,8 @@ fn main() {
*/
#![doc(primitive = "str")]
use char::Char;
use char;
use clone::Clone;
......
......@@ -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<ast::Variant>, Vec<(Span, Option<Ident>, @Expr)> )]),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册