diff --git a/src/doc/rustdoc.md b/src/doc/rustdoc.md index 3880503c8e561..1034c776ea6dd 100644 --- a/src/doc/rustdoc.md +++ b/src/doc/rustdoc.md @@ -41,6 +41,31 @@ pub fn recalibrate() { # } ~~~ +Documentation can also be controlled via the `doc` attribute on items. This is +implicitly done by the compiler when using the above form of doc comments +(converting the slash-based comments to `#[doc]` attributes). + +~~~ +#[doc = " +Calculates the factorial of a number. + +Given the input integer `n`, this function will calculate `n!` and return it. +"] +pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n)} } +# fn main() {} +~~~ + +The `doc` attribute can also be used to control how rustdoc emits documentation +in some cases. + +``` +// Rustdoc will inline documentation of a `pub use` into this crate when the +// `pub use` reaches across crates, but this behavior can also be disabled. +#[doc(no_inline)] +pub use std::option::Option; +# fn main() {} +``` + Doc comments are markdown, and are currently parsed with the [sundown][sundown] library. rustdoc does not yet do any fanciness such as referencing other items inline, like javadoc's `@see`. One exception to this diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index f30d6119339ab..c798118bbd0fa 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -206,6 +206,9 @@ pub static tag_crate_triple: uint = 0x66; pub static tag_dylib_dependency_formats: uint = 0x67; +pub static tag_method_argument_names: uint = 0x8e; +pub static tag_method_argument_name: uint = 0x8f; + #[deriving(Clone, Show)] pub struct LinkMeta { pub crateid: CrateId, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index efe3633195e7c..d407cc046807b 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -306,3 +306,10 @@ pub fn get_missing_lang_items(cstore: &cstore::CStore, cnum: ast::CrateNum) let cdata = cstore.get_crate_data(cnum); decoder::get_missing_lang_items(&*cdata) } + +pub fn get_method_arg_names(cstore: &cstore::CStore, did: ast::DefId) + -> Vec +{ + let cdata = cstore.get_crate_data(did.krate); + decoder::get_method_arg_names(&*cdata, did.node) +} diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 83b24d882e5b5..e8be05feae806 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1309,3 +1309,18 @@ pub fn get_missing_lang_items(cdata: Cmd) }); return result; } + +pub fn get_method_arg_names(cdata: Cmd, id: ast::NodeId) -> Vec { + let mut ret = Vec::new(); + let method_doc = lookup_item(id, cdata.data()); + match reader::maybe_get_doc(method_doc, tag_method_argument_names) { + Some(args_doc) => { + reader::tagged_docs(args_doc, tag_method_argument_name, |name_doc| { + ret.push(name_doc.as_str_slice().to_strbuf()); + true + }); + } + None => {} + } + return ret; +} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index bd333a5afe087..443a8acfb0cc6 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -536,6 +536,7 @@ fn encode_reexports(ecx: &EncodeContext, fn encode_info_for_mod(ecx: &EncodeContext, ebml_w: &mut Encoder, md: &Mod, + attrs: &[Attribute], id: NodeId, path: PathElems, name: Ident, @@ -584,6 +585,7 @@ fn encode_info_for_mod(ecx: &EncodeContext, debug!("(encoding info for module) encoding reexports for {}", id); encode_reexports(ecx, ebml_w, id, path); } + encode_attributes(ebml_w, attrs); ebml_w.end_tag(); } @@ -774,11 +776,30 @@ fn encode_info_for_method(ecx: &EncodeContext, } else { encode_symbol(ecx, ebml_w, m.def_id.node); } + encode_method_argument_names(ebml_w, &*ast_method.decl); } ebml_w.end_tag(); } +fn encode_method_argument_names(ebml_w: &mut Encoder, + decl: &ast::FnDecl) { + ebml_w.start_tag(tag_method_argument_names); + for arg in decl.inputs.iter() { + ebml_w.start_tag(tag_method_argument_name); + match arg.pat.node { + ast::PatIdent(_, ref name, _) => { + let name = name.segments.last().unwrap().identifier; + let name = token::get_ident(name); + ebml_w.writer.write(name.get().as_bytes()); + } + _ => {} + } + ebml_w.end_tag(); + } + ebml_w.end_tag(); +} + fn encode_inlined_item(ecx: &EncodeContext, ebml_w: &mut Encoder, ii: InlinedItemRef) { @@ -895,7 +916,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_visibility(ebml_w, vis); ebml_w.end_tag(); } - ItemFn(_, fn_style, _, ref generics, _) => { + ItemFn(ref decl, fn_style, _, ref generics, _) => { add_to_index(item, ebml_w, index); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, def_id); @@ -911,6 +932,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_symbol(ecx, ebml_w, item.id); } encode_visibility(ebml_w, vis); + encode_method_argument_names(ebml_w, &**decl); ebml_w.end_tag(); } ItemMod(ref m) => { @@ -918,6 +940,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_info_for_mod(ecx, ebml_w, m, + item.attrs.as_slice(), item.id, path, item.ident, @@ -1317,6 +1340,7 @@ fn encode_info_for_items(ecx: &EncodeContext, encode_info_for_mod(ecx, ebml_w, &krate.module, + &[], CRATE_NODE_ID, ast_map::Values([].iter()).chain(None), syntax::parse::token::special_idents::invalid, diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs new file mode 100644 index 0000000000000..dd5fddca0db8a --- /dev/null +++ b/src/librustdoc/clean/inline.rs @@ -0,0 +1,278 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for inlining external documentation into the current AST. + +use syntax::ast; +use syntax::ast_util; +use syntax::attr::AttrMetaMethods; + +use rustc::metadata::csearch; +use rustc::metadata::decoder; +use rustc::middle::ty; + +use core; +use doctree; +use clean; + +use super::Clean; + +/// Attempt to inline the definition of a local node id into this AST. +/// +/// This function will fetch the definition of the id specified, and if it is +/// from another crate it will attempt to inline the documentation from the +/// other crate into this crate. +/// +/// This is primarily used for `pub use` statements which are, in general, +/// implementation details. Inlining the documentation should help provide a +/// better experience when reading the documentation in this use case. +/// +/// The returned value is `None` if the `id` could not be inlined, and `Some` +/// of a vector of items if it was successfully expanded. +pub fn try_inline(id: ast::NodeId) -> Option> { + let cx = ::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + core::NotTyped(_) => return None, + }; + let def = match tcx.def_map.borrow().find(&id) { + Some(def) => *def, + None => return None, + }; + let did = ast_util::def_id_of_def(def); + if ast_util::is_local(did) { return None } + try_inline_def(&**cx, tcx, def) +} + +fn try_inline_def(cx: &core::DocContext, + tcx: &ty::ctxt, + def: ast::Def) -> Option> { + let mut ret = Vec::new(); + let did = ast_util::def_id_of_def(def); + let inner = match def { + ast::DefTrait(did) => { + record_extern_fqn(cx, did, clean::TypeTrait); + clean::TraitItem(build_external_trait(tcx, did)) + } + ast::DefFn(did, style) => { + 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()); + clean::StructItem(build_struct(tcx, did)) + } + ast::DefTy(did) => { + record_extern_fqn(cx, did, clean::TypeEnum); + ret.extend(build_impls(tcx, did).move_iter()); + build_type(tcx, did) + } + // Assume that the enum type is reexported next to the variant, and + // variants don't show up in documentation specially. + ast::DefVariant(..) => return Some(Vec::new()), + ast::DefMod(did) => { + record_extern_fqn(cx, did, clean::TypeModule); + clean::ModuleItem(build_module(cx, tcx, did)) + } + _ => return None, + }; + let fqn = csearch::get_item_path(tcx, did); + ret.push(clean::Item { + source: clean::Span::empty(), + name: Some(fqn.last().unwrap().to_str().to_strbuf()), + attrs: load_attrs(tcx, did), + inner: inner, + visibility: Some(ast::Public), + def_id: did, + }); + Some(ret) +} + +pub fn load_attrs(tcx: &ty::ctxt, did: ast::DefId) -> Vec { + let mut attrs = Vec::new(); + csearch::get_item_attrs(&tcx.sess.cstore, did, |v| { + attrs.extend(v.move_iter().map(|mut a| { + // FIXME this isn't quite always true, it's just true about 99% of + // the time when dealing with documentation. For example, + // this would treat doc comments of the form `#[doc = "foo"]` + // incorrectly. + if a.name().get() == "doc" && a.value_str().is_some() { + a.node.is_sugared_doc = true; + } + a.clean() + })); + }); + attrs +} + +/// Record an external fully qualified name in the external_paths cache. +/// +/// These names are used later on by HTML rendering to generate things like +/// source links back to the original item. +pub fn record_extern_fqn(cx: &core::DocContext, + did: ast::DefId, + kind: clean::TypeKind) { + match cx.maybe_typed { + core::Typed(ref tcx) => { + let fqn = csearch::get_item_path(tcx, did); + let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect(); + cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind)); + } + core::NotTyped(..) => {} + } +} + +pub fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> clean::Trait { + let def = ty::lookup_trait_def(tcx, did); + let methods = ty::trait_methods(tcx, did); + clean::Trait { + generics: def.generics.clean(), + methods: methods.iter().map(|i| i.clean()).collect(), + parents: Vec::new(), // FIXME: this is likely wrong + } +} + +fn build_external_function(tcx: &ty::ctxt, + did: ast::DefId, + style: ast::FnStyle) -> clean::Function { + let t = ty::lookup_item_type(tcx, did); + clean::Function { + decl: match ty::get(t.ty).sty { + ty::ty_bare_fn(ref f) => (did, &f.sig).clean(), + _ => fail!("bad function"), + }, + generics: t.generics.clean(), + fn_style: style, + } +} + +fn build_struct(tcx: &ty::ctxt, did: ast::DefId) -> clean::Struct { + use syntax::parse::token::special_idents::unnamed_field; + + let t = ty::lookup_item_type(tcx, did); + let fields = ty::lookup_struct_fields(tcx, did); + + clean::Struct { + struct_type: match fields.as_slice() { + [] => doctree::Unit, + [ref f] if f.name == unnamed_field.name => doctree::Newtype, + [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple, + _ => doctree::Plain, + }, + generics: t.generics.clean(), + fields: fields.iter().map(|f| f.clean()).collect(), + fields_stripped: false, + } +} + +fn build_type(tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum { + let t = ty::lookup_item_type(tcx, did); + match ty::get(t.ty).sty { + ty::ty_enum(edid, _) => { + return clean::EnumItem(clean::Enum { + generics: t.generics.clean(), + variants_stripped: false, + variants: ty::enum_variants(tcx, edid).clean(), + }) + } + _ => {} + } + + clean::TypedefItem(clean::Typedef { + type_: t.ty.clean(), + generics: t.generics.clean(), + }) +} + +fn build_impls(tcx: &ty::ctxt, + did: ast::DefId) -> Vec { + ty::populate_implementations_for_type_if_necessary(tcx, did); + let mut impls = Vec::new(); + + match tcx.inherent_impls.borrow().find(&did) { + None => {} + Some(i) => { + impls.extend(i.borrow().iter().map(|&did| { build_impl(tcx, did) })); + } + } + + impls +} + +fn build_impl(tcx: &ty::ctxt, did: ast::DefId) -> clean::Item { + let associated_trait = csearch::get_impl_trait(tcx, did); + let attrs = load_attrs(tcx, did); + let ty = ty::lookup_item_type(tcx, did); + let methods = csearch::get_impl_methods(&tcx.sess.cstore, did).iter().map(|did| { + let mut item = match ty::method(tcx, *did).clean() { + clean::Provided(item) => item, + clean::Required(item) => item, + }; + item.inner = match item.inner.clone() { + clean::TyMethodItem(clean::TyMethod { + fn_style, decl, self_, generics + }) => { + clean::MethodItem(clean::Method { + fn_style: fn_style, + decl: decl, + self_: self_, + generics: generics, + }) + } + _ => fail!("not a tymethod"), + }; + item + }).collect(); + clean::Item { + inner: clean::ImplItem(clean::Impl { + derived: clean::detect_derived(attrs.as_slice()), + trait_: associated_trait.clean().map(|bound| { + match bound { + clean::TraitBound(ty) => ty, + clean::RegionBound => unreachable!(), + } + }), + for_: ty.ty.clean(), + generics: ty.generics.clean(), + methods: methods, + }), + source: clean::Span::empty(), + name: None, + attrs: attrs, + visibility: Some(ast::Inherited), + def_id: did, + } +} + +fn build_module(cx: &core::DocContext, tcx: &ty::ctxt, + did: ast::DefId) -> clean::Module { + let mut items = Vec::new(); + + // FIXME: this doesn't handle reexports inside the module itself. + // Should they be handled? + csearch::each_child_of_item(&tcx.sess.cstore, did, |def, _, _| { + match def { + decoder::DlDef(def) => { + match try_inline_def(cx, tcx, def) { + Some(i) => items.extend(i.move_iter()), + None => {} + } + } + decoder::DlImpl(did) => items.push(build_impl(tcx, did)), + decoder::DlField => fail!("unimplemented field"), + } + }); + + clean::Module { + items: items, + is_crate: false, + } +} diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean/mod.rs similarity index 86% rename from src/librustdoc/clean.rs rename to src/librustdoc/clean/mod.rs index 68af35acdbe33..f0f6842642534 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean/mod.rs @@ -15,7 +15,7 @@ use syntax; use syntax::ast; use syntax::ast_util; use syntax::attr; -use syntax::attr::AttributeMethods; +use syntax::attr::{AttributeMethods, AttrMetaMethods}; use syntax::codemap::Pos; use syntax::parse::token::InternedString; use syntax::parse::token; @@ -27,7 +27,7 @@ use rustc::metadata::csearch; use rustc::metadata::decoder; use rustc::middle::ty; -use std::string::String; +use std::rc::Rc; use core; use doctree; @@ -37,6 +37,8 @@ use visit_ast; /// Increment this when the `Crate` and related structures change. pub static SCHEMA_VERSION: &'static str = "0.8.2"; +mod inline; + pub trait Clean { fn clean(&self) -> T; } @@ -53,6 +55,12 @@ impl, U> Clean for @T { } } +impl, U> Clean for Rc { + fn clean(&self) -> U { + (**self).clean() + } +} + impl, U> Clean> for Option { fn clean(&self) -> Option { match self { @@ -250,7 +258,8 @@ impl Clean for doctree::Module { self.statics.clean().move_iter().collect(), self.traits.clean().move_iter().collect(), self.impls.clean().move_iter().collect(), - self.view_items.clean().move_iter().collect(), + self.view_items.clean().move_iter() + .flat_map(|s| s.move_iter()).collect(), self.macros.clean().move_iter().collect() ); @@ -336,6 +345,14 @@ impl attr::AttrMetaMethods for Attribute { None } } +impl<'a> attr::AttrMetaMethods for &'a Attribute { + fn name(&self) -> InternedString { (**self).name() } + fn value_str(&self) -> Option { (**self).value_str() } + fn meta_item_list<'a>(&'a self) -> Option<&'a [@ast::MetaItem]> { None } + fn name_str_pair(&self) -> Option<(InternedString, InternedString)> { + None + } +} #[deriving(Clone, Encodable, Decodable)] pub struct TyParam { @@ -473,7 +490,7 @@ impl Clean>> for ty::substs { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, Eq)] pub struct Lifetime(String); impl Lifetime { @@ -614,7 +631,7 @@ impl Clean for ast::TypeMethod { } } -#[deriving(Clone, Encodable, Decodable)] +#[deriving(Clone, Encodable, Decodable, Eq)] pub enum SelfTy { SelfStatic, SelfValue, @@ -707,18 +724,32 @@ impl Clean for ast::FnDecl { } } -impl Clean for ty::FnSig { +impl<'a> Clean for (ast::DefId, &'a ty::FnSig) { fn clean(&self) -> FnDecl { + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tcx) => tcx, + core::NotTyped(_) => unreachable!(), + }; + let (did, sig) = *self; + let mut names = if did.node != 0 { + csearch::get_method_arg_names(&tcx.sess.cstore, did).move_iter() + } else { + Vec::new().move_iter() + }.peekable(); + if names.peek().map(|s| s.as_slice()) == Some("self") { + let _ = names.next(); + } FnDecl { - output: self.output.clean(), + output: sig.output.clean(), cf: Return, - attrs: Vec::new(), // FIXME: this is likely wrong + attrs: Vec::new(), inputs: Arguments { - values: self.inputs.iter().map(|t| { + values: sig.inputs.iter().map(|t| { Argument { type_: t.clean(), id: 0, - name: "".to_strbuf(), // FIXME: where are the names? + name: names.next().unwrap_or("".to_strbuf()), } }).collect(), }, @@ -830,12 +861,8 @@ impl Clean for ty::Method { let cx = super::ctxtkey.get().unwrap(); let tcx = match cx.maybe_typed { core::Typed(ref tcx) => tcx, - core::NotTyped(_) => fail!(), + core::NotTyped(_) => unreachable!(), }; - let mut attrs = Vec::new(); - csearch::get_item_attrs(&tcx.sess.cstore, self.def_id, |v| { - attrs.extend(v.move_iter().map(|i| i.clean())); - }); let (self_, sig) = match self.explicit_self { ast::SelfStatic => (ast::SelfStatic.clean(), self.fty.sig.clone()), s => { @@ -857,20 +884,18 @@ impl Clean for ty::Method { (s, sig) } }; + m(Item { name: Some(self.ident.clean()), visibility: Some(ast::Inherited), def_id: self.def_id, - attrs: attrs, - source: Span { - filename: "".to_strbuf(), - loline: 0, locol: 0, hiline: 0, hicol: 0, - }, + attrs: inline::load_attrs(tcx, self.def_id), + source: Span::empty(), inner: TyMethodItem(TyMethod { fn_style: self.fty.fn_style, generics: self.generics.clean(), self_: self_, - decl: sig.clean(), + decl: (self.def_id, &sig).clean(), }) }) } @@ -987,13 +1012,13 @@ impl Clean for ty::t { generics: Generics { lifetimes: Vec::new(), type_params: Vec::new() }, - decl: fty.sig.clean(), + decl: (ast_util::local_def(0), &fty.sig).clean(), abi: fty.abi.to_str().to_strbuf(), }), ty::ty_closure(ref fty) => { let decl = box ClosureDecl { lifetimes: Vec::new(), // FIXME: this looks wrong... - decl: fty.sig.clean(), + decl: (ast_util::local_def(0), &fty.sig).clean(), onceness: fty.onceness, fn_style: fty.fn_style, bounds: fty.bounds.iter().map(|i| i.clean()).collect(), @@ -1009,7 +1034,7 @@ impl Clean for ty::t { let cx = super::ctxtkey.get().unwrap(); let tcx = match cx.maybe_typed { core::Typed(ref tycx) => tycx, - core::NotTyped(_) => fail!(), + core::NotTyped(_) => unreachable!(), }; let fqn = csearch::get_item_path(tcx, did); let fqn: Vec = fqn.move_iter().map(|i| { @@ -1073,6 +1098,31 @@ impl Clean for ast::StructField { } } +impl Clean for ty::field_ty { + fn clean(&self) -> Item { + use syntax::parse::token::special_idents::unnamed_field; + let name = if self.name == unnamed_field.name { + None + } else { + Some(self.name) + }; + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + core::NotTyped(_) => unreachable!(), + }; + let ty = ty::lookup_item_type(tcx, self.id); + Item { + name: name.clean(), + attrs: inline::load_attrs(tcx, self.id), + source: Span::empty(), + visibility: Some(self.vis), + def_id: self.id, + inner: StructFieldItem(TypedStructField(ty.ty.clean())), + } + } +} + pub type Visibility = ast::Visibility; impl Clean> for ast::Visibility { @@ -1171,6 +1221,53 @@ impl Clean for doctree::Variant { } } +impl Clean for ty::VariantInfo { + fn clean(&self) -> Item { + // use syntax::parse::token::special_idents::unnamed_field; + let cx = super::ctxtkey.get().unwrap(); + let tcx = match cx.maybe_typed { + core::Typed(ref tycx) => tycx, + core::NotTyped(_) => fail!("tcx not present"), + }; + let kind = match self.arg_names.as_ref().map(|s| s.as_slice()) { + None | Some([]) if self.args.len() == 0 => CLikeVariant, + None | Some([]) => { + TupleVariant(self.args.iter().map(|t| t.clean()).collect()) + } + Some(s) => { + StructVariant(VariantStruct { + struct_type: doctree::Plain, + fields_stripped: false, + fields: s.iter().zip(self.args.iter()).map(|(name, ty)| { + Item { + source: Span::empty(), + name: Some(name.clean()), + attrs: Vec::new(), + visibility: Some(ast::Public), + // FIXME: this is not accurate, we need an id for + // the specific field but we're using the id + // for the whole variant. Nothing currently + // uses this so we should be good for now. + def_id: self.id, + inner: StructFieldItem( + TypedStructField(ty.clean()) + ) + } + }).collect() + }) + } + }; + Item { + name: Some(self.name.clean()), + attrs: inline::load_attrs(tcx, self.id), + source: Span::empty(), + visibility: Some(ast::Public), + def_id: self.id, + inner: VariantItem(Variant { kind: kind }), + } + } +} + #[deriving(Clone, Encodable, Decodable)] pub enum VariantKind { CLikeVariant, @@ -1202,6 +1299,16 @@ pub struct Span { pub hicol: uint, } +impl Span { + fn empty() -> Span { + Span { + filename: "".to_strbuf(), + loline: 0, locol: 0, + hiline: 0, hicol: 0, + } + } +} + impl Clean for syntax::codemap::Span { fn clean(&self) -> Span { let ctxt = super::ctxtkey.get().unwrap(); @@ -1273,6 +1380,12 @@ impl Clean for ast::Ident { } } +impl Clean for ast::Name { + fn clean(&self) -> String { + token::get_name(*self).get().to_strbuf() + } +} + #[deriving(Clone, Encodable, Decodable)] pub struct Typedef { pub type_: Type, @@ -1345,7 +1458,7 @@ impl Clean for doctree::Static { } } -#[deriving(Show, Clone, Encodable, Decodable)] +#[deriving(Show, Clone, Encodable, Decodable, Eq)] pub enum Mutability { Mutable, Immutable, @@ -1369,19 +1482,12 @@ pub struct Impl { pub derived: bool, } +fn detect_derived(attrs: &[M]) -> bool { + attr::contains_name(attrs, "automatically_derived") +} + impl Clean for doctree::Impl { fn clean(&self) -> Item { - let mut derived = false; - for attr in self.attrs.iter() { - match attr.node.value.node { - ast::MetaWord(ref s) => { - if s.get() == "automatically_derived" { - derived = true; - } - } - _ => {} - } - } Item { name: None, attrs: self.attrs.clean(), @@ -1393,7 +1499,7 @@ impl Clean for doctree::Impl { trait_: self.trait_.clean(), for_: self.for_.clean(), methods: self.methods.clean(), - derived: derived, + derived: detect_derived(self.attrs.as_slice()), }), } } @@ -1404,18 +1510,63 @@ pub struct ViewItem { pub inner: ViewItemInner, } -impl Clean for ast::ViewItem { - fn clean(&self) -> Item { - Item { - name: None, - attrs: self.attrs.clean().move_iter().collect(), - source: self.span.clean(), - def_id: ast_util::local_def(0), - visibility: self.vis.clean(), - inner: ViewItemItem(ViewItem { - inner: self.node.clean() - }), +impl Clean> for ast::ViewItem { + fn clean(&self) -> Vec { + // We consider inlining the documentation of `pub use` statments, but we + // forcefully don't inline if this is not public or if the + // #[doc(no_inline)] attribute is present. + let denied = self.vis != ast::Public || self.attrs.iter().any(|a| { + a.name().get() == "doc" && match a.meta_item_list() { + Some(l) => attr::contains_name(l, "no_inline"), + None => false, + } + }); + let convert = |node: &ast::ViewItem_| { + Item { + name: None, + attrs: self.attrs.clean().move_iter().collect(), + source: self.span.clean(), + def_id: ast_util::local_def(0), + visibility: self.vis.clean(), + inner: ViewItemItem(ViewItem { inner: node.clean() }), + } + }; + let mut ret = Vec::new(); + match self.node { + ast::ViewItemUse(ref path) if !denied => { + match path.node { + ast::ViewPathGlob(..) => ret.push(convert(&self.node)), + ast::ViewPathList(ref a, ref list, ref b) => { + // Attempt to inline all reexported items, but be sure + // to keep any non-inlineable reexports so they can be + // listed in the documentation. + let remaining = list.iter().filter(|path| { + match inline::try_inline(path.node.id) { + Some(items) => { + ret.extend(items.move_iter()); false + } + None => true, + } + }).map(|a| a.clone()).collect::>(); + if remaining.len() > 0 { + let path = ast::ViewPathList(a.clone(), + remaining, + b.clone()); + let path = syntax::codemap::dummy_spanned(path); + ret.push(convert(&ast::ViewItemUse(@path))); + } + } + ast::ViewPathSimple(_, _, id) => { + match inline::try_inline(id) { + Some(items) => ret.extend(items.move_iter()), + None => ret.push(convert(&self.node)), + } + } + } + } + ref n => ret.push(convert(n)), } + return ret; } } @@ -1630,13 +1781,10 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { core::Typed(ref t) => t, core::NotTyped(_) => return did }; - let fqn = csearch::get_item_path(tcx, did); - let fqn = fqn.move_iter().map(|i| i.to_str().to_strbuf()).collect(); - debug!("recording {} => {}", did, fqn); - cx.external_paths.borrow_mut().get_mut_ref().insert(did, (fqn, kind)); + inline::record_extern_fqn(cx, did, kind); match kind { TypeTrait => { - let t = build_external_trait(tcx, did); + let t = inline::build_external_trait(tcx, did); cx.external_traits.borrow_mut().get_mut_ref().insert(did, t); } _ => {} @@ -1644,16 +1792,6 @@ fn register_def(cx: &core::DocContext, def: ast::Def) -> ast::DefId { return did; } -fn build_external_trait(tcx: &ty::ctxt, did: ast::DefId) -> Trait { - let def = csearch::get_trait_def(tcx, did); - let methods = ty::trait_methods(tcx, did); - Trait { - generics: def.generics.clean(), - methods: methods.iter().map(|i| i.clean()).collect(), - parents: Vec::new(), // FIXME: this is likely wrong - } -} - fn resolve_use_source(path: Path, id: ast::NodeId) -> ImportSource { ImportSource { path: path, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index e14be8ac6fda2..9043ffd10ba95 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -99,7 +99,7 @@ impl fmt::Show for clean::TyParamBound { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { clean::RegionBound => { - f.write("::".as_bytes()) + f.write("'static".as_bytes()) } clean::TraitBound(ref ty) => { write!(f, "{}", *ty) @@ -150,7 +150,7 @@ fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path, print_all: bool) -> fmt::Result { path(w, p, print_all, |cache, loc| { - if ast_util::is_local(did) { + if ast_util::is_local(did) || cache.paths.contains_key(&did) { Some(("../".repeat(loc.len())).to_strbuf()) } else { match *cache.extern_locations.get(&did.krate) { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 7b8514ab38f62..f49b7f3e98903 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -144,6 +144,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result { extern fn block(ob: *mut hoedown_buffer, text: *hoedown_buffer, lang: *hoedown_buffer, opaque: *mut libc::c_void) { unsafe { + if text.is_null() { return } + let opaque = opaque as *mut hoedown_html_renderer_state; let my_opaque: &MyOpaque = &*((*opaque).opaque as *MyOpaque); slice::raw::buf_as_slice((*text).data, (*text).size as uint, |text| { diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 53e271dafa28d..d601d2ae957fe 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -132,7 +132,7 @@ pub struct Cache { /// /// The values of the map are a list of implementations and documentation /// found on that implementation. - pub impls: HashMap)>>, + pub impls: HashMap)>>, /// Maintains a mapping of local crate node ids to the fully qualified name /// and "short type description" of that node. This is used when generating @@ -141,6 +141,10 @@ pub struct Cache { /// necessary. pub paths: HashMap, ItemType)>, + /// Similar to `paths`, but only holds external paths. This is only used for + /// generating explicit hyperlinks to other crates. + pub external_paths: HashMap>, + /// This map contains information about all known traits of this crate. /// Implementations of a crate should inherit the documentation of the /// parent trait if no extra documentation is specified, and default methods @@ -157,9 +161,9 @@ pub struct Cache { // Private fields only used when initially crawling a crate to build a cache - stack: Vec , - parent_stack: Vec , - search_index: Vec , + stack: Vec, + parent_stack: Vec, + search_index: Vec, privmod: bool, public_items: NodeSet, @@ -198,7 +202,7 @@ struct IndexItem { name: String, path: String, desc: String, - parent: Option, + parent: Option, } // TLS keys used to carry information around during rendering. @@ -249,7 +253,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { let analysis = ::analysiskey.get(); let public_items = analysis.as_ref().map(|a| a.public_items.clone()); let public_items = public_items.unwrap_or(NodeSet::new()); - let paths = analysis.as_ref().map(|a| { + let paths: HashMap, ItemType)> = + analysis.as_ref().map(|a| { let paths = a.external_paths.borrow_mut().take_unwrap(); paths.move_iter().map(|(k, (v, t))| { (k, (v, match t { @@ -265,6 +270,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { }).unwrap_or(HashMap::new()); let mut cache = Cache { impls: HashMap::new(), + external_paths: paths.iter().map(|(&k, &(ref v, _))| (k, v.clone())) + .collect(), paths: paths, implementors: HashMap::new(), stack: Vec::new(), @@ -302,7 +309,7 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { path: fqp.slice_to(fqp.len() - 1).connect("::") .to_strbuf(), desc: shorter(item.doc_value()).to_strbuf(), - parent: Some(pid), + parent: Some(did), }); }, None => {} @@ -360,9 +367,8 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { try!(write!(&mut w, r#"],"paths":["#)); - for (i, &nodeid) in pathid_to_nodeid.iter().enumerate() { - let def = ast_util::local_def(nodeid); - let &(ref fqp, short) = cache.paths.find(&def).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, ",")); } @@ -497,13 +503,15 @@ pub fn run(mut krate: clean::Crate, dst: Path) -> io::IoResult<()> { seen: HashSet::new(), cx: &mut cx, }; + // skip all invalid spans + folder.seen.insert("".to_strbuf()); krate = folder.fold_crate(krate); } 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::new(), item_type::Module)); + cache.paths.insert(did, (vec![e.name.to_strbuf()], item_type::Module)); } // And finally render the whole crate's documentation @@ -730,14 +738,13 @@ impl DocFolder for Cache { clean::VariantItem(..) => { (Some(*self.parent_stack.last().unwrap()), Some(self.stack.slice_to(self.stack.len() - 1))) - } clean::MethodItem(..) => { if self.parent_stack.len() == 0 { (None, None) } else { let last = self.parent_stack.last().unwrap(); - let did = ast_util::local_def(*last); + let did = *last; let path = match self.paths.find(&did) { Some(&(_, item_type::Trait)) => Some(self.stack.slice_to(self.stack.len() - 1)), @@ -766,9 +773,11 @@ impl DocFolder for Cache { }); } (Some(parent), None) if !self.privmod => { - // We have a parent, but we don't know where they're - // defined yet. Wait for later to index this item. - self.orphan_methods.push((parent, item.clone())) + if ast_util::is_local(parent) { + // We have a parent, but we don't know where they're + // defined yet. Wait for later to index this item. + self.orphan_methods.push((parent.node, item.clone())) + } } _ => {} } @@ -789,19 +798,18 @@ impl DocFolder for Cache { clean::TypedefItem(..) | clean::TraitItem(..) | clean::FunctionItem(..) | clean::ModuleItem(..) | clean::ForeignFunctionItem(..) => { - if ast_util::is_local(item.def_id) { - // 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 - // `public_items` map, so we can skip inserting into the - // paths map if there was already an entry present and we're - // not a public item. - let id = item.def_id.node; - if !self.paths.contains_key(&item.def_id) || - self.public_items.contains(&id) { - self.paths.insert(item.def_id, - (self.stack.clone(), shortty(&item))); - } + // 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 + // `public_items` map, so we can skip inserting into the + // paths map if there was already an entry present and we're + // not a public item. + let id = item.def_id.node; + if !self.paths.contains_key(&item.def_id) || + !ast_util::is_local(item.def_id) || + self.public_items.contains(&id) { + self.paths.insert(item.def_id, + (self.stack.clone(), shortty(&item))); } } // link variants to their parent enum because pages aren't emitted @@ -817,20 +825,14 @@ impl DocFolder for Cache { // Maintain the parent stack let parent_pushed = match item.inner { clean::TraitItem(..) | clean::EnumItem(..) | clean::StructItem(..) => { - if ast_util::is_local(item.def_id) { - self.parent_stack.push(item.def_id.node); - } + self.parent_stack.push(item.def_id); true } clean::ImplItem(ref i) => { match i.for_ { clean::ResolvedPath{ did, .. } => { - if ast_util::is_local(did) { - self.parent_stack.push(did.node); - true - } else { - false - } + self.parent_stack.push(did); + true } _ => false } @@ -845,10 +847,8 @@ impl DocFolder for Cache { match item { clean::Item{ attrs, inner: clean::ImplItem(i), .. } => { match i.for_ { - clean::ResolvedPath { did, .. } - if ast_util::is_local(did) => - { - let v = self.impls.find_or_insert_with(did.node, |_| { + clean::ResolvedPath { did, .. } => { + let v = self.impls.find_or_insert_with(did, |_| { Vec::new() }); // extract relevant documentation for this impl @@ -1041,23 +1041,62 @@ impl<'a> Item<'a> { } } - fn link(&self) -> String { - let mut path = Vec::new(); - clean_srcpath(self.item.source.filename.as_bytes(), |component| { - path.push(component.to_owned()); - }); - let href = if self.item.source.loline == self.item.source.hiline { - format_strbuf!("{}", self.item.source.loline) + /// Generate a url appropriate for an `href` attribute back to the source of + /// this item. + /// + /// The url generated, when clicked, will redirect the browser back to the + /// original source code. + /// + /// If `None` is returned, then a source link couldn't be generated. This + /// may happen, for example, with externally inlined items where the source + /// of their crate documentation isn't known. + fn href(&self) -> Option { + // If this item is part of the local crate, then we're guaranteed to + // know the span, so we plow forward and generate a proper url. The url + // has anchors for the line numbers that we're linking to. + if ast_util::is_local(self.item.def_id) { + let mut path = Vec::new(); + clean_srcpath(self.item.source.filename.as_bytes(), |component| { + path.push(component.to_owned()); + }); + let href = if self.item.source.loline == self.item.source.hiline { + format!("{}", self.item.source.loline) + } else { + format!("{}-{}", + self.item.source.loline, + self.item.source.hiline) + }; + Some(format!("{root}src/{krate}/{path}.html\\#{href}", + root = self.cx.root_path, + krate = self.cx.layout.krate, + path = path.connect("/"), + href = href)) + + // If this item is not part of the local crate, then things get a little + // trickier. We don't actually know the span of the external item, but + // we know that the documentation on the other end knows the span! + // + // In this case, we generate a link to the *documentation* for this type + // in the original crate. There's an extra URL parameter which says that + // we want to go somewhere else, and the JS on the destination page will + // pick it up and instantly redirect the browser to the source code. + // + // If we don't know where the external documentation for this crate is + // located, then we return `None`. } else { - format_strbuf!("{}-{}", - self.item.source.loline, - self.item.source.hiline) - }; - format_strbuf!("{root}src/{krate}/{path}.html\\#{href}", - root = self.cx.root_path, - krate = self.cx.layout.krate, - path = path.connect("/"), - href = href) + let cache = cache_key.get().unwrap(); + let path = cache.external_paths.get(&self.item.def_id); + let root = match *cache.extern_locations.get(&self.item.def_id.krate) { + Remote(ref s) => s.to_strbuf(), + Local => format!("{}/..", self.cx.root_path), + Unknown => return None, + }; + Some(format!("{root}/{path}/{file}?gotosrc={goto}", + root = root, + path = path.slice_to(path.len() - 1).connect("/"), + file = item_path(self.item), + goto = self.item.def_id.node)) + } } } @@ -1105,9 +1144,21 @@ impl<'a> fmt::Show for Item<'a> { } // Write `src` tag + // + // When this item is part of a `pub use` in a downstream crate, the + // [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 { - try!(write!(fmt, "[src]", - self.link())); + match self.href() { + Some(l) => { + try!(write!(fmt, + "[src]", + self.item.def_id.node, l)); + } + None => {} + } } try!(write!(fmt, "\n")); @@ -1266,7 +1317,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, try!(write!(f, " = ")); if s.contains("\n") { write!(f, "[definition]", - item.link()) + item.href()) } else { write!(f, "{}", s.as_slice()) } @@ -1672,7 +1723,7 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } fn render_methods(w: &mut fmt::Formatter, it: &clean::Item) -> fmt::Result { - match cache_key.get().unwrap().impls.find(&it.def_id.node) { + match cache_key.get().unwrap().impls.find(&it.def_id) { Some(v) => { let mut non_trait = v.iter().filter(|p| { p.ref0().trait_.is_none() diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index c88e6aa586833..2fb824653d3db 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -675,4 +675,10 @@ if (window.pending_implementors) { window.register_implementors(window.pending_implementors); } + + // See documentaiton in html/render.rs for what this is doing. + var query = getQueryStringParams(); + if (query['gotosrc']) { + window.location = $('#src-' + query['gotosrc']).attr('href'); + } }()); diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 16c319d6363bb..390f81642e6b2 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -152,7 +152,8 @@ impl<'a> fold::DocFolder for Stripper<'a> { clean::ImplItem(clean::Impl{ for_: clean::ResolvedPath{ did, .. }, .. }) => { - if !self.exported_items.contains(&did.node) { + if ast_util::is_local(did) && + !self.exported_items.contains(&did.node) { return None; } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 0d42e1743f561..1786cc8062e21 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -16,10 +16,10 @@ //! //! ## Intrinsic types and operations //! -//! The [`ptr`](../core/ptr/index.html) and [`mem`](../core/mem/index.html) +//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html) //! modules deal with unsafe pointers and memory manipulation. -//! [`kinds`](../core/kinds/index.html) defines the special built-in traits, -//! and [`raw`](../core/raw/index.html) the runtime representation of Rust types. +//! [`kinds`](kinds/index.html) defines the special built-in traits, +//! and [`raw`](raw/index.html) the runtime representation of Rust types. //! These are some of the lowest-level building blocks in Rust. //! //! ## Math on primitive types and math traits @@ -31,11 +31,11 @@ //! //! ## Pervasive types //! -//! The [`option`](option/index.html) and [`result`](../core/result/index.html) +//! The [`option`](option/index.html) and [`result`](result/index.html) //! modules define optional and error-handling types, `Option` and `Result`. -//! [`iter`](../core/iter/index.html) defines Rust's iterator protocol +//! [`iter`](iter/index.html) defines Rust's iterator protocol //! along with a wide variety of iterators. -//! [`Cell` and `RefCell`](../core/cell/index.html) are for creating types that +//! [`Cell` and `RefCell`](cell/index.html) are for creating types that //! manage their own mutability. //! //! ## Vectors, slices and strings diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 8d028a7a96a7e..07aaeac64be1c 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -38,55 +38,62 @@ //! `drop`, `spawn`, and `channel`. // Reexported core operators -pub use kinds::{Copy, Send, Sized, Share}; -pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; -pub use ops::{BitAnd, BitOr, BitXor}; -pub use ops::{Drop, Deref, DerefMut}; -pub use ops::{Shl, Shr, Index}; -pub use option::{Option, Some, None}; -pub use result::{Result, Ok, Err}; +#[doc(no_inline)] pub use kinds::{Copy, Send, Sized, Share}; +#[doc(no_inline)] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; +#[doc(no_inline)] pub use ops::{BitAnd, BitOr, BitXor}; +#[doc(no_inline)] pub use ops::{Drop, Deref, DerefMut}; +#[doc(no_inline)] pub use ops::{Shl, Shr, Index}; +#[doc(no_inline)] pub use option::{Option, Some, None}; +#[doc(no_inline)] pub use result::{Result, Ok, Err}; // Reexported functions -pub use from_str::from_str; -pub use iter::range; -pub use mem::drop; +#[doc(no_inline)] pub use from_str::from_str; +#[doc(no_inline)] pub use iter::range; +#[doc(no_inline)] pub use mem::drop; // Reexported types and traits -pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr, IntoBytes}; -pub use c_str::ToCStr; -pub use char::Char; -pub use clone::Clone; -pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; -pub use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; -pub use iter::{FromIterator, Extendable}; -pub use iter::{Iterator, DoubleEndedIterator, RandomAccessIterator, CloneableIterator}; -pub use iter::{OrdIterator, MutableDoubleEndedIterator, ExactSize}; -pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; -pub use num::{Signed, Unsigned}; -pub use num::{Primitive, Int, Float, FloatMath, ToPrimitive, FromPrimitive}; -pub use option::Expect; -pub use owned::Box; -pub use path::{GenericPath, Path, PosixPath, WindowsPath}; -pub use ptr::RawPtr; -pub use io::{Buffer, Writer, Reader, Seek}; -pub use str::{Str, StrVector, StrSlice, OwnedStr, IntoMaybeOwned}; -pub use str::{StrAllocating}; -pub use to_str::{ToStr, IntoStr}; -pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; -pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; -pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; -pub use slice::{CloneableVector, ImmutableCloneableVector, MutableCloneableVector}; -pub use slice::{ImmutableVector, MutableVector}; -pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector, MutableTotalOrdVector}; -pub use slice::{Vector, VectorVector, OwnedVector, MutableVectorAllocating}; -pub use string::String; -pub use vec::Vec; +#[doc(no_inline)] pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; +#[doc(no_inline)] pub use ascii::IntoBytes; +#[doc(no_inline)] pub use c_str::ToCStr; +#[doc(no_inline)] pub use char::Char; +#[doc(no_inline)] pub use clone::Clone; +#[doc(no_inline)] pub use cmp::{Eq, Ord, TotalEq, TotalOrd}; +#[doc(no_inline)] pub use cmp::{Ordering, Less, Equal, Greater, Equiv}; +#[doc(no_inline)] pub use container::{Container, Mutable, Map, MutableMap}; +#[doc(no_inline)] pub use container::{Set, MutableSet}; +#[doc(no_inline)] pub use iter::{FromIterator, Extendable, ExactSize}; +#[doc(no_inline)] pub use iter::{Iterator, DoubleEndedIterator}; +#[doc(no_inline)] pub use iter::{RandomAccessIterator, CloneableIterator}; +#[doc(no_inline)] pub use iter::{OrdIterator, MutableDoubleEndedIterator}; +#[doc(no_inline)] pub use num::{Num, NumCast, CheckedAdd, CheckedSub, CheckedMul}; +#[doc(no_inline)] pub use num::{Signed, Unsigned, Primitive, Int, Float}; +#[doc(no_inline)] pub use num::{FloatMath, ToPrimitive, FromPrimitive}; +#[doc(no_inline)] pub use option::Expect; +#[doc(no_inline)] pub use owned::Box; +#[doc(no_inline)] pub use path::{GenericPath, Path, PosixPath, WindowsPath}; +#[doc(no_inline)] pub use ptr::RawPtr; +#[doc(no_inline)] pub use io::{Buffer, Writer, Reader, Seek}; +#[doc(no_inline)] pub use str::{Str, StrVector, StrSlice, OwnedStr}; +#[doc(no_inline)] pub use str::{IntoMaybeOwned, StrAllocating}; +#[doc(no_inline)] pub use to_str::{ToStr, IntoStr}; +#[doc(no_inline)] pub use tuple::{Tuple1, Tuple2, Tuple3, Tuple4}; +#[doc(no_inline)] pub use tuple::{Tuple5, Tuple6, Tuple7, Tuple8}; +#[doc(no_inline)] pub use tuple::{Tuple9, Tuple10, Tuple11, Tuple12}; +#[doc(no_inline)] pub use slice::{CloneableVector, ImmutableCloneableVector}; +#[doc(no_inline)] pub use slice::{MutableCloneableVector, MutableTotalOrdVector}; +#[doc(no_inline)] pub use slice::{ImmutableVector, MutableVector}; +#[doc(no_inline)] pub use slice::{ImmutableEqVector, ImmutableTotalOrdVector}; +#[doc(no_inline)] pub use slice::{Vector, VectorVector, OwnedVector}; +#[doc(no_inline)] pub use slice::MutableVectorAllocating; +#[doc(no_inline)] pub use string::String; +#[doc(no_inline)] pub use vec::Vec; // Reexported runtime types -pub use comm::{sync_channel, channel, SyncSender, Sender, Receiver}; -pub use task::spawn; +#[doc(no_inline)] pub use comm::{sync_channel, channel}; +#[doc(no_inline)] pub use comm::{SyncSender, Sender, Receiver}; +#[doc(no_inline)] pub use task::spawn; // Reexported statics #[cfg(not(test))] -pub use gc::GC; +#[doc(no_inline)] pub use gc::GC;