2013-09-19 00:18:38 -05:00
|
|
|
// Copyright 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 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
|
|
|
use std::fmt;
|
|
|
|
use std::local_data;
|
|
|
|
use std::rt::io;
|
|
|
|
|
|
|
|
use syntax::ast;
|
2013-09-24 15:55:22 -05:00
|
|
|
use syntax::ast_util;
|
2013-09-19 00:18:38 -05:00
|
|
|
|
|
|
|
use clean;
|
|
|
|
use html::render::{cache_key, current_location_key};
|
|
|
|
|
|
|
|
pub struct VisSpace(Option<ast::visibility>);
|
2013-09-23 22:38:17 -05:00
|
|
|
pub struct PuritySpace(ast::purity);
|
2013-09-19 00:18:38 -05:00
|
|
|
pub struct Method<'self>(&'self clean::SelfTy, &'self clean::FnDecl);
|
|
|
|
|
|
|
|
impl fmt::Default for clean::Generics {
|
|
|
|
fn fmt(g: &clean::Generics, f: &mut fmt::Formatter) {
|
|
|
|
if g.lifetimes.len() == 0 && g.type_params.len() == 0 { return }
|
|
|
|
f.buf.write("<".as_bytes());
|
|
|
|
|
|
|
|
for (i, life) in g.lifetimes.iter().enumerate() {
|
|
|
|
if i > 0 { f.buf.write(", ".as_bytes()); }
|
|
|
|
write!(f.buf, "{}", *life);
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.type_params.len() > 0 {
|
|
|
|
if g.lifetimes.len() > 0 { f.buf.write(", ".as_bytes()); }
|
|
|
|
|
|
|
|
for (i, tp) in g.type_params.iter().enumerate() {
|
|
|
|
if i > 0 { f.buf.write(", ".as_bytes()) }
|
|
|
|
f.buf.write(tp.name.as_bytes());
|
|
|
|
|
|
|
|
if tp.bounds.len() > 0 {
|
|
|
|
f.buf.write(": ".as_bytes());
|
|
|
|
for (i, bound) in tp.bounds.iter().enumerate() {
|
|
|
|
if i > 0 { f.buf.write(" + ".as_bytes()); }
|
|
|
|
write!(f.buf, "{}", *bound);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f.buf.write(">".as_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for clean::Lifetime {
|
|
|
|
fn fmt(l: &clean::Lifetime, f: &mut fmt::Formatter) {
|
|
|
|
f.buf.write("'".as_bytes());
|
|
|
|
f.buf.write(l.as_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for clean::TyParamBound {
|
|
|
|
fn fmt(bound: &clean::TyParamBound, f: &mut fmt::Formatter) {
|
|
|
|
match *bound {
|
|
|
|
clean::RegionBound => {
|
|
|
|
f.buf.write("'static".as_bytes())
|
|
|
|
}
|
|
|
|
clean::TraitBound(ref ty) => {
|
|
|
|
write!(f.buf, "{}", *ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for clean::Path {
|
|
|
|
fn fmt(path: &clean::Path, f: &mut fmt::Formatter) {
|
|
|
|
if path.global { f.buf.write("::".as_bytes()) }
|
|
|
|
for (i, seg) in path.segments.iter().enumerate() {
|
|
|
|
if i > 0 { f.buf.write("::".as_bytes()) }
|
|
|
|
f.buf.write(seg.name.as_bytes());
|
|
|
|
|
|
|
|
if seg.lifetime.is_some() || seg.types.len() > 0 {
|
|
|
|
f.buf.write("<".as_bytes());
|
|
|
|
match seg.lifetime {
|
|
|
|
Some(ref lifetime) => write!(f.buf, "{}", *lifetime),
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
for (i, ty) in seg.types.iter().enumerate() {
|
|
|
|
if i > 0 || seg.lifetime.is_some() {
|
|
|
|
f.buf.write(", ".as_bytes());
|
|
|
|
}
|
|
|
|
write!(f.buf, "{}", *ty);
|
|
|
|
}
|
|
|
|
f.buf.write(">".as_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-27 20:23:57 -05:00
|
|
|
fn resolved_path(w: &mut io::Writer, did: ast::DefId,
|
2013-09-24 15:56:52 -05:00
|
|
|
path: &clean::Path, print_all: bool) {
|
2013-09-19 00:18:38 -05:00
|
|
|
// The generics will get written to both the title and link
|
|
|
|
let mut generics = ~"";
|
|
|
|
let last = path.segments.last();
|
|
|
|
if last.lifetime.is_some() || last.types.len() > 0 {
|
|
|
|
generics.push_str("<");
|
|
|
|
match last.lifetime {
|
|
|
|
Some(ref lifetime) => generics.push_str(format!("{}", *lifetime)),
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
for (i, ty) in last.types.iter().enumerate() {
|
|
|
|
if i > 0 || last.lifetime.is_some() {
|
|
|
|
generics.push_str(", ");
|
|
|
|
}
|
|
|
|
generics.push_str(format!("{}", *ty));
|
|
|
|
}
|
|
|
|
generics.push_str(">");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Did someone say rightward-drift?
|
|
|
|
do local_data::get(current_location_key) |loc| {
|
|
|
|
let loc = loc.unwrap();
|
2013-09-24 15:56:52 -05:00
|
|
|
|
|
|
|
if print_all {
|
|
|
|
let mut root = match path.segments[0].name.as_slice() {
|
|
|
|
"super" => ~"../",
|
|
|
|
"self" => ~"",
|
|
|
|
_ => "../".repeat(loc.len() - 1),
|
|
|
|
};
|
|
|
|
let amt = path.segments.len() - 1;
|
|
|
|
for seg in path.segments.slice_to(amt).iter() {
|
|
|
|
if "super" == seg.name || "self" == seg.name {
|
|
|
|
write!(w, "{}::", seg.name);
|
|
|
|
} else {
|
|
|
|
root.push_str(seg.name);
|
|
|
|
root.push_str("/");
|
|
|
|
write!(w, "<a class='mod'
|
|
|
|
href='{}index.html'>{}</a>::",
|
|
|
|
root,
|
|
|
|
seg.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-19 00:18:38 -05:00
|
|
|
do local_data::get(cache_key) |cache| {
|
|
|
|
do cache.unwrap().read |cache| {
|
2013-09-27 20:23:57 -05:00
|
|
|
match cache.paths.find(&did.node) {
|
2013-09-19 00:18:38 -05:00
|
|
|
// This is a documented path, link to it!
|
2013-09-27 20:23:57 -05:00
|
|
|
// FIXME(#9539): this is_local check should not exist
|
|
|
|
Some(&(ref fqp, shortty)) if ast_util::is_local(did) => {
|
2013-09-19 00:18:38 -05:00
|
|
|
let fqn = fqp.connect("::");
|
2013-09-24 15:56:52 -05:00
|
|
|
let same = loc.iter().zip(fqp.iter())
|
|
|
|
.take_while(|&(a, b)| *a == *b).len();
|
2013-09-19 00:18:38 -05:00
|
|
|
|
|
|
|
let mut url = ~"";
|
2013-09-24 15:56:52 -05:00
|
|
|
if "super" == path.segments[0].name {
|
2013-09-19 00:18:38 -05:00
|
|
|
url.push_str("../");
|
2013-09-24 15:56:52 -05:00
|
|
|
} else if "self" != path.segments[0].name {
|
|
|
|
url.push_str("../".repeat(loc.len() - same));
|
2013-09-19 00:18:38 -05:00
|
|
|
}
|
2013-09-24 15:56:52 -05:00
|
|
|
if same < fqp.len() {
|
2013-09-19 00:18:38 -05:00
|
|
|
let remaining = fqp.slice_from(same);
|
|
|
|
let to_link = remaining.slice_to(remaining.len() - 1);
|
|
|
|
for component in to_link.iter() {
|
|
|
|
url.push_str(*component);
|
|
|
|
url.push_str("/");
|
|
|
|
}
|
|
|
|
}
|
2013-09-24 15:56:52 -05:00
|
|
|
match shortty {
|
|
|
|
"mod" => {
|
|
|
|
url.push_str(*fqp.last());
|
|
|
|
url.push_str("/index.html");
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
url.push_str(shortty);
|
|
|
|
url.push_str(".");
|
|
|
|
url.push_str(*fqp.last());
|
|
|
|
url.push_str(".html");
|
|
|
|
}
|
|
|
|
}
|
2013-09-19 00:18:38 -05:00
|
|
|
write!(w, "<a class='{}' href='{}' title='{}'>{}</a>{}",
|
|
|
|
shortty, url, fqn, last.name, generics);
|
|
|
|
}
|
2013-09-27 20:23:57 -05:00
|
|
|
_ => {
|
2013-09-24 15:56:52 -05:00
|
|
|
if print_all {
|
|
|
|
let amt = path.segments.len() - 1;
|
|
|
|
for seg in path.segments.iter().take(amt) {
|
|
|
|
write!(w, "{}::", seg.name);
|
|
|
|
}
|
|
|
|
}
|
2013-09-19 00:18:38 -05:00
|
|
|
write!(w, "{}{}", last.name, generics);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for clean::Type {
|
|
|
|
fn fmt(g: &clean::Type, f: &mut fmt::Formatter) {
|
|
|
|
match *g {
|
|
|
|
clean::TyParamBinder(id) | clean::Generic(id) => {
|
|
|
|
do local_data::get(cache_key) |cache| {
|
|
|
|
do cache.unwrap().read |m| {
|
|
|
|
f.buf.write(m.typarams.get(&id).as_bytes());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-27 20:23:57 -05:00
|
|
|
clean::ResolvedPath{did, typarams: ref typarams, path: ref path} => {
|
|
|
|
resolved_path(f.buf, did, path, false);
|
2013-09-19 00:18:38 -05:00
|
|
|
match *typarams {
|
|
|
|
Some(ref params) => {
|
|
|
|
f.buf.write("<".as_bytes());
|
|
|
|
for (i, param) in params.iter().enumerate() {
|
|
|
|
if i > 0 { f.buf.write(", ".as_bytes()) }
|
|
|
|
write!(f.buf, "{}", *param);
|
|
|
|
}
|
|
|
|
f.buf.write(">".as_bytes());
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clean::Self(*) => f.buf.write("Self".as_bytes()),
|
|
|
|
clean::Primitive(prim) => {
|
|
|
|
let s = match prim {
|
|
|
|
ast::ty_int(ast::ty_i) => "int",
|
|
|
|
ast::ty_int(ast::ty_i8) => "i8",
|
|
|
|
ast::ty_int(ast::ty_i16) => "i16",
|
|
|
|
ast::ty_int(ast::ty_i32) => "i32",
|
|
|
|
ast::ty_int(ast::ty_i64) => "i64",
|
|
|
|
ast::ty_uint(ast::ty_u) => "uint",
|
|
|
|
ast::ty_uint(ast::ty_u8) => "u8",
|
|
|
|
ast::ty_uint(ast::ty_u16) => "u16",
|
|
|
|
ast::ty_uint(ast::ty_u32) => "u32",
|
|
|
|
ast::ty_uint(ast::ty_u64) => "u64",
|
|
|
|
ast::ty_float(ast::ty_f32) => "f32",
|
|
|
|
ast::ty_float(ast::ty_f64) => "f64",
|
|
|
|
ast::ty_str => "str",
|
|
|
|
ast::ty_bool => "bool",
|
|
|
|
ast::ty_char => "char",
|
|
|
|
};
|
|
|
|
f.buf.write(s.as_bytes());
|
|
|
|
}
|
|
|
|
clean::Closure(ref decl) => {
|
|
|
|
f.buf.write(match decl.sigil {
|
|
|
|
ast::BorrowedSigil => "&",
|
|
|
|
ast::ManagedSigil => "@",
|
|
|
|
ast::OwnedSigil => "~",
|
|
|
|
}.as_bytes());
|
|
|
|
match decl.region {
|
|
|
|
Some(ref region) => write!(f.buf, "{} ", *region),
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
write!(f.buf, "{}{}fn{}",
|
2013-09-23 22:38:17 -05:00
|
|
|
PuritySpace(decl.purity),
|
2013-09-19 00:18:38 -05:00
|
|
|
match decl.onceness {
|
|
|
|
ast::Once => "once ",
|
|
|
|
ast::Many => "",
|
|
|
|
},
|
|
|
|
decl.decl);
|
|
|
|
// XXX: where are bounds and lifetimes printed?!
|
|
|
|
}
|
|
|
|
clean::BareFunction(ref decl) => {
|
|
|
|
write!(f.buf, "{}{}fn{}{}",
|
2013-09-23 22:38:17 -05:00
|
|
|
PuritySpace(decl.purity),
|
2013-09-19 00:18:38 -05:00
|
|
|
match decl.abi {
|
|
|
|
~"" | ~"\"Rust\"" => ~"",
|
|
|
|
ref s => " " + *s + " ",
|
|
|
|
},
|
|
|
|
decl.generics,
|
|
|
|
decl.decl);
|
|
|
|
}
|
|
|
|
clean::Tuple(ref typs) => {
|
|
|
|
f.buf.write("(".as_bytes());
|
|
|
|
for (i, typ) in typs.iter().enumerate() {
|
|
|
|
if i > 0 { f.buf.write(", ".as_bytes()) }
|
|
|
|
write!(f.buf, "{}", *typ);
|
|
|
|
}
|
|
|
|
f.buf.write(")".as_bytes());
|
|
|
|
}
|
|
|
|
clean::Vector(ref t) => write!(f.buf, "[{}]", **t),
|
|
|
|
clean::FixedVector(ref t, ref s) => {
|
|
|
|
write!(f.buf, "[{}, ..{}]", **t, *s);
|
|
|
|
}
|
|
|
|
clean::String => f.buf.write("str".as_bytes()),
|
|
|
|
clean::Bool => f.buf.write("bool".as_bytes()),
|
|
|
|
clean::Unit => f.buf.write("()".as_bytes()),
|
|
|
|
clean::Bottom => f.buf.write("!".as_bytes()),
|
|
|
|
clean::Unique(ref t) => write!(f.buf, "~{}", **t),
|
|
|
|
clean::Managed(m, ref t) => {
|
|
|
|
write!(f.buf, "@{}{}",
|
|
|
|
match m {
|
|
|
|
clean::Mutable => "mut ",
|
|
|
|
clean::Immutable => "",
|
|
|
|
}, **t)
|
|
|
|
}
|
|
|
|
clean::RawPointer(m, ref t) => {
|
|
|
|
write!(f.buf, "*{}{}",
|
|
|
|
match m {
|
|
|
|
clean::Mutable => "mut ",
|
|
|
|
clean::Immutable => "",
|
|
|
|
}, **t)
|
|
|
|
}
|
|
|
|
clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
|
|
|
|
let lt = match *l { Some(ref l) => format!("{} ", *l), _ => ~"" };
|
|
|
|
write!(f.buf, "&{}{}{}",
|
|
|
|
lt,
|
|
|
|
match mutability {
|
|
|
|
clean::Mutable => "mut ",
|
|
|
|
clean::Immutable => "",
|
|
|
|
},
|
|
|
|
**ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for clean::FnDecl {
|
|
|
|
fn fmt(d: &clean::FnDecl, f: &mut fmt::Formatter) {
|
|
|
|
let mut args = ~"";
|
|
|
|
for (i, input) in d.inputs.iter().enumerate() {
|
|
|
|
if i > 0 { args.push_str(", "); }
|
|
|
|
if input.name.len() > 0 {
|
|
|
|
args.push_str(format!("{}: ", input.name));
|
|
|
|
}
|
|
|
|
args.push_str(format!("{}", input.type_));
|
|
|
|
}
|
|
|
|
write!(f.buf, "({args}){arrow, select, yes{ -> {ret}} other{}}",
|
|
|
|
args = args,
|
|
|
|
arrow = match d.output { clean::Unit => "no", _ => "yes" },
|
|
|
|
ret = d.output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'self> fmt::Default for Method<'self> {
|
|
|
|
fn fmt(m: &Method<'self>, f: &mut fmt::Formatter) {
|
|
|
|
let Method(selfty, d) = *m;
|
|
|
|
let mut args = ~"";
|
|
|
|
match *selfty {
|
|
|
|
clean::SelfStatic => {},
|
|
|
|
clean::SelfValue => args.push_str("self"),
|
|
|
|
clean::SelfOwned => args.push_str("~self"),
|
|
|
|
clean::SelfManaged(clean::Mutable) => args.push_str("@mut self"),
|
|
|
|
clean::SelfManaged(clean::Immutable) => args.push_str("@self"),
|
|
|
|
clean::SelfBorrowed(Some(ref lt), clean::Immutable) => {
|
|
|
|
args.push_str(format!("&{} self", *lt));
|
|
|
|
}
|
|
|
|
clean::SelfBorrowed(Some(ref lt), clean::Mutable) => {
|
|
|
|
args.push_str(format!("&{} mut self", *lt));
|
|
|
|
}
|
|
|
|
clean::SelfBorrowed(None, clean::Mutable) => {
|
|
|
|
args.push_str("&mut self");
|
|
|
|
}
|
|
|
|
clean::SelfBorrowed(None, clean::Immutable) => {
|
|
|
|
args.push_str("&self");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i, input) in d.inputs.iter().enumerate() {
|
|
|
|
if i > 0 || args.len() > 0 { args.push_str(", "); }
|
|
|
|
if input.name.len() > 0 {
|
|
|
|
args.push_str(format!("{}: ", input.name));
|
|
|
|
}
|
|
|
|
args.push_str(format!("{}", input.type_));
|
|
|
|
}
|
|
|
|
write!(f.buf, "({args}){arrow, select, yes{ -> {ret}} other{}}",
|
|
|
|
args = args,
|
|
|
|
arrow = match d.output { clean::Unit => "no", _ => "yes" },
|
|
|
|
ret = d.output);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for VisSpace {
|
|
|
|
fn fmt(v: &VisSpace, f: &mut fmt::Formatter) {
|
|
|
|
match **v {
|
|
|
|
Some(ast::public) => { write!(f.buf, "pub "); }
|
|
|
|
Some(ast::private) => { write!(f.buf, "priv "); }
|
|
|
|
Some(ast::inherited) | None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-23 22:38:17 -05:00
|
|
|
|
|
|
|
impl fmt::Default for PuritySpace {
|
|
|
|
fn fmt(p: &PuritySpace, f: &mut fmt::Formatter) {
|
|
|
|
match **p {
|
|
|
|
ast::unsafe_fn => write!(f.buf, "unsafe "),
|
|
|
|
ast::extern_fn => write!(f.buf, "extern "),
|
|
|
|
ast::impure_fn => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-24 15:56:52 -05:00
|
|
|
|
|
|
|
impl fmt::Default for clean::ViewPath {
|
|
|
|
fn fmt(v: &clean::ViewPath, f: &mut fmt::Formatter) {
|
|
|
|
match *v {
|
|
|
|
clean::SimpleImport(ref name, ref src) => {
|
|
|
|
if *name == src.path.segments.last().name {
|
|
|
|
write!(f.buf, "use {};", *src);
|
|
|
|
} else {
|
|
|
|
write!(f.buf, "use {} = {};", *name, *src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
clean::GlobImport(ref src) => {
|
|
|
|
write!(f.buf, "use {}::*;", *src);
|
|
|
|
}
|
|
|
|
clean::ImportList(ref src, ref names) => {
|
|
|
|
write!(f.buf, "use {}::\\{", *src);
|
|
|
|
for (i, n) in names.iter().enumerate() {
|
|
|
|
if i > 0 { write!(f.buf, ", "); }
|
|
|
|
write!(f.buf, "{}", *n);
|
|
|
|
}
|
|
|
|
write!(f.buf, "\\};");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for clean::ImportSource {
|
|
|
|
fn fmt(v: &clean::ImportSource, f: &mut fmt::Formatter) {
|
|
|
|
match v.did {
|
2013-09-27 20:23:57 -05:00
|
|
|
Some(did) => {
|
|
|
|
resolved_path(f.buf, did, &v.path, true);
|
2013-09-24 15:56:52 -05:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
for (i, seg) in v.path.segments.iter().enumerate() {
|
|
|
|
if i > 0 { write!(f.buf, "::") }
|
|
|
|
write!(f.buf, "{}", seg.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Default for clean::ViewListIdent {
|
|
|
|
fn fmt(v: &clean::ViewListIdent, f: &mut fmt::Formatter) {
|
|
|
|
match v.source {
|
2013-09-27 20:23:57 -05:00
|
|
|
Some(did) => {
|
2013-09-24 15:56:52 -05:00
|
|
|
let path = clean::Path {
|
|
|
|
global: false,
|
|
|
|
segments: ~[clean::PathSegment {
|
|
|
|
name: v.name.clone(),
|
|
|
|
lifetime: None,
|
|
|
|
types: ~[],
|
|
|
|
}]
|
|
|
|
};
|
2013-09-27 20:23:57 -05:00
|
|
|
resolved_path(f.buf, did, &path, false);
|
2013-09-24 15:56:52 -05:00
|
|
|
}
|
|
|
|
_ => write!(f.buf, "{}", v.name),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|