1
Fork 0

rustdoc: Create anchor pages for primitive types

This commit adds support in rustdoc to recognize the `#[doc(primitive = "foo")]`
attribute. This attribute indicates that the current module is the "owner" of
the primitive type `foo`. For rustdoc, this means that the doc-comment for the
module is the doc-comment for the primitive type, plus a signal to all
downstream crates that hyperlinks for primitive types will be directed at the
crate containing the `#[doc]` directive.

Additionally, rustdoc will favor crates closest to the one being documented
which "implements the primitive type". For example, documentation of libcore
links to libcore for primitive types, but documentation for libstd and beyond
all links to libstd for primitive types.

This change involves no compiler modifications, it is purely a rustdoc change.
The landing pages for the primitive types primarily serve to show a list of
implemented traits for the primitive type itself.

The primitive types documented includes both strings and slices in a semi-ad-hoc
way, but in a way that should provide at least somewhat meaningful
documentation.

Closes #14474
This commit is contained in:
Alex Crichton 2014-05-28 19:53:37 -07:00
parent ba9be0a72b
commit c2e3aa37da
37 changed files with 444 additions and 88 deletions

View file

@ -12,6 +12,8 @@
//! //!
//! A `to_bit` conversion function. //! A `to_bit` conversion function.
#![doc(primitive = "bool")]
use num::{Int, one, zero}; use num::{Int, one, zero};
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////

View file

@ -24,6 +24,7 @@
//! and, as such, should be performed via the `from_u32` function.. //! and, as such, should be performed via the `from_u32` function..
#![allow(non_snake_case_functions)] #![allow(non_snake_case_functions)]
#![doc(primitive = "char")]
use mem::transmute; use mem::transmute;
use option::{None, Option, Some}; use option::{None, Option, Some};

View file

@ -10,6 +10,8 @@
//! Operations and constants for 32-bits floats (`f32` type) //! Operations and constants for 32-bits floats (`f32` type)
#![doc(primitive = "f32")]
use intrinsics; use intrinsics;
use mem; use mem;
use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};

View file

@ -10,6 +10,8 @@
//! Operations and constants for 64-bits floats (`f64` type) //! Operations and constants for 64-bits floats (`f64` type)
#![doc(primitive = "f64")]
use intrinsics; use intrinsics;
use mem; use mem;
use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN}; use num::{FPNormal, FPCategory, FPZero, FPSubnormal, FPInfinite, FPNaN};

View file

@ -10,5 +10,7 @@
//! Operations and constants for signed 16-bits integers (`i16` type) //! Operations and constants for signed 16-bits integers (`i16` type)
#![doc(primitive = "i16")]
int_module!(i16, 16) int_module!(i16, 16)

View file

@ -10,5 +10,7 @@
//! Operations and constants for signed 32-bits integers (`i32` type) //! Operations and constants for signed 32-bits integers (`i32` type)
#![doc(primitive = "i32")]
int_module!(i32, 32) int_module!(i32, 32)

View file

@ -10,5 +10,7 @@
//! Operations and constants for signed 64-bits integers (`i64` type) //! Operations and constants for signed 64-bits integers (`i64` type)
#![doc(primitive = "i64")]
int_module!(i64, 64) int_module!(i64, 64)

View file

@ -10,5 +10,7 @@
//! Operations and constants for signed 8-bits integers (`i8` type) //! Operations and constants for signed 8-bits integers (`i8` type)
#![doc(primitive = "i8")]
int_module!(i8, 8) int_module!(i8, 8)

View file

@ -10,6 +10,8 @@
//! Operations and constants for architecture-sized signed integers (`int` type) //! 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 = "32")] int_module!(int, 32)
#[cfg(target_word_size = "64")] int_module!(int, 64) #[cfg(target_word_size = "64")] int_module!(int, 64)

View file

@ -10,4 +10,6 @@
//! Operations and constants for unsigned 16-bits integers (`u16` type) //! Operations and constants for unsigned 16-bits integers (`u16` type)
#![doc(primitive = "u16")]
uint_module!(u16, i16, 16) uint_module!(u16, i16, 16)

View file

@ -10,5 +10,7 @@
//! Operations and constants for unsigned 32-bits integers (`u32` type) //! Operations and constants for unsigned 32-bits integers (`u32` type)
#![doc(primitive = "u32")]
uint_module!(u32, i32, 32) uint_module!(u32, i32, 32)

View file

@ -10,5 +10,7 @@
//! Operations and constants for unsigned 64-bits integer (`u64` type) //! Operations and constants for unsigned 64-bits integer (`u64` type)
#![doc(primitive = "u64")]
uint_module!(u64, i64, 64) uint_module!(u64, i64, 64)

View file

@ -10,5 +10,7 @@
//! Operations and constants for unsigned 8-bits integers (`u8` type) //! Operations and constants for unsigned 8-bits integers (`u8` type)
#![doc(primitive = "u8")]
uint_module!(u8, i8, 8) uint_module!(u8, i8, 8)

View file

@ -10,5 +10,7 @@
//! Operations and constants for architecture-sized unsigned integers (`uint` type) //! Operations and constants for architecture-sized unsigned integers (`uint` type)
#![doc(primitive = "uint")]
uint_module!(uint, int, ::int::BITS) uint_module!(uint, int, ::int::BITS)

View file

@ -12,6 +12,8 @@
//! //!
//! For more details `std::slice`. //! For more details `std::slice`.
#![doc(primitive = "slice")]
use mem::transmute; use mem::transmute;
use clone::Clone; use clone::Clone;
use container::Container; use container::Container;

View file

@ -12,6 +12,8 @@
//! //!
//! For more details, see std::str //! For more details, see std::str
#![doc(primitive = "str")]
use mem; use mem;
use char; use char;
use clone::Clone; use clone::Clone;

View file

@ -59,6 +59,8 @@
//! assert_eq!(d, (0u32, 0.0f32)); //! assert_eq!(d, (0u32, 0.0f32));
//! ``` //! ```
#![doc(primitive = "tuple")]
use clone::Clone; use clone::Clone;
#[cfg(not(test))] use cmp::*; #[cfg(not(test))] use cmp::*;
#[cfg(not(test))] use default::Default; #[cfg(not(test))] use default::Default;

View file

@ -28,6 +28,7 @@ use rustc::metadata::decoder;
use rustc::middle::ty; use rustc::middle::ty;
use std::rc::Rc; use std::rc::Rc;
use std::u32;
use core; use core;
use doctree; use doctree;
@ -81,6 +82,7 @@ pub struct Crate {
pub name: String, pub name: String,
pub module: Option<Item>, pub module: Option<Item>,
pub externs: Vec<(ast::CrateNum, ExternalCrate)>, pub externs: Vec<(ast::CrateNum, ExternalCrate)>,
pub primitives: Vec<Primitive>,
} }
impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> { impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
@ -92,6 +94,7 @@ impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
externs.push((n, meta.clean())); externs.push((n, meta.clean()));
}); });
// Figure out the name of this crate
let input = driver::FileInput(cx.src.clone()); let input = driver::FileInput(cx.src.clone());
let t_outputs = driver::build_output_filenames(&input, let t_outputs = driver::build_output_filenames(&input,
&None, &None,
@ -100,10 +103,47 @@ impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
cx.sess()); cx.sess());
let id = link::find_crate_id(self.attrs.as_slice(), let id = link::find_crate_id(self.attrs.as_slice(),
t_outputs.out_filestem.as_slice()); t_outputs.out_filestem.as_slice());
// Clean the module, 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.
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 { Crate {
name: id.name.to_string(), name: id.name.to_string(),
module: Some(self.module.clean()), module: Some(module),
externs: externs, externs: externs,
primitives: primitives,
} }
} }
} }
@ -112,15 +152,35 @@ impl<'a> Clean<Crate> for visit_ast::RustdocVisitor<'a> {
pub struct ExternalCrate { pub struct ExternalCrate {
pub name: String, pub name: String,
pub attrs: Vec<Attribute>, pub attrs: Vec<Attribute>,
pub primitives: Vec<Primitive>,
} }
impl Clean<ExternalCrate> for cstore::crate_metadata { impl Clean<ExternalCrate> for cstore::crate_metadata {
fn clean(&self) -> ExternalCrate { 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 { ExternalCrate {
name: self.name.to_string(), name: self.name.to_string(),
attrs: decoder::get_crate_attributes(self.data()).clean() attrs: decoder::get_crate_attributes(self.data()).clean(),
.move_iter() primitives: primitives,
.collect(),
} }
} }
} }
@ -227,6 +287,7 @@ pub enum ItemEnum {
/// `static`s from an extern block /// `static`s from an extern block
ForeignStaticItem(Static), ForeignStaticItem(Static),
MacroItem(Macro), MacroItem(Macro),
PrimitiveItem(Primitive),
} }
#[deriving(Clone, Encodable, Decodable)] #[deriving(Clone, Encodable, Decodable)]
@ -931,7 +992,7 @@ pub enum Type {
/// For references to self /// For references to self
Self(ast::DefId), Self(ast::DefId),
/// Primitives are just the fixed-size numeric types (plus int/uint/float), and char. /// Primitives are just the fixed-size numeric types (plus int/uint/float), and char.
Primitive(ast::PrimTy), Primitive(Primitive),
Closure(Box<ClosureDecl>, Option<Lifetime>), Closure(Box<ClosureDecl>, Option<Lifetime>),
Proc(Box<ClosureDecl>), Proc(Box<ClosureDecl>),
/// extern "ABI" fn /// extern "ABI" fn
@ -939,10 +1000,6 @@ pub enum Type {
Tuple(Vec<Type>), Tuple(Vec<Type>),
Vector(Box<Type>), Vector(Box<Type>),
FixedVector(Box<Type>, String), FixedVector(Box<Type>, String),
String,
Bool,
/// aka TyNil
Unit,
/// aka TyBot /// aka TyBot
Bottom, Bottom,
Unique(Box<Type>), Unique(Box<Type>),
@ -956,6 +1013,19 @@ pub enum Type {
// region, raw, other boxes, mutable // region, raw, other boxes, mutable
} }
#[deriving(Clone, Encodable, Decodable, Eq, 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)] #[deriving(Clone, Encodable, Decodable)]
pub enum TypeKind { pub enum TypeKind {
TypeEnum, TypeEnum,
@ -967,11 +1037,97 @@ pub enum TypeKind {
TypeVariant, 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 { impl Clean<Type> for ast::Ty {
fn clean(&self) -> Type { fn clean(&self) -> Type {
use syntax::ast::*; use syntax::ast::*;
match self.node { match self.node {
TyNil => Unit, TyNil => Primitive(Nil),
TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()), TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()),
TyRptr(ref l, ref m) => TyRptr(ref l, ref m) =>
BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(), BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
@ -999,16 +1155,26 @@ impl Clean<Type> for ast::Ty {
impl Clean<Type> for ty::t { impl Clean<Type> for ty::t {
fn clean(&self) -> Type { fn clean(&self) -> Type {
match ty::get(*self).sty { match ty::get(*self).sty {
ty::ty_nil => Unit,
ty::ty_bot => Bottom, ty::ty_bot => Bottom,
ty::ty_bool => Bool, ty::ty_nil => Primitive(Nil),
ty::ty_char => Primitive(ast::TyChar), ty::ty_bool => Primitive(Bool),
ty::ty_int(t) => Primitive(ast::TyInt(t)), ty::ty_char => Primitive(Char),
ty::ty_uint(u) => Primitive(ast::TyUint(u)), ty::ty_int(ast::TyI) => Primitive(Int),
ty::ty_float(f) => Primitive(ast::TyFloat(f)), 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_box(t) => Managed(box t.clean()),
ty::ty_uniq(t) => Unique(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, None) => Vector(box mt.ty.clean()),
ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(), ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(),
format!("{}", i)), format!("{}", i)),
@ -1056,11 +1222,12 @@ impl Clean<Type> for ty::t {
ty::ty_trait(..) => TypeTrait, ty::ty_trait(..) => TypeTrait,
_ => TypeEnum, _ => TypeEnum,
}; };
let path = external_path(fqn.last().unwrap().to_str().as_slice(),
substs);
cx.external_paths.borrow_mut().get_mut_ref().insert(did, cx.external_paths.borrow_mut().get_mut_ref().insert(did,
(fqn, kind)); (fqn, kind));
ResolvedPath { ResolvedPath {
path: external_path(fqn.last().unwrap().to_str().as_slice(), path: path,
substs),
typarams: None, typarams: None,
did: did, did: did,
} }
@ -1748,7 +1915,7 @@ fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
let tycx = match cx.maybe_typed { let tycx = match cx.maybe_typed {
core::Typed(ref tycx) => tycx, core::Typed(ref tycx) => tycx,
// If we're extracting tests, this return value doesn't matter. // 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); debug!("searching for {:?} in defmap", id);
let def = match tycx.def_map.borrow().find(&id) { let def = match tycx.def_map.borrow().find(&id) {
@ -1759,9 +1926,22 @@ fn resolve_type(path: Path, tpbs: Option<Vec<TyParamBound>>,
match def { match def {
ast::DefSelfTy(i) => return Self(ast_util::local_def(i)), ast::DefSelfTy(i) => return Self(ast_util::local_def(i)),
ast::DefPrimTy(p) => match p { ast::DefPrimTy(p) => match p {
ast::TyStr => return String, ast::TyStr => return Primitive(Str),
ast::TyBool => return Bool, ast::TyBool => return Primitive(Bool),
_ => return Primitive(p) 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::DefTyParam(i, _) => return Generic(i),
ast::DefTyParamBinder(i) => return TyParamBinder(i), ast::DefTyParamBinder(i) => return TyParamBinder(i),

View file

@ -263,6 +263,47 @@ fn path(w: &mut fmt::Formatter, path: &clean::Path, print_all: bool,
Ok(()) 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 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())).to_string())
}
render::Unknown => None,
};
match loc {
Some(s) => {
try!(write!(f, "<a href='{}/primitive.{}.html'>",
s, 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 /// Helper to render type parameters
fn tybounds(w: &mut fmt::Formatter, fn tybounds(w: &mut fmt::Formatter,
typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result { typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result {
@ -297,27 +338,7 @@ impl fmt::Show for clean::Type {
tybounds(f, typarams) tybounds(f, typarams)
} }
clean::Self(..) => f.write("Self".as_bytes()), clean::Self(..) => f.write("Self".as_bytes()),
clean::Primitive(prim) => { clean::Primitive(prim) => primitive_link(f, prim, prim.to_str()),
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::Closure(ref decl, ref region) => { clean::Closure(ref decl, ref region) => {
write!(f, "{style}{lifetimes}|{args}|{bounds}\ write!(f, "{style}{lifetimes}|{args}|{bounds}\
{arrow, select, yes{ -&gt; {ret}} other{}}", {arrow, select, yes{ -&gt; {ret}} other{}}",
@ -329,7 +350,7 @@ impl fmt::Show for clean::Type {
}, },
args = decl.decl.inputs, args = decl.decl.inputs,
arrow = match decl.decl.output { arrow = match decl.decl.output {
clean::Unit => "no", clean::Primitive(clean::Nil) => "no",
_ => "yes", _ => "yes",
}, },
ret = decl.decl.output, ret = decl.decl.output,
@ -379,7 +400,10 @@ impl fmt::Show for clean::Type {
": {}", ": {}",
m.collect::<Vec<String>>().connect(" + ")) 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) ret = decl.decl.output)
} }
clean::BareFunction(ref decl) => { clean::BareFunction(ref decl) => {
@ -403,13 +427,13 @@ impl fmt::Show for clean::Type {
} }
f.write(")".as_bytes()) f.write(")".as_bytes())
} }
clean::Vector(ref t) => write!(f, "[{}]", **t), clean::Vector(ref t) => {
clean::FixedVector(ref t, ref s) => { primitive_link(f, clean::Slice, format!("[{}]", **t).as_slice())
write!(f, "[{}, ..{}]", **t, *s) }
clean::FixedVector(ref t, ref 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::Bottom => f.write("!".as_bytes()),
clean::Unique(ref t) => write!(f, "~{}", **t), clean::Unique(ref t) => write!(f, "~{}", **t),
clean::Managed(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 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({args}){arrow, select, yes{ -&gt; {ret}} other{}}", write!(f, "({args}){arrow, select, yes{ -&gt; {ret}} other{}}",
args = self.inputs, args = self.inputs,
arrow = match self.output { clean::Unit => "no", _ => "yes" }, arrow = match self.output {
clean::Primitive(clean::Nil) => "no",
_ => "yes"
},
ret = self.output) ret = self.output)
} }
} }
@ -490,7 +517,10 @@ impl<'a> fmt::Show for Method<'a> {
write!(f, write!(f,
"({args}){arrow, select, yes{ -&gt; {ret}} other{}}", "({args}){arrow, select, yes{ -&gt; {ret}} other{}}",
args = args, args = args,
arrow = match d.output { clean::Unit => "no", _ => "yes" }, arrow = match d.output {
clean::Primitive(clean::Nil) => "no",
_ => "yes"
},
ret = d.output) ret = d.output)
} }
} }

View file

@ -37,6 +37,7 @@ pub enum ItemType {
ForeignFunction = 13, ForeignFunction = 13,
ForeignStatic = 14, ForeignStatic = 14,
Macro = 15, Macro = 15,
Primitive = 16,
} }
impl ItemType { impl ItemType {
@ -58,6 +59,7 @@ impl ItemType {
ForeignFunction => "ffi", ForeignFunction => "ffi",
ForeignStatic => "ffs", ForeignStatic => "ffs",
Macro => "macro", Macro => "macro",
Primitive => "primitive",
} }
} }
} }
@ -92,6 +94,7 @@ pub fn shortty(item: &clean::Item) -> ItemType {
clean::ForeignFunctionItem(..) => ForeignFunction, clean::ForeignFunctionItem(..) => ForeignFunction,
clean::ForeignStaticItem(..) => ForeignStatic, clean::ForeignStaticItem(..) => ForeignStatic,
clean::MacroItem(..) => Macro, clean::MacroItem(..) => Macro,
clean::PrimitiveItem(..) => Primitive,
} }
} }

View file

@ -157,6 +157,9 @@ pub struct Cache {
/// Cache of where external crate documentation can be found. /// Cache of where external crate documentation can be found.
pub extern_locations: HashMap<ast::CrateNum, ExternalLocation>, 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. /// Set of definitions which have been inlined from external crates.
pub inlined: HashSet<ast::DefId>, pub inlined: HashSet<ast::DefId>,
@ -281,6 +284,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
parent_stack: Vec::new(), parent_stack: Vec::new(),
search_index: Vec::new(), search_index: Vec::new(),
extern_locations: HashMap::new(), extern_locations: HashMap::new(),
primitive_locations: HashMap::new(),
privmod: false, privmod: false,
public_items: public_items, public_items: public_items,
orphan_methods: Vec::new(), orphan_methods: Vec::new(),
@ -297,13 +301,27 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> {
cache.stack.push(krate.name.clone()); cache.stack.push(krate.name.clone());
krate = cache.fold_crate(krate); krate = cache.fold_crate(krate);
// Cache where all our extern crates are located
for &(n, ref e) in krate.externs.iter() { for &(n, ref e) in krate.externs.iter() {
cache.extern_locations.insert(n, extern_location(e, &cx.dst)); cache.extern_locations.insert(n, extern_location(e, &cx.dst));
let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID }; let did = ast::DefId { krate: n, node: ast::CRATE_NODE_ID };
cache.paths.insert(did, (vec![e.name.to_string()], item_type::Module)); 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)); let index = try!(build_index(&krate, &mut cache));
// Freeze the cache now that the index has been built. Put an Arc into TLS // Freeze the cache now that the index has been built. Put an Arc into TLS
@ -854,13 +872,11 @@ impl DocFolder for Cache {
Some(item) => { Some(item) => {
match item { match item {
clean::Item{ attrs, inner: clean::ImplItem(i), .. } => { clean::Item{ attrs, inner: clean::ImplItem(i), .. } => {
match i.for_ { use clean::{Primitive, Vector, ResolvedPath, BorrowedRef};
clean::ResolvedPath { did, .. } => { use clean::{FixedVector, Slice, Tuple, PrimitiveTuple};
let v = self.impls.find_or_insert_with(did, |_| {
Vec::new()
});
// extract relevant documentation for this impl // extract relevant documentation for this impl
match attrs.move_iter().find(|a| { let dox = match attrs.move_iter().find(|a| {
match *a { match *a {
clean::NameValue(ref x, _) clean::NameValue(ref x, _)
if "doc" == x.as_slice() => { if "doc" == x.as_slice() => {
@ -869,15 +885,50 @@ impl DocFolder for Cache {
_ => false _ => false
} }
}) { }) {
Some(clean::NameValue(_, dox)) => { Some(clean::NameValue(_, dox)) => Some(dox),
v.push((i, 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()))
} }
Some(..) | None => {
v.push((i, None)); // 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()
});
v.push((i, dox));
} }
_ => {} None => {}
} }
None None
} }
@ -1119,17 +1170,21 @@ impl<'a> fmt::Show for Item<'a> {
clean::TraitItem(..) => try!(write!(fmt, "Trait ")), clean::TraitItem(..) => try!(write!(fmt, "Trait ")),
clean::StructItem(..) => try!(write!(fmt, "Struct ")), clean::StructItem(..) => try!(write!(fmt, "Struct ")),
clean::EnumItem(..) => try!(write!(fmt, "Enum ")), clean::EnumItem(..) => try!(write!(fmt, "Enum ")),
clean::PrimitiveItem(..) => try!(write!(fmt, "Primitive Type ")),
_ => {} _ => {}
} }
let is_primitive = match self.item.inner {
clean::PrimitiveItem(..) => true,
_ => false,
};
if !is_primitive {
let cur = self.cx.current.as_slice(); let cur = self.cx.current.as_slice();
let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() }; let amt = if self.ismodule() { cur.len() - 1 } else { cur.len() };
for (i, component) in cur.iter().enumerate().take(amt) { 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("../");
}
try!(write!(fmt, "<a href='{}index.html'>{}</a>::", try!(write!(fmt, "<a href='{}index.html'>{}</a>::",
trail, component.as_slice())); "../".repeat(cur.len() - i - 1),
component.as_slice()));
}
} }
try!(write!(fmt, "<a class='{}' href=''>{}</a>", try!(write!(fmt, "<a class='{}' href=''>{}</a>",
shortty(self.item), self.item.name.get_ref().as_slice())); shortty(self.item), self.item.name.get_ref().as_slice()));
@ -1154,7 +1209,7 @@ impl<'a> fmt::Show for Item<'a> {
// [src] link in the downstream documentation will actually come back to // [src] link in the downstream documentation will actually come back to
// this page, and this link will be auto-clicked. The `id` attribute is // this page, and this link will be auto-clicked. The `id` attribute is
// used to find the link to auto-click. // used to find the link to auto-click.
if self.cx.include_sources { if self.cx.include_sources && !is_primitive {
match self.href() { match self.href() {
Some(l) => { Some(l) => {
try!(write!(fmt, try!(write!(fmt,
@ -1178,6 +1233,7 @@ impl<'a> fmt::Show for Item<'a> {
clean::EnumItem(ref e) => item_enum(fmt, self.item, e), clean::EnumItem(ref e) => item_enum(fmt, self.item, e),
clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t), clean::TypedefItem(ref t) => item_typedef(fmt, self.item, t),
clean::MacroItem(ref m) => item_macro(fmt, self.item, m), clean::MacroItem(ref m) => item_macro(fmt, self.item, m),
clean::PrimitiveItem(ref p) => item_primitive(fmt, self.item, p),
_ => Ok(()) _ => Ok(())
} }
} }
@ -1250,6 +1306,8 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
} }
(&clean::ViewItemItem(..), _) => Less, (&clean::ViewItemItem(..), _) => Less,
(_, &clean::ViewItemItem(..)) => Greater, (_, &clean::ViewItemItem(..)) => Greater,
(&clean::PrimitiveItem(..), _) => Less,
(_, &clean::PrimitiveItem(..)) => Greater,
(&clean::ModuleItem(..), _) => Less, (&clean::ModuleItem(..), _) => Less,
(_, &clean::ModuleItem(..)) => Greater, (_, &clean::ModuleItem(..)) => Greater,
(&clean::MacroItem(..), _) => Less, (&clean::MacroItem(..), _) => Less,
@ -1305,6 +1363,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
clean::ForeignFunctionItem(..) => ("ffi-fns", "Foreign Functions"), clean::ForeignFunctionItem(..) => ("ffi-fns", "Foreign Functions"),
clean::ForeignStaticItem(..) => ("ffi-statics", "Foreign Statics"), clean::ForeignStaticItem(..) => ("ffi-statics", "Foreign Statics"),
clean::MacroItem(..) => ("macros", "Macros"), clean::MacroItem(..) => ("macros", "Macros"),
clean::PrimitiveItem(..) => ("primitives", "Primitive Types"),
}; };
try!(write!(w, try!(write!(w,
"<h2 id='{id}' class='section-header'>\ "<h2 id='{id}' class='section-header'>\
@ -1877,8 +1936,11 @@ impl<'a> fmt::Show for Sidebar<'a> {
try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty)); try!(write!(w, "<div class='block {}'><h2>{}</h2>", short, longty));
for item in items.iter() { for item in items.iter() {
let curty = shortty(cur).to_static_str(); let curty = shortty(cur).to_static_str();
let class = if cur.name.get_ref() == item && let class = if cur.name.get_ref() == item && short == curty {
short == curty { "current" } else { "" }; "current"
} else {
""
};
try!(write!(w, "<a class='{ty} {class}' href='{curty, select, try!(write!(w, "<a class='{ty} {class}' href='{curty, select,
mod{../} mod{../}
other{} other{}
@ -1949,3 +2011,10 @@ fn item_macro(w: &mut fmt::Formatter, it: &clean::Item,
try!(w.write(highlight::highlight(t.source.as_slice(), Some("macro")).as_bytes())); try!(w.write(highlight::highlight(t.source.as_slice(), Some("macro")).as_bytes()));
document(w, it) 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)
}

View file

@ -527,7 +527,8 @@
"variant", "variant",
"ffi", "ffi",
"ffs", "ffs",
"macro"]; "macro",
"primitive"];
function itemTypeFromName(typename) { function itemTypeFromName(typename) {
for (var i = 0; i < itemTypes.length; ++i) { for (var i = 0; i < itemTypes.length; ++i) {

View file

@ -67,11 +67,22 @@ pub fn strip_hidden(krate: clean::Crate) -> plugins::PluginResult {
fn fold_item(&mut self, i: Item) -> Option<Item> { fn fold_item(&mut self, i: Item) -> Option<Item> {
match i.inner { match i.inner {
clean::ImplItem(clean::Impl{ clean::ImplItem(clean::Impl{
for_: clean::ResolvedPath{ did, .. }, .. for_: clean::ResolvedPath{ did, .. },
ref trait_, ..
}) => { }) => {
// Impls for stripped don't need to exist
if self.stripped.contains(&did.node) { if self.stripped.contains(&did.node) {
return None; 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 // tymethods/macros have no control over privacy
clean::MacroItem(..) | clean::TyMethodItem(..) => {} clean::MacroItem(..) | clean::TyMethodItem(..) => {}
// Primitives are never stripped
clean::PrimitiveItem(..) => {}
} }
let fastreturn = match i.inner { let fastreturn = match i.inner {

View file

@ -12,6 +12,7 @@
#![allow(missing_doc)] #![allow(missing_doc)]
#![allow(unsigned_negate)] #![allow(unsigned_negate)]
#![doc(primitive = "f32")]
use prelude::*; use prelude::*;

View file

@ -11,6 +11,7 @@
//! Operations and constants for 64-bits floats (`f64` type) //! Operations and constants for 64-bits floats (`f64` type)
#![allow(missing_doc)] #![allow(missing_doc)]
#![doc(primitive = "f64")]
use prelude::*; use prelude::*;

View file

@ -10,6 +10,8 @@
//! Operations and constants for signed 16-bits integers (`i16` type) //! Operations and constants for signed 16-bits integers (`i16` type)
#![doc(primitive = "i16")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for signed 32-bits integers (`i32` type) //! Operations and constants for signed 32-bits integers (`i32` type)
#![doc(primitive = "i32")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for signed 64-bits integers (`i64` type) //! Operations and constants for signed 64-bits integers (`i64` type)
#![doc(primitive = "i64")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for signed 8-bits integers (`i8` type) //! Operations and constants for signed 8-bits integers (`i8` type)
#![doc(primitive = "i8")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for architecture-sized signed integers (`int` type) //! Operations and constants for architecture-sized signed integers (`int` type)
#![doc(primitive = "int")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for unsigned 16-bits integers (`u16` type) //! Operations and constants for unsigned 16-bits integers (`u16` type)
#![doc(primitive = "u16")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for unsigned 32-bits integers (`u32` type) //! Operations and constants for unsigned 32-bits integers (`u32` type)
#![doc(primitive = "u32")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for unsigned 64-bits integer (`u64` type) //! Operations and constants for unsigned 64-bits integer (`u64` type)
#![doc(primitive = "u64")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for unsigned 8-bits integers (`u8` type) //! Operations and constants for unsigned 8-bits integers (`u8` type)
#![doc(primitive = "u8")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -10,6 +10,8 @@
//! Operations and constants for architecture-sized unsigned integers (`uint` type) //! Operations and constants for architecture-sized unsigned integers (`uint` type)
#![doc(primitive = "uint")]
use from_str::FromStr; use from_str::FromStr;
use num::{ToStrRadix, FromStrRadix}; use num::{ToStrRadix, FromStrRadix};
use num::strconv; use num::strconv;

View file

@ -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 mem::transmute;
use clone::Clone; use clone::Clone;
use cmp::{TotalOrd, Ordering, Less, Greater}; use cmp::{TotalOrd, Ordering, Less, Greater};

View file

@ -65,6 +65,8 @@ is the same as `&[u8]`.
*/ */
#![doc(primitive = "str")]
use char::Char; use char::Char;
use char; use char;
use clone::Clone; use clone::Clone;