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.
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.
11 //! HTML formatting module
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.
19 use std::iter::repeat;
25 use stability_summary::ModuleSummary;
26 use html::item_type::ItemType;
28 use html::render::{cache, CURRENT_LOCATION_KEY};
30 /// Helper to render an optional visibility with a space after it (if the
31 /// visibility is preset)
33 pub struct VisSpace(pub Option<ast::Visibility>);
34 /// Similarly to VisSpace, this structure is used to render a function style with a
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
42 pub struct MutableSpace(pub clean::Mutability);
43 /// Similar to VisSpace, but used for mutability
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]);
56 pub fn get(&self) -> Option<ast::Visibility> {
57 let VisSpace(v) = *self; v
62 pub fn get(&self) -> ast::Unsafety {
63 let UnsafetySpace(v) = *self; v
67 //NOTE(stage0): remove impl after snapshot
69 impl<'a> fmt::Show for TyParamBounds<'a> {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 fmt::String::fmt(self, f)
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() {
80 try!(f.write_str(" + "));
82 try!(write!(f, "{}", *bound));
88 //NOTE(stage0): remove impl after snapshot
90 impl fmt::Show for clean::Generic {
91 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
92 fmt::String::fmt(self, f)
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("<"));
101 for (i, life) in self.lifetimes.iter().enumerate() {
103 try!(f.write_str(", "));
105 try!(write!(f, "{}", *life));
108 if self.type_params.len() > 0 {
109 if self.lifetimes.len() > 0 {
110 try!(f.write_str(", "));
112 for (i, tp) in self.type_params.iter().enumerate() {
114 try!(f.write_str(", "))
116 try!(f.write_str(tp.name.as_slice()));
118 if tp.bounds.len() > 0 {
119 try!(write!(f, ": {}", TyParamBounds(tp.bounds.as_slice())));
123 Some(ref ty) => { try!(write!(f, " = {}", ty)); },
128 try!(f.write_str(">"));
133 //NOTE(stage0): remove impl after snapshot
135 impl<'a> fmt::Show for WhereClause<'a> {
136 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137 fmt::String::fmt(self, f)
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 {
147 try!(f.write_str(" <span class='where'>where "));
148 for (i, pred) in gens.where_predicates.iter().enumerate() {
150 try!(f.write_str(", "));
153 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
154 let bounds = bounds.as_slice();
155 try!(write!(f, "{}: {}", ty, TyParamBounds(bounds)));
157 &clean::WherePredicate::RegionPredicate { ref lifetime,
159 try!(write!(f, "{}: ", lifetime));
160 for (i, lifetime) in bounds.iter().enumerate() {
162 try!(f.write_str(" + "));
165 try!(write!(f, "{}", lifetime));
168 &clean::WherePredicate::EqPredicate => {
173 try!(f.write_str("</span>"));
178 //NOTE(stage0): remove impl after snapshot
180 impl fmt::Show for clean::Lifetime {
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 fmt::String::fmt(self, f)
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()));
193 //NOTE(stage0): remove impl after snapshot
195 impl fmt::Show for clean::PolyTrait {
196 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197 fmt::String::fmt(self, f)
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<"));
205 for (i, lt) in self.lifetimes.iter().enumerate() {
207 try!(f.write_str(", "));
209 try!(write!(f, "{}", lt));
211 try!(f.write_str("> "));
213 write!(f, "{}", self.trait_)
217 //NOTE(stage0): remove impl after snapshot
219 impl fmt::Show for clean::TyParamBound {
220 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221 fmt::String::fmt(self, f)
225 impl fmt::String for clean::TyParamBound {
226 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
228 clean::RegionBound(ref lt) => {
231 clean::TraitBound(ref ty, modifier) => {
232 let modifier_str = match modifier {
233 ast::TraitBoundModifier::None => "",
234 ast::TraitBoundModifier::Maybe => "?",
236 write!(f, "{}{}", modifier_str, *ty)
242 //NOTE(stage0): remove impl after snapshot
244 impl fmt::Show for clean::PathParameters {
245 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
246 fmt::String::fmt(self, f)
250 impl fmt::String for clean::PathParameters {
251 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253 clean::PathParameters::AngleBracketed { ref lifetimes, ref types } => {
254 if lifetimes.len() > 0 || types.len() > 0 {
255 try!(f.write_str("<"));
256 let mut comma = false;
257 for lifetime in lifetimes.iter() {
259 try!(f.write_str(", "));
262 try!(write!(f, "{}", *lifetime));
264 for ty in types.iter() {
266 try!(f.write_str(", "));
269 try!(write!(f, "{}", *ty));
271 try!(f.write_str(">"));
274 clean::PathParameters::Parenthesized { ref inputs, ref output } => {
275 try!(f.write_str("("));
276 let mut comma = false;
277 for ty in inputs.iter() {
279 try!(f.write_str(", "));
282 try!(write!(f, "{}", *ty));
284 try!(f.write_str(")"));
285 if let Some(ref ty) = *output {
286 try!(f.write_str(" -> "));
287 try!(write!(f, "{}", ty));
295 //NOTE(stage0): remove impl after snapshot
297 impl fmt::Show for clean::PathSegment {
298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299 fmt::String::fmt(self, f)
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)
310 //NOTE(stage0): remove impl after snapshot
312 impl fmt::Show for clean::Path {
313 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
314 fmt::String::fmt(self, f)
318 impl fmt::String for clean::Path {
319 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
321 try!(f.write_str("::"))
324 for (i, seg) in self.segments.iter().enumerate() {
326 try!(f.write_str("::"))
328 try!(write!(f, "{}", seg));
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,
340 if ast_util::is_local(did) || cache.inlined.contains(&did) {
341 Some(repeat("../").take(loc.len()).collect::<String>())
343 match cache.extern_locations[did.krate] {
344 render::Remote(ref s) => Some(s.to_string()),
346 Some(repeat("../").take(loc.len()).collect::<String>())
348 render::Unknown => None,
353 match cache.paths.get(&did) {
355 Some(&(ref fqp, shortty)) => Some((fqp.clone(), shortty))
360 fn path<F, G>(w: &mut fmt::Formatter,
366 F: FnOnce(&render::Cache, &[String]) -> Option<String>,
367 G: FnOnce(&render::Cache) -> Option<(Vec<String>, ItemType)>,
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);
373 let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
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()),
382 let amt = path.segments.len() - 1;
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 ||
389 try!(write!(w, "{}::", seg.name));
391 root.push_str(seg.name.as_slice());
393 try!(write!(w, "<a class='mod'
394 href='{}index.html'>{}</a>::",
401 for seg in path.segments.index(&(0..amt)).iter() {
402 try!(write!(w, "{}::", seg.name));
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());
418 ItemType::Module => {
419 url.push_str(fqp.last().unwrap().as_slice());
420 url.push_str("/index.html");
423 url.push_str(shortty.to_static_str());
425 url.push_str(fqp.last().unwrap().as_slice());
426 url.push_str(".html");
430 try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
431 shortty, url, fqp.connect("::"), last.name));
435 try!(write!(w, "{}", last.name));
438 try!(write!(w, "{}", generics.as_slice()));
442 fn primitive_link(f: &mut fmt::Formatter,
443 prim: clean::PrimitiveType,
444 name: &str) -> fmt::Result {
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>(),
454 needs_termination = true;
457 let path = &m.paths[ast::DefId {
459 node: ast::CRATE_NODE_ID,
461 let loc = match m.extern_locations[cnum] {
462 render::Remote(ref s) => Some(s.to_string()),
464 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
465 Some(repeat("../").take(len).collect::<String>())
467 render::Unknown => None,
471 try!(write!(f, "<a href='{}{}/primitive.{}.html'>",
473 path.0.first().unwrap(),
475 needs_termination = true;
482 try!(write!(f, "{}", name));
483 if needs_termination {
484 try!(write!(f, "</a>"));
489 /// Helper to render type parameters
490 fn tybounds(w: &mut fmt::Formatter,
491 typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result {
493 Some(ref params) => {
494 for param in params.iter() {
495 try!(write!(w, " + "));
496 try!(write!(w, "{}", *param));
504 //NOTE(stage0): remove impl after snapshot
506 impl fmt::Show for clean::Type {
507 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
508 fmt::String::fmt(self, f)
512 impl fmt::String for clean::Type {
513 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
515 clean::TyParamBinder(id) => {
516 f.write_str(cache().typarams[ast_util::local_def(id)].as_slice())
518 clean::Generic(ref name) => {
519 f.write_str(name.as_slice())
521 clean::ResolvedPath{ did, ref typarams, ref path } => {
522 try!(resolved_path(f, did, path, false));
523 tybounds(f, typarams)
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 {
533 format!("for <{:#}>", decl.lifetimes)
535 args = decl.decl.inputs,
536 arrow = decl.decl.output,
538 let mut ret = String::new();
539 for bound in decl.bounds.iter() {
541 clean::RegionBound(..) => {}
542 clean::TraitBound(ref t, modifier) => {
548 if modifier == ast::TraitBoundModifier::Maybe {
551 ret.push_str(format!("{}",
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 {
565 format!("for <{:#}>", decl.lifetimes)
567 args = decl.decl.inputs,
568 bounds = if decl.bounds.len() == 0 {
573 .map(|s| s.to_string());
576 m.collect::<Vec<String>>().connect(" + "))
578 arrow = decl.decl.output)
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)
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)
598 clean::Vector(ref t) => {
599 primitive_link(f, clean::Slice, format!("[{}]", **t).as_slice())
601 clean::FixedVector(ref t, ref s) => {
602 primitive_link(f, clean::Slice,
603 format!("[{}, ..{}]", **t, *s).as_slice())
605 clean::Bottom => f.write_str("!"),
606 clean::RawPointer(m, ref t) => {
607 write!(f, "*{}{}", RawMutableSpace(m), **t)
609 clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
611 Some(ref l) => format!("{} ", *l),
614 let m = MutableSpace(mutability);
616 clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
619 primitive_link(f, clean::Slice,
620 format!("&{}{}[{}]", lt, m, **bt).as_slice()),
622 try!(primitive_link(f, clean::Slice,
623 format!("&{}{}[", lt, m).as_slice()));
624 try!(write!(f, "{}", **bt));
625 primitive_link(f, clean::Slice, "]")
630 write!(f, "&{}{}{}", lt, m, **ty)
634 clean::PolyTraitRef(ref bounds) => {
635 for (i, bound) in bounds.iter().enumerate() {
637 try!(write!(f, " + "));
639 try!(write!(f, "{}", *bound));
643 clean::QPath { ref name, ref self_type, ref trait_ } => {
644 write!(f, "<{} as {}>::{}", self_type, trait_, name)
646 clean::Unique(..) => {
647 panic!("should have been cleaned")
653 //NOTE(stage0): remove impl after snapshot
655 impl fmt::Show for clean::Arguments {
656 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657 fmt::String::fmt(self, f)
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));
669 try!(write!(f, "{}", input.type_));
675 //NOTE(stage0): remove impl after snapshot
677 impl fmt::Show for clean::FunctionRetTy {
678 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
679 fmt::String::fmt(self, f)
683 impl fmt::String for clean::FunctionRetTy {
684 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
686 clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
687 clean::Return(ref ty) => write!(f, " -> {}", ty),
688 clean::NoReturn => write!(f, " -> !")
693 //NOTE(stage0): remove impl after snapshot
695 impl fmt::Show for clean::FnDecl {
696 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
697 fmt::String::fmt(self, f)
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)
707 //NOTE(stage0): remove impl after snapshot
709 impl<'a> fmt::Show for Method<'a> {
710 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
711 fmt::String::fmt(self, f)
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();
720 clean::SelfStatic => {},
721 clean::SelfValue => args.push_str("self"),
722 clean::SelfBorrowed(Some(ref lt), mtbl) => {
723 args.push_str(format!("&{} {}self", *lt,
724 MutableSpace(mtbl)).as_slice());
726 clean::SelfBorrowed(None, mtbl) => {
727 args.push_str(format!("&{}self",
728 MutableSpace(mtbl)).as_slice());
730 clean::SelfExplicit(ref typ) => {
731 args.push_str(format!("self: {}", *typ).as_slice());
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());
739 args.push_str(format!("{}", input.type_).as_slice());
741 write!(f, "({args}){arrow}", args = args, arrow = d.output)
745 //NOTE(stage0): remove impl after snapshot
747 impl fmt::Show for VisSpace {
748 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
749 fmt::String::fmt(self, f)
753 impl fmt::String for VisSpace {
754 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
756 Some(ast::Public) => write!(f, "pub "),
757 Some(ast::Inherited) | None => Ok(())
762 //NOTE(stage0): remove impl after snapshot
764 impl fmt::Show for UnsafetySpace {
765 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
766 fmt::String::fmt(self, f)
770 impl fmt::String for UnsafetySpace {
771 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
773 ast::Unsafety::Unsafe => write!(f, "unsafe "),
774 ast::Unsafety::Normal => Ok(())
779 //NOTE(stage0): remove impl after snapshot
781 impl fmt::Show for clean::ViewPath {
782 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
783 fmt::String::fmt(self, f)
787 impl fmt::String for clean::ViewPath {
788 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
790 clean::SimpleImport(ref name, ref src) => {
791 if *name == src.path.segments.last().unwrap().name {
792 write!(f, "use {};", *src)
794 write!(f, "use {} as {};", *src, *name)
797 clean::GlobImport(ref src) => {
798 write!(f, "use {}::*;", *src)
800 clean::ImportList(ref src, ref names) => {
801 try!(write!(f, "use {}::{{", *src));
802 for (i, n) in names.iter().enumerate() {
804 try!(write!(f, ", "));
806 try!(write!(f, "{}", *n));
814 //NOTE(stage0): remove impl after snapshot
816 impl fmt::Show for clean::ImportSource {
817 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
818 fmt::String::fmt(self, f)
822 impl fmt::String for clean::ImportSource {
823 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
825 Some(did) => resolved_path(f, did, &self.path, true),
827 for (i, seg) in self.path.segments.iter().enumerate() {
829 try!(write!(f, "::"))
831 try!(write!(f, "{}", seg.name));
839 //NOTE(stage0): remove impl after snapshot
841 impl fmt::Show for clean::ViewListIdent {
842 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
843 fmt::String::fmt(self, f)
847 impl fmt::String for clean::ViewListIdent {
848 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
851 let path = clean::Path {
853 segments: vec!(clean::PathSegment {
854 name: self.name.clone(),
855 params: clean::PathParameters::AngleBracketed {
856 lifetimes: Vec::new(),
861 resolved_path(f, did, &path, false)
863 _ => write!(f, "{}", self.name),
868 //NOTE(stage0): remove impl after snapshot
870 impl fmt::Show for MutableSpace {
871 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
872 fmt::String::fmt(self, f)
876 impl fmt::String for MutableSpace {
877 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
879 MutableSpace(clean::Immutable) => Ok(()),
880 MutableSpace(clean::Mutable) => write!(f, "mut "),
885 //NOTE(stage0): remove impl after snapshot
887 impl fmt::Show for RawMutableSpace {
888 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
889 fmt::String::fmt(self, f)
893 impl fmt::String for RawMutableSpace {
894 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
896 RawMutableSpace(clean::Immutable) => write!(f, "const "),
897 RawMutableSpace(clean::Mutable) => write!(f, "mut "),
902 //NOTE(stage0): remove impl after snapshot
904 impl<'a> fmt::Show for Stability<'a> {
905 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
906 fmt::String::fmt(self, f)
910 impl<'a> fmt::String for Stability<'a> {
911 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
912 let Stability(stab) = *self;
914 Some(ref stability) => {
915 write!(f, "<a class='stability {lvl}' title='{reason}'>{lvl}</a>",
916 lvl = stability.level,
917 reason = stability.text)
924 //NOTE(stage0): remove impl after snapshot
926 impl<'a> fmt::Show for ConciseStability<'a> {
927 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
928 fmt::String::fmt(self, f)
932 impl<'a> fmt::String for ConciseStability<'a> {
933 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
934 let ConciseStability(stab) = *self;
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)
943 write!(f, "<a class='stability Unmarked' title='No stability level'></a>")
949 //NOTE(stage0): remove impl after snapshot
951 impl fmt::Show for ModuleSummary {
952 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
953 fmt::String::fmt(self, f)
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)
964 let tot = cnt.total();
965 if tot == 0 { return Ok(()) }
967 context.push(m.name.as_slice());
968 let path = context.connect("::");
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");
977 try!(write!(f, "<td class='summary-column'>"));
978 try!(write!(f, "<span class='summary Stable' \
979 style='width: {:.4}%; display: inline-block'> </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'> </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'> </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'> </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'> </span>",
992 (100 * cnt.unmarked) as f64/tot as f64));
993 try!(write!(f, "</td></tr>"));
995 for submodule in m.submodules.iter() {
996 try!(fmt_inner(f, context, submodule));
1002 let mut context = Vec::new();
1004 let tot = self.counts.total();
1005 let (stable, unstable, experimental, deprecated, unmarked) = if tot == 0 {
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)
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}):
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 ({}%)
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,
1031 try!(write!(f, "<table>"));
1032 try!(fmt_inner(f, &mut context, self));
1033 write!(f, "</table>")