]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/format.rs
b24e7a7a4cf81a06d6fb25572293a787c1c56b5f
[rust.git] / src / librustdoc / html / format.rs
1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! HTML formatting module
12 //!
13 //! This module contains a large number of `fmt::String` implementations for
14 //! various types in `rustdoc::clean`. These implementations all currently
15 //! assume that HTML output is desired, although it may be possible to redesign
16 //! them in the future to instead emit any format desired.
17
18 use std::fmt;
19 use std::iter::repeat;
20
21 use syntax::ast;
22 use syntax::ast_util;
23
24 use clean;
25 use stability_summary::ModuleSummary;
26 use html::item_type::ItemType;
27 use html::render;
28 use html::render::{cache, CURRENT_LOCATION_KEY};
29
30 /// Helper to render an optional visibility with a space after it (if the
31 /// visibility is preset)
32 #[derive(Copy)]
33 pub struct VisSpace(pub Option<ast::Visibility>);
34 /// Similarly to VisSpace, this structure is used to render a function style with a
35 /// space after it.
36 #[derive(Copy)]
37 pub struct UnsafetySpace(pub ast::Unsafety);
38 /// Wrapper struct for properly emitting a method declaration.
39 pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
40 /// Similar to VisSpace, but used for mutability
41 #[derive(Copy)]
42 pub struct MutableSpace(pub clean::Mutability);
43 /// Similar to VisSpace, but used for mutability
44 #[derive(Copy)]
45 pub struct RawMutableSpace(pub clean::Mutability);
46 /// Wrapper struct for properly emitting the stability level.
47 pub struct Stability<'a>(pub &'a Option<clean::Stability>);
48 /// Wrapper struct for emitting the stability level concisely.
49 pub struct ConciseStability<'a>(pub &'a Option<clean::Stability>);
50 /// Wrapper struct for emitting a where clause from Generics.
51 pub struct WhereClause<'a>(pub &'a clean::Generics);
52 /// Wrapper struct for emitting type parameter bounds.
53 pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
54
55 impl VisSpace {
56     pub fn get(&self) -> Option<ast::Visibility> {
57         let VisSpace(v) = *self; v
58     }
59 }
60
61 impl UnsafetySpace {
62     pub fn get(&self) -> ast::Unsafety {
63         let UnsafetySpace(v) = *self; v
64     }
65 }
66
67 //NOTE(stage0): remove impl after snapshot
68 #[cfg(stage0)]
69 impl<'a> fmt::Show for TyParamBounds<'a> {
70     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71         fmt::String::fmt(self, f)
72     }
73 }
74
75 impl<'a> fmt::String for TyParamBounds<'a> {
76     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
77         let &TyParamBounds(bounds) = self;
78         for (i, bound) in bounds.iter().enumerate() {
79             if i > 0 {
80                 try!(f.write_str(" + "));
81             }
82             try!(write!(f, "{}", *bound));
83         }
84         Ok(())
85     }
86 }
87
88 //NOTE(stage0): remove impl after snapshot
89 #[cfg(stage0)]
90 impl fmt::Show for clean::Generic {
91     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92         fmt::String::fmt(self, f)
93     }
94 }
95
96 impl fmt::String for clean::Generics {
97     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98         if self.lifetimes.len() == 0 && self.type_params.len() == 0 { return Ok(()) }
99         try!(f.write_str("&lt;"));
100
101         for (i, life) in self.lifetimes.iter().enumerate() {
102             if i > 0 {
103                 try!(f.write_str(", "));
104             }
105             try!(write!(f, "{}", *life));
106         }
107
108         if self.type_params.len() > 0 {
109             if self.lifetimes.len() > 0 {
110                 try!(f.write_str(", "));
111             }
112             for (i, tp) in self.type_params.iter().enumerate() {
113                 if i > 0 {
114                     try!(f.write_str(", "))
115                 }
116                 try!(f.write_str(tp.name.as_slice()));
117
118                 if tp.bounds.len() > 0 {
119                     try!(write!(f, ": {}", TyParamBounds(tp.bounds.as_slice())));
120                 }
121
122                 match tp.default {
123                     Some(ref ty) => { try!(write!(f, " = {}", ty)); },
124                     None => {}
125                 };
126             }
127         }
128         try!(f.write_str("&gt;"));
129         Ok(())
130     }
131 }
132
133 //NOTE(stage0): remove impl after snapshot
134 #[cfg(stage0)]
135 impl<'a> fmt::Show for WhereClause<'a> {
136     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137         fmt::String::fmt(self, f)
138     }
139 }
140
141 impl<'a> fmt::String for WhereClause<'a> {
142     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143         let &WhereClause(gens) = self;
144         if gens.where_predicates.len() == 0 {
145             return Ok(());
146         }
147         try!(f.write_str(" <span class='where'>where "));
148         for (i, pred) in gens.where_predicates.iter().enumerate() {
149             if i > 0 {
150                 try!(f.write_str(", "));
151             }
152             match pred {
153                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
154                     let bounds = bounds.as_slice();
155                     try!(write!(f, "{}: {}", ty, TyParamBounds(bounds)));
156                 }
157                 &clean::WherePredicate::RegionPredicate { ref lifetime,
158                                                           ref bounds } => {
159                     try!(write!(f, "{}: ", lifetime));
160                     for (i, lifetime) in bounds.iter().enumerate() {
161                         if i > 0 {
162                             try!(f.write_str(" + "));
163                         }
164
165                         try!(write!(f, "{}", lifetime));
166                     }
167                 }
168                 &clean::WherePredicate::EqPredicate => {
169                     unimplemented!()
170                 }
171             }
172         }
173         try!(f.write_str("</span>"));
174         Ok(())
175     }
176 }
177
178 //NOTE(stage0): remove impl after snapshot
179 #[cfg(stage0)]
180 impl fmt::Show for clean::Lifetime {
181     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182         fmt::String::fmt(self, f)
183     }
184 }
185
186 impl fmt::String for clean::Lifetime {
187     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188         try!(f.write_str(self.get_ref()));
189         Ok(())
190     }
191 }
192
193 //NOTE(stage0): remove impl after snapshot
194 #[cfg(stage0)]
195 impl fmt::Show for clean::PolyTrait {
196     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197         fmt::String::fmt(self, f)
198     }
199 }
200
201 impl fmt::String for clean::PolyTrait {
202     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
203         if self.lifetimes.len() > 0 {
204             try!(f.write_str("for&lt;"));
205             for (i, lt) in self.lifetimes.iter().enumerate() {
206                 if i > 0 {
207                     try!(f.write_str(", "));
208                 }
209                 try!(write!(f, "{}", lt));
210             }
211             try!(f.write_str("&gt; "));
212         }
213         write!(f, "{}", self.trait_)
214     }
215 }
216
217 //NOTE(stage0): remove impl after snapshot
218 #[cfg(stage0)]
219 impl fmt::Show for clean::TyParamBound {
220     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221         fmt::String::fmt(self, f)
222     }
223 }
224
225 impl fmt::String for clean::TyParamBound {
226     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
227         match *self {
228             clean::RegionBound(ref lt) => {
229                 write!(f, "{}", *lt)
230             }
231             clean::TraitBound(ref ty, modifier) => {
232                 let modifier_str = match modifier {
233                     ast::TraitBoundModifier::None => "",
234                     ast::TraitBoundModifier::Maybe => "?",
235                 };
236                 write!(f, "{}{}", modifier_str, *ty)
237             }
238         }
239     }
240 }
241
242 //NOTE(stage0): remove impl after snapshot
243 #[cfg(stage0)]
244 impl fmt::Show for clean::PathParameters {
245     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246         fmt::String::fmt(self, f)
247     }
248 }
249
250 impl fmt::String for clean::PathParameters {
251     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252         match *self {
253             clean::PathParameters::AngleBracketed { ref lifetimes, ref types } => {
254                 if lifetimes.len() > 0 || types.len() > 0 {
255                     try!(f.write_str("&lt;"));
256                     let mut comma = false;
257                     for lifetime in lifetimes.iter() {
258                         if comma {
259                             try!(f.write_str(", "));
260                         }
261                         comma = true;
262                         try!(write!(f, "{}", *lifetime));
263                     }
264                     for ty in types.iter() {
265                         if comma {
266                             try!(f.write_str(", "));
267                         }
268                         comma = true;
269                         try!(write!(f, "{}", *ty));
270                     }
271                     try!(f.write_str("&gt;"));
272                 }
273             }
274             clean::PathParameters::Parenthesized { ref inputs, ref output } => {
275                 try!(f.write_str("("));
276                 let mut comma = false;
277                 for ty in inputs.iter() {
278                     if comma {
279                         try!(f.write_str(", "));
280                     }
281                     comma = true;
282                     try!(write!(f, "{}", *ty));
283                 }
284                 try!(f.write_str(")"));
285                 if let Some(ref ty) = *output {
286                     try!(f.write_str(" -&gt; "));
287                     try!(write!(f, "{}", ty));
288                 }
289             }
290         }
291         Ok(())
292     }
293 }
294
295 //NOTE(stage0): remove impl after snapshot
296 #[cfg(stage0)]
297 impl fmt::Show for clean::PathSegment {
298     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299         fmt::String::fmt(self, f)
300     }
301 }
302
303 impl fmt::String for clean::PathSegment {
304     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
305         try!(f.write_str(self.name.as_slice()));
306         write!(f, "{}", self.params)
307     }
308 }
309
310 //NOTE(stage0): remove impl after snapshot
311 #[cfg(stage0)]
312 impl fmt::Show for clean::Path {
313     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314         fmt::String::fmt(self, f)
315     }
316 }
317
318 impl fmt::String for clean::Path {
319     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320         if self.global {
321             try!(f.write_str("::"))
322         }
323
324         for (i, seg) in self.segments.iter().enumerate() {
325             if i > 0 {
326                 try!(f.write_str("::"))
327             }
328             try!(write!(f, "{}", seg));
329         }
330         Ok(())
331     }
332 }
333
334 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
335 /// rendering function with the necessary arguments for linking to a local path.
336 fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, p: &clean::Path,
337                  print_all: bool) -> fmt::Result {
338     path(w, p, print_all,
339         |cache, loc| {
340             if ast_util::is_local(did) || cache.inlined.contains(&did) {
341                 Some(repeat("../").take(loc.len()).collect::<String>())
342             } else {
343                 match cache.extern_locations[did.krate] {
344                     render::Remote(ref s) => Some(s.to_string()),
345                     render::Local => {
346                         Some(repeat("../").take(loc.len()).collect::<String>())
347                     }
348                     render::Unknown => None,
349                 }
350             }
351         },
352         |cache| {
353             match cache.paths.get(&did) {
354                 None => None,
355                 Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty))
356             }
357         })
358 }
359
360 fn path<F, G>(w: &mut fmt::Formatter,
361               path: &clean::Path,
362               print_all: bool,
363               root: F,
364               info: G)
365               -> fmt::Result where
366     F: FnOnce(&render::Cache, &[String]) -> Option<String>,
367     G: FnOnce(&render::Cache) -> Option<(Vec<String>, ItemType)>,
368 {
369     // The generics will get written to both the title and link
370     let last = path.segments.last().unwrap();
371     let generics = format!("{}", last.params);
372
373     let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
374     let cache = cache();
375     let abs_root = root(&*cache, loc.as_slice());
376     let rel_root = match path.segments[0].name.as_slice() {
377         "self" => Some("./".to_string()),
378         _ => None,
379     };
380
381     if print_all {
382         let amt = path.segments.len() - 1;
383         match rel_root {
384             Some(root) => {
385                 let mut root = String::from_str(root.as_slice());
386                 for seg in path.segments.index(&(0..amt)).iter() {
387                     if "super" == seg.name ||
388                             "self" == seg.name {
389                         try!(write!(w, "{}::", seg.name));
390                     } else {
391                         root.push_str(seg.name.as_slice());
392                         root.push_str("/");
393                         try!(write!(w, "<a class='mod'
394                                             href='{}index.html'>{}</a>::",
395                                       root.as_slice(),
396                                       seg.name));
397                     }
398                 }
399             }
400             None => {
401                 for seg in path.segments.index(&(0..amt)).iter() {
402                     try!(write!(w, "{}::", seg.name));
403                 }
404             }
405         }
406     }
407
408     match info(&*cache) {
409         // This is a documented path, link to it!
410         Some((ref fqp, shortty)) if abs_root.is_some() => {
411             let mut url = String::from_str(abs_root.unwrap().as_slice());
412             let to_link = &fqp[..(fqp.len() - 1)];
413             for component in to_link.iter() {
414                 url.push_str(component.as_slice());
415                 url.push_str("/");
416             }
417             match shortty {
418                 ItemType::Module => {
419                     url.push_str(fqp.last().unwrap().as_slice());
420                     url.push_str("/index.html");
421                 }
422                 _ => {
423                     url.push_str(shortty.to_static_str());
424                     url.push_str(".");
425                     url.push_str(fqp.last().unwrap().as_slice());
426                     url.push_str(".html");
427                 }
428             }
429
430             try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
431                           shortty, url, fqp.connect("::"), last.name));
432         }
433
434         _ => {
435             try!(write!(w, "{}", last.name));
436         }
437     }
438     try!(write!(w, "{}", generics.as_slice()));
439     Ok(())
440 }
441
442 fn primitive_link(f: &mut fmt::Formatter,
443                   prim: clean::PrimitiveType,
444                   name: &str) -> fmt::Result {
445     let m = cache();
446     let mut needs_termination = false;
447     match m.primitive_locations.get(&prim) {
448         Some(&ast::LOCAL_CRATE) => {
449             let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
450             let len = if len == 0 {0} else {len - 1};
451             try!(write!(f, "<a href='{}primitive.{}.html'>",
452                         repeat("../").take(len).collect::<String>(),
453                         prim.to_url_str()));
454             needs_termination = true;
455         }
456         Some(&cnum) => {
457             let path = &m.paths[ast::DefId {
458                 krate: cnum,
459                 node: ast::CRATE_NODE_ID,
460             }];
461             let loc = match m.extern_locations[cnum] {
462                 render::Remote(ref s) => Some(s.to_string()),
463                 render::Local => {
464                     let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
465                     Some(repeat("../").take(len).collect::<String>())
466                 }
467                 render::Unknown => None,
468             };
469             match loc {
470                 Some(root) => {
471                     try!(write!(f, "<a href='{}{}/primitive.{}.html'>",
472                                 root,
473                                 path.0.first().unwrap(),
474                                 prim.to_url_str()));
475                     needs_termination = true;
476                 }
477                 None => {}
478             }
479         }
480         None => {}
481     }
482     try!(write!(f, "{}", name));
483     if needs_termination {
484         try!(write!(f, "</a>"));
485     }
486     Ok(())
487 }
488
489 /// Helper to render type parameters
490 fn tybounds(w: &mut fmt::Formatter,
491             typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result {
492     match *typarams {
493         Some(ref params) => {
494             for param in params.iter() {
495                 try!(write!(w, " + "));
496                 try!(write!(w, "{}", *param));
497             }
498             Ok(())
499         }
500         None => Ok(())
501     }
502 }
503
504 //NOTE(stage0): remove impl after snapshot
505 #[cfg(stage0)]
506 impl fmt::Show for clean::Type {
507     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
508         fmt::String::fmt(self, f)
509     }
510 }
511
512 impl fmt::String for clean::Type {
513     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
514         match *self {
515             clean::TyParamBinder(id) => {
516                 f.write_str(cache().typarams[ast_util::local_def(id)].as_slice())
517             }
518             clean::Generic(ref name) => {
519                 f.write_str(name.as_slice())
520             }
521             clean::ResolvedPath{ did, ref typarams, ref path } => {
522                 try!(resolved_path(f, did, path, false));
523                 tybounds(f, typarams)
524             }
525             clean::Infer => write!(f, "_"),
526             clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
527             clean::Closure(ref decl) => {
528                 write!(f, "{style}{lifetimes}|{args}|{bounds}{arrow}",
529                        style = UnsafetySpace(decl.unsafety),
530                        lifetimes = if decl.lifetimes.len() == 0 {
531                            "".to_string()
532                        } else {
533                            format!("for &lt;{:#}&gt;", decl.lifetimes)
534                        },
535                        args = decl.decl.inputs,
536                        arrow = decl.decl.output,
537                        bounds = {
538                            let mut ret = String::new();
539                            for bound in decl.bounds.iter() {
540                                 match *bound {
541                                     clean::RegionBound(..) => {}
542                                     clean::TraitBound(ref t, modifier) => {
543                                         if ret.len() == 0 {
544                                             ret.push_str(": ");
545                                         } else {
546                                             ret.push_str(" + ");
547                                         }
548                                         if modifier == ast::TraitBoundModifier::Maybe {
549                                             ret.push_str("?");
550                                         }
551                                         ret.push_str(format!("{}",
552                                                              *t).as_slice());
553                                     }
554                                 }
555                            }
556                            ret
557                        })
558             }
559             clean::Proc(ref decl) => {
560                 write!(f, "{style}{lifetimes}proc({args}){bounds}{arrow}",
561                        style = UnsafetySpace(decl.unsafety),
562                        lifetimes = if decl.lifetimes.len() == 0 {
563                            "".to_string()
564                        } else {
565                            format!("for &lt;{:#}&gt;", decl.lifetimes)
566                        },
567                        args = decl.decl.inputs,
568                        bounds = if decl.bounds.len() == 0 {
569                            "".to_string()
570                        } else {
571                            let m = decl.bounds
572                                            .iter()
573                                            .map(|s| s.to_string());
574                            format!(
575                                ": {}",
576                                m.collect::<Vec<String>>().connect(" + "))
577                        },
578                        arrow = decl.decl.output)
579             }
580             clean::BareFunction(ref decl) => {
581                 write!(f, "{}{}fn{}{}",
582                        UnsafetySpace(decl.unsafety),
583                        match decl.abi.as_slice() {
584                            "" => " extern ".to_string(),
585                            "\"Rust\"" => "".to_string(),
586                            s => format!(" extern {} ", s)
587                        },
588                        decl.generics,
589                        decl.decl)
590             }
591             clean::Tuple(ref typs) => {
592                 primitive_link(f, clean::PrimitiveTuple,
593                                match typs.as_slice() {
594                                     [ref one] => format!("({},)", one),
595                                     many => format!("({:#})", many)
596                                }.as_slice())
597             }
598             clean::Vector(ref t) => {
599                 primitive_link(f, clean::Slice, format!("[{}]", **t).as_slice())
600             }
601             clean::FixedVector(ref t, ref s) => {
602                 primitive_link(f, clean::Slice,
603                                format!("[{}, ..{}]", **t, *s).as_slice())
604             }
605             clean::Bottom => f.write_str("!"),
606             clean::RawPointer(m, ref t) => {
607                 write!(f, "*{}{}", RawMutableSpace(m), **t)
608             }
609             clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
610                 let lt = match *l {
611                     Some(ref l) => format!("{} ", *l),
612                     _ => "".to_string(),
613                 };
614                 let m = MutableSpace(mutability);
615                 match **ty {
616                     clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
617                         match **bt {
618                             clean::Generic(_) =>
619                                 primitive_link(f, clean::Slice,
620                                     format!("&amp;{}{}[{}]", lt, m, **bt).as_slice()),
621                             _ => {
622                                 try!(primitive_link(f, clean::Slice,
623                                     format!("&amp;{}{}[", lt, m).as_slice()));
624                                 try!(write!(f, "{}", **bt));
625                                 primitive_link(f, clean::Slice, "]")
626                             }
627                         }
628                     }
629                     _ => {
630                         write!(f, "&amp;{}{}{}", lt, m, **ty)
631                     }
632                 }
633             }
634             clean::PolyTraitRef(ref bounds) => {
635                 for (i, bound) in bounds.iter().enumerate() {
636                     if i != 0 {
637                         try!(write!(f, " + "));
638                     }
639                     try!(write!(f, "{}", *bound));
640                 }
641                 Ok(())
642             }
643             clean::QPath { ref name, ref self_type, ref trait_ } => {
644                 write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
645             }
646             clean::Unique(..) => {
647                 panic!("should have been cleaned")
648             }
649         }
650     }
651 }
652
653 //NOTE(stage0): remove impl after snapshot
654 #[cfg(stage0)]
655 impl fmt::Show for clean::Arguments {
656     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657         fmt::String::fmt(self, f)
658     }
659 }
660
661
662 impl fmt::String for clean::Arguments {
663     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
664         for (i, input) in self.values.iter().enumerate() {
665             if i > 0 { try!(write!(f, ", ")); }
666             if input.name.len() > 0 {
667                 try!(write!(f, "{}: ", input.name));
668             }
669             try!(write!(f, "{}", input.type_));
670         }
671         Ok(())
672     }
673 }
674
675 //NOTE(stage0): remove impl after snapshot
676 #[cfg(stage0)]
677 impl fmt::Show for clean::FunctionRetTy {
678     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679         fmt::String::fmt(self, f)
680     }
681 }
682
683 impl fmt::String for clean::FunctionRetTy {
684     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
685         match *self {
686             clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
687             clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
688             clean::NoReturn => write!(f, " -&gt; !")
689         }
690     }
691 }
692
693 //NOTE(stage0): remove impl after snapshot
694 #[cfg(stage0)]
695 impl fmt::Show for clean::FnDecl {
696     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
697         fmt::String::fmt(self, f)
698     }
699 }
700
701 impl fmt::String for clean::FnDecl {
702     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
703         write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
704     }
705 }
706
707 //NOTE(stage0): remove impl after snapshot
708 #[cfg(stage0)]
709 impl<'a> fmt::Show for Method<'a> {
710     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
711         fmt::String::fmt(self, f)
712     }
713 }
714
715 impl<'a> fmt::String for Method<'a> {
716     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
717         let Method(selfty, d) = *self;
718         let mut args = String::new();
719         match *selfty {
720             clean::SelfStatic => {},
721             clean::SelfValue => args.push_str("self"),
722             clean::SelfBorrowed(Some(ref lt), mtbl) => {
723                 args.push_str(format!("&amp;{} {}self", *lt,
724                                       MutableSpace(mtbl)).as_slice());
725             }
726             clean::SelfBorrowed(None, mtbl) => {
727                 args.push_str(format!("&amp;{}self",
728                                       MutableSpace(mtbl)).as_slice());
729             }
730             clean::SelfExplicit(ref typ) => {
731                 args.push_str(format!("self: {}", *typ).as_slice());
732             }
733         }
734         for (i, input) in d.inputs.values.iter().enumerate() {
735             if i > 0 || args.len() > 0 { args.push_str(", "); }
736             if input.name.len() > 0 {
737                 args.push_str(format!("{}: ", input.name).as_slice());
738             }
739             args.push_str(format!("{}", input.type_).as_slice());
740         }
741         write!(f, "({args}){arrow}", args = args, arrow = d.output)
742     }
743 }
744
745 //NOTE(stage0): remove impl after snapshot
746 #[cfg(stage0)]
747 impl fmt::Show for VisSpace {
748     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
749         fmt::String::fmt(self, f)
750     }
751 }
752
753 impl fmt::String for VisSpace {
754     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
755         match self.get() {
756             Some(ast::Public) => write!(f, "pub "),
757             Some(ast::Inherited) | None => Ok(())
758         }
759     }
760 }
761
762 //NOTE(stage0): remove impl after snapshot
763 #[cfg(stage0)]
764 impl fmt::Show for UnsafetySpace {
765     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
766         fmt::String::fmt(self, f)
767     }
768 }
769
770 impl fmt::String for UnsafetySpace {
771     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
772         match self.get() {
773             ast::Unsafety::Unsafe => write!(f, "unsafe "),
774             ast::Unsafety::Normal => Ok(())
775         }
776     }
777 }
778
779 //NOTE(stage0): remove impl after snapshot
780 #[cfg(stage0)]
781 impl fmt::Show for clean::ViewPath {
782     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
783         fmt::String::fmt(self, f)
784     }
785 }
786
787 impl fmt::String for clean::ViewPath {
788     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
789         match *self {
790             clean::SimpleImport(ref name, ref src) => {
791                 if *name == src.path.segments.last().unwrap().name {
792                     write!(f, "use {};", *src)
793                 } else {
794                     write!(f, "use {} as {};", *src, *name)
795                 }
796             }
797             clean::GlobImport(ref src) => {
798                 write!(f, "use {}::*;", *src)
799             }
800             clean::ImportList(ref src, ref names) => {
801                 try!(write!(f, "use {}::{{", *src));
802                 for (i, n) in names.iter().enumerate() {
803                     if i > 0 {
804                         try!(write!(f, ", "));
805                     }
806                     try!(write!(f, "{}", *n));
807                 }
808                 write!(f, "}};")
809             }
810         }
811     }
812 }
813
814 //NOTE(stage0): remove impl after snapshot
815 #[cfg(stage0)]
816 impl fmt::Show for clean::ImportSource {
817     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
818         fmt::String::fmt(self, f)
819     }
820 }
821
822 impl fmt::String for clean::ImportSource {
823     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
824         match self.did {
825             Some(did) => resolved_path(f, did, &self.path, true),
826             _ => {
827                 for (i, seg) in self.path.segments.iter().enumerate() {
828                     if i > 0 {
829                         try!(write!(f, "::"))
830                     }
831                     try!(write!(f, "{}", seg.name));
832                 }
833                 Ok(())
834             }
835         }
836     }
837 }
838
839 //NOTE(stage0): remove impl after snapshot
840 #[cfg(stage0)]
841 impl fmt::Show for clean::ViewListIdent {
842     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
843         fmt::String::fmt(self, f)
844     }
845 }
846
847 impl fmt::String for clean::ViewListIdent {
848     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
849         match self.source {
850             Some(did) => {
851                 let path = clean::Path {
852                     global: false,
853                     segments: vec!(clean::PathSegment {
854                         name: self.name.clone(),
855                         params: clean::PathParameters::AngleBracketed {
856                             lifetimes: Vec::new(),
857                             types: Vec::new(),
858                         }
859                     })
860                 };
861                 resolved_path(f, did, &path, false)
862             }
863             _ => write!(f, "{}", self.name),
864         }
865     }
866 }
867
868 //NOTE(stage0): remove impl after snapshot
869 #[cfg(stage0)]
870 impl fmt::Show for MutableSpace {
871     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
872         fmt::String::fmt(self, f)
873     }
874 }
875
876 impl fmt::String for MutableSpace {
877     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
878         match *self {
879             MutableSpace(clean::Immutable) => Ok(()),
880             MutableSpace(clean::Mutable) => write!(f, "mut "),
881         }
882     }
883 }
884
885 //NOTE(stage0): remove impl after snapshot
886 #[cfg(stage0)]
887 impl fmt::Show for RawMutableSpace {
888     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
889         fmt::String::fmt(self, f)
890     }
891 }
892
893 impl fmt::String for RawMutableSpace {
894     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
895         match *self {
896             RawMutableSpace(clean::Immutable) => write!(f, "const "),
897             RawMutableSpace(clean::Mutable) => write!(f, "mut "),
898         }
899     }
900 }
901
902 //NOTE(stage0): remove impl after snapshot
903 #[cfg(stage0)]
904 impl<'a> fmt::Show for Stability<'a> {
905     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
906         fmt::String::fmt(self, f)
907     }
908 }
909
910 impl<'a> fmt::String for Stability<'a> {
911     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
912         let Stability(stab) = *self;
913         match *stab {
914             Some(ref stability) => {
915                 write!(f, "<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
916                        lvl = stability.level,
917                        reason = stability.text)
918             }
919             None => Ok(())
920         }
921     }
922 }
923
924 //NOTE(stage0): remove impl after snapshot
925 #[cfg(stage0)]
926 impl<'a> fmt::Show for ConciseStability<'a> {
927     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
928         fmt::String::fmt(self, f)
929     }
930 }
931
932 impl<'a> fmt::String for ConciseStability<'a> {
933     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
934         let ConciseStability(stab) = *self;
935         match *stab {
936             Some(ref stability) => {
937                 write!(f, "<a class='stability {lvl}' title='{lvl}{colon}{reason}'></a>",
938                        lvl = stability.level,
939                        colon = if stability.text.len() > 0 { ": " } else { "" },
940                        reason = stability.text)
941             }
942             None => {
943                 write!(f, "<a class='stability Unmarked' title='No stability level'></a>")
944             }
945         }
946     }
947 }
948
949 //NOTE(stage0): remove impl after snapshot
950 #[cfg(stage0)]
951 impl fmt::Show for ModuleSummary {
952     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
953         fmt::String::fmt(self, f)
954     }
955 }
956
957 impl fmt::String for ModuleSummary {
958     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
959         fn fmt_inner<'a>(f: &mut fmt::Formatter,
960                          context: &mut Vec<&'a str>,
961                          m: &'a ModuleSummary)
962                      -> fmt::Result {
963             let cnt = m.counts;
964             let tot = cnt.total();
965             if tot == 0 { return Ok(()) }
966
967             context.push(m.name.as_slice());
968             let path = context.connect("::");
969
970             try!(write!(f, "<tr>"));
971             try!(write!(f, "<td><a href='{}'>{}</a></td>", {
972                             let mut url = context.slice_from(1).to_vec();
973                             url.push("index.html");
974                             url.connect("/")
975                         },
976                         path));
977             try!(write!(f, "<td class='summary-column'>"));
978             try!(write!(f, "<span class='summary Stable' \
979                             style='width: {:.4}%; display: inline-block'>&nbsp</span>",
980                         (100 * cnt.stable) as f64/tot as f64));
981             try!(write!(f, "<span class='summary Unstable' \
982                             style='width: {:.4}%; display: inline-block'>&nbsp</span>",
983                         (100 * cnt.unstable) as f64/tot as f64));
984             try!(write!(f, "<span class='summary Experimental' \
985                             style='width: {:.4}%; display: inline-block'>&nbsp</span>",
986                         (100 * cnt.experimental) as f64/tot as f64));
987             try!(write!(f, "<span class='summary Deprecated' \
988                             style='width: {:.4}%; display: inline-block'>&nbsp</span>",
989                         (100 * cnt.deprecated) as f64/tot as f64));
990             try!(write!(f, "<span class='summary Unmarked' \
991                             style='width: {:.4}%; display: inline-block'>&nbsp</span>",
992                         (100 * cnt.unmarked) as f64/tot as f64));
993             try!(write!(f, "</td></tr>"));
994
995             for submodule in m.submodules.iter() {
996                 try!(fmt_inner(f, context, submodule));
997             }
998             context.pop();
999             Ok(())
1000         }
1001
1002         let mut context = Vec::new();
1003
1004         let tot = self.counts.total();
1005         let (stable, unstable, experimental, deprecated, unmarked) = if tot == 0 {
1006             (0, 0, 0, 0, 0)
1007         } else {
1008             ((100 * self.counts.stable)/tot,
1009              (100 * self.counts.unstable)/tot,
1010              (100 * self.counts.experimental)/tot,
1011              (100 * self.counts.deprecated)/tot,
1012              (100 * self.counts.unmarked)/tot)
1013         };
1014
1015         try!(write!(f,
1016 r"<h1 class='fqn'>Stability dashboard: crate <a class='mod' href='index.html'>{name}</a></h1>
1017 This dashboard summarizes the stability levels for all of the public modules of
1018 the crate, according to the total number of items at each level in the module and
1019 its children (percentages total for {name}):
1020 <blockquote>
1021 <a class='stability Stable'></a> stable ({}%),<br/>
1022 <a class='stability Unstable'></a> unstable ({}%),<br/>
1023 <a class='stability Experimental'></a> experimental ({}%),<br/>
1024 <a class='stability Deprecated'></a> deprecated ({}%),<br/>
1025 <a class='stability Unmarked'></a> unmarked ({}%)
1026 </blockquote>
1027 The counts do not include methods or trait
1028 implementations that are visible only through a re-exported type.",
1029 stable, unstable, experimental, deprecated, unmarked,
1030 name=self.name));
1031         try!(write!(f, "<table>"));
1032         try!(fmt_inner(f, &mut context, self));
1033         write!(f, "</table>")
1034     }
1035 }