]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/format.rs
Don't display full blanket implementation and put it into its own section
[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::Display` 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 rustc::hir::def_id::DefId;
22 use rustc_target::spec::abi::Abi;
23 use rustc::hir;
24
25 use clean::{self, PrimitiveType};
26 use core::DocAccessLevels;
27 use html::item_type::ItemType;
28 use html::render::{self, 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, Clone)]
33 pub struct VisSpace<'a>(pub &'a Option<clean::Visibility>);
34 /// Similarly to VisSpace, this structure is used to render a function style with a
35 /// space after it.
36 #[derive(Copy, Clone)]
37 pub struct UnsafetySpace(pub hir::Unsafety);
38 /// Similarly to VisSpace, this structure is used to render a function constness
39 /// with a space after it.
40 #[derive(Copy, Clone)]
41 pub struct ConstnessSpace(pub hir::Constness);
42 /// Similarly to VisSpace, this structure is used to render a function asyncness
43 /// with a space after it.
44 #[derive(Copy, Clone)]
45 pub struct AsyncSpace(pub hir::IsAsync);
46 /// Similar to VisSpace, but used for mutability
47 #[derive(Copy, Clone)]
48 pub struct MutableSpace(pub clean::Mutability);
49 /// Similar to VisSpace, but used for mutability
50 #[derive(Copy, Clone)]
51 pub struct RawMutableSpace(pub clean::Mutability);
52 /// Wrapper struct for emitting type parameter bounds.
53 pub struct GenericBounds<'a>(pub &'a [clean::GenericBound]);
54 /// Wrapper struct for emitting a comma-separated list of items
55 pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
56 pub struct AbiSpace(pub Abi);
57
58 /// Wrapper struct for properly emitting a method declaration.
59 pub struct Method<'a> {
60     /// The declaration to emit.
61     pub decl: &'a clean::FnDecl,
62     /// The length of the function's "name", used to determine line-wrapping.
63     pub name_len: usize,
64     /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
65     pub indent: usize,
66 }
67
68 /// Wrapper struct for emitting a where clause from Generics.
69 pub struct WhereClause<'a>{
70     /// The Generics from which to emit a where clause.
71     pub gens: &'a clean::Generics,
72     /// The number of spaces to indent each line with.
73     pub indent: usize,
74     /// Whether the where clause needs to add a comma and newline after the last bound.
75     pub end_newline: bool,
76 }
77
78 pub struct HRef<'a> {
79     pub did: DefId,
80     pub text: &'a str,
81 }
82
83 impl<'a> VisSpace<'a> {
84     pub fn get(self) -> &'a Option<clean::Visibility> {
85         let VisSpace(v) = self; v
86     }
87 }
88
89 impl UnsafetySpace {
90     pub fn get(&self) -> hir::Unsafety {
91         let UnsafetySpace(v) = *self; v
92     }
93 }
94
95 impl ConstnessSpace {
96     pub fn get(&self) -> hir::Constness {
97         let ConstnessSpace(v) = *self; v
98     }
99 }
100
101 impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
102     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
103         for (i, item) in self.0.iter().enumerate() {
104             if i != 0 { write!(f, ", ")?; }
105             fmt::Display::fmt(item, f)?;
106         }
107         Ok(())
108     }
109 }
110
111 impl<'a> fmt::Display for GenericBounds<'a> {
112     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
113         let &GenericBounds(bounds) = self;
114         for (i, bound) in bounds.iter().enumerate() {
115             if i > 0 {
116                 f.write_str(" + ")?;
117             }
118             fmt::Display::fmt(bound, f)?;
119         }
120         Ok(())
121     }
122 }
123
124 impl fmt::Display for clean::GenericParamDef {
125     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126         match self.kind {
127             clean::GenericParamDefKind::Lifetime => write!(f, "{}", self.name),
128             clean::GenericParamDefKind::Type { ref bounds, ref default, .. } => {
129                 f.write_str(&self.name)?;
130
131                 if !bounds.is_empty() {
132                     if f.alternate() {
133                         write!(f, ": {:#}", GenericBounds(bounds))?;
134                     } else {
135                         write!(f, ":&nbsp;{}", GenericBounds(bounds))?;
136                     }
137                 }
138
139                 if let Some(ref ty) = default {
140                     if f.alternate() {
141                         write!(f, " = {:#}", ty)?;
142                     } else {
143                         write!(f, "&nbsp;=&nbsp;{}", ty)?;
144                     }
145                 }
146
147                 Ok(())
148             }
149         }
150     }
151 }
152
153 impl fmt::Display for clean::Generics {
154     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
155         let real_params = self.params
156             .iter()
157             .filter(|p| !p.is_synthetic_type_param())
158             .collect::<Vec<_>>();
159         if real_params.is_empty() {
160             return Ok(());
161         }
162         if f.alternate() {
163             write!(f, "<{:#}>", CommaSep(&real_params))
164         } else {
165             write!(f, "&lt;{}&gt;", CommaSep(&real_params))
166         }
167     }
168 }
169
170 impl<'a> fmt::Display for WhereClause<'a> {
171     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
172         let &WhereClause { gens, indent, end_newline } = self;
173         if gens.where_predicates.is_empty() {
174             return Ok(());
175         }
176         let mut clause = String::new();
177         if f.alternate() {
178             clause.push_str(" where");
179         } else {
180             if end_newline {
181                 clause.push_str(" <span class=\"where fmt-newline\">where");
182             } else {
183                 clause.push_str(" <span class=\"where\">where");
184             }
185         }
186         for (i, pred) in gens.where_predicates.iter().enumerate() {
187             if f.alternate() {
188                 clause.push(' ');
189             } else {
190                 clause.push_str("<br>");
191             }
192
193             match pred {
194                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
195                     let bounds = bounds;
196                     if f.alternate() {
197                         clause.push_str(&format!("{:#}: {:#}", ty, GenericBounds(bounds)));
198                     } else {
199                         clause.push_str(&format!("{}: {}", ty, GenericBounds(bounds)));
200                     }
201                 }
202                 &clean::WherePredicate::RegionPredicate { ref lifetime,
203                                                           ref bounds } => {
204                     clause.push_str(&format!("{}: ", lifetime));
205                     for (i, lifetime) in bounds.iter().enumerate() {
206                         if i > 0 {
207                             clause.push_str(" + ");
208                         }
209
210                         clause.push_str(&format!("{}", lifetime));
211                     }
212                 }
213                 &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
214                     if f.alternate() {
215                         clause.push_str(&format!("{:#} == {:#}", lhs, rhs));
216                     } else {
217                         clause.push_str(&format!("{} == {}", lhs, rhs));
218                     }
219                 }
220             }
221
222             if i < gens.where_predicates.len() - 1 || end_newline {
223                 clause.push(',');
224             }
225         }
226
227         if end_newline {
228             // add a space so stripping <br> tags and breaking spaces still renders properly
229             if f.alternate() {
230                 clause.push(' ');
231             } else {
232                 clause.push_str("&nbsp;");
233             }
234         }
235
236         if !f.alternate() {
237             clause.push_str("</span>");
238             let padding = repeat("&nbsp;").take(indent + 4).collect::<String>();
239             clause = clause.replace("<br>", &format!("<br>{}", padding));
240             clause.insert_str(0, &repeat("&nbsp;").take(indent.saturating_sub(1))
241                                                   .collect::<String>());
242             if !end_newline {
243                 clause.insert_str(0, "<br>");
244             }
245         }
246         write!(f, "{}", clause)
247     }
248 }
249
250 impl fmt::Display for clean::Lifetime {
251     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252         f.write_str(self.get_ref())?;
253         Ok(())
254     }
255 }
256
257 impl fmt::Display for clean::PolyTrait {
258     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
259         if !self.generic_params.is_empty() {
260             if f.alternate() {
261                 write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?;
262             } else {
263                 write!(f, "for&lt;{}&gt; ", CommaSep(&self.generic_params))?;
264             }
265         }
266         if f.alternate() {
267             write!(f, "{:#}", self.trait_)
268         } else {
269             write!(f, "{}", self.trait_)
270         }
271     }
272 }
273
274 impl fmt::Display for clean::GenericBound {
275     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276         match *self {
277             clean::GenericBound::Outlives(ref lt) => {
278                 write!(f, "{}", *lt)
279             }
280             clean::GenericBound::TraitBound(ref ty, modifier) => {
281                 let modifier_str = match modifier {
282                     hir::TraitBoundModifier::None => "",
283                     hir::TraitBoundModifier::Maybe => "?",
284                 };
285                 if f.alternate() {
286                     write!(f, "{}{:#}", modifier_str, *ty)
287                 } else {
288                     write!(f, "{}{}", modifier_str, *ty)
289                 }
290             }
291         }
292     }
293 }
294
295 impl fmt::Display for clean::GenericArgs {
296     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
297         match *self {
298             clean::GenericArgs::AngleBracketed {
299                 ref lifetimes, ref types, ref bindings
300             } => {
301                 if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
302                     if f.alternate() {
303                         f.write_str("<")?;
304                     } else {
305                         f.write_str("&lt;")?;
306                     }
307                     let mut comma = false;
308                     for lifetime in lifetimes {
309                         if comma {
310                             f.write_str(", ")?;
311                         }
312                         comma = true;
313                         write!(f, "{}", *lifetime)?;
314                     }
315                     for ty in types {
316                         if comma {
317                             f.write_str(", ")?;
318                         }
319                         comma = true;
320                         if f.alternate() {
321                             write!(f, "{:#}", *ty)?;
322                         } else {
323                             write!(f, "{}", *ty)?;
324                         }
325                     }
326                     for binding in bindings {
327                         if comma {
328                             f.write_str(", ")?;
329                         }
330                         comma = true;
331                         if f.alternate() {
332                             write!(f, "{:#}", *binding)?;
333                         } else {
334                             write!(f, "{}", *binding)?;
335                         }
336                     }
337                     if f.alternate() {
338                         f.write_str(">")?;
339                     } else {
340                         f.write_str("&gt;")?;
341                     }
342                 }
343             }
344             clean::GenericArgs::Parenthesized { ref inputs, ref output } => {
345                 f.write_str("(")?;
346                 let mut comma = false;
347                 for ty in inputs {
348                     if comma {
349                         f.write_str(", ")?;
350                     }
351                     comma = true;
352                     if f.alternate() {
353                         write!(f, "{:#}", *ty)?;
354                     } else {
355                         write!(f, "{}", *ty)?;
356                     }
357                 }
358                 f.write_str(")")?;
359                 if let Some(ref ty) = *output {
360                     if f.alternate() {
361                         write!(f, " -> {:#}", ty)?;
362                     } else {
363                         write!(f, " -&gt; {}", ty)?;
364                     }
365                 }
366             }
367         }
368         Ok(())
369     }
370 }
371
372 impl fmt::Display for clean::PathSegment {
373     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
374         f.write_str(&self.name)?;
375         if f.alternate() {
376             write!(f, "{:#}", self.args)
377         } else {
378             write!(f, "{}", self.args)
379         }
380     }
381 }
382
383 impl fmt::Display for clean::Path {
384     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
385         if self.global {
386             f.write_str("::")?
387         }
388
389         for (i, seg) in self.segments.iter().enumerate() {
390             if i > 0 {
391                 f.write_str("::")?
392             }
393             if f.alternate() {
394                 write!(f, "{:#}", seg)?;
395             } else {
396                 write!(f, "{}", seg)?;
397             }
398         }
399         Ok(())
400     }
401 }
402
403 pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
404     let cache = cache();
405     if !did.is_local() && !cache.access_levels.is_doc_reachable(did) {
406         return None
407     }
408
409     let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
410     let (fqp, shortty, mut url) = match cache.paths.get(&did) {
411         Some(&(ref fqp, shortty)) => {
412             (fqp, shortty, repeat("../").take(loc.len()).collect())
413         }
414         None => {
415             let &(ref fqp, shortty) = cache.external_paths.get(&did)?;
416             (fqp, shortty, match cache.extern_locations[&did.krate] {
417                 (.., render::Remote(ref s)) => s.to_string(),
418                 (.., render::Local) => repeat("../").take(loc.len()).collect(),
419                 (.., render::Unknown) => return None,
420             })
421         }
422     };
423     for component in &fqp[..fqp.len() - 1] {
424         url.push_str(component);
425         url.push_str("/");
426     }
427     match shortty {
428         ItemType::Module => {
429             url.push_str(fqp.last().unwrap());
430             url.push_str("/index.html");
431         }
432         _ => {
433             url.push_str(shortty.css_class());
434             url.push_str(".");
435             url.push_str(fqp.last().unwrap());
436             url.push_str(".html");
437         }
438     }
439     Some((url, shortty, fqp.to_vec()))
440 }
441
442 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
443 /// rendering function with the necessary arguments for linking to a local path.
444 fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
445                  print_all: bool, use_absolute: bool) -> fmt::Result {
446     let last = path.segments.last().unwrap();
447
448     if print_all {
449         for seg in &path.segments[..path.segments.len() - 1] {
450             write!(w, "{}::", seg.name)?;
451         }
452     }
453     if w.alternate() {
454         write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.args)?;
455     } else {
456         let path = if use_absolute {
457             match href(did) {
458                 Some((_, _, fqp)) => {
459                     format!("{}::{}",
460                             fqp[..fqp.len() - 1].join("::"),
461                             HRef::new(did, fqp.last().unwrap()))
462                 }
463                 None => format!("{}", HRef::new(did, &last.name)),
464             }
465         } else {
466             format!("{}", HRef::new(did, &last.name))
467         };
468         write!(w, "{}{}", path, last.args)?;
469     }
470     Ok(())
471 }
472
473 fn primitive_link(f: &mut fmt::Formatter,
474                   prim: clean::PrimitiveType,
475                   name: &str) -> fmt::Result {
476     let m = cache();
477     let mut needs_termination = false;
478     if !f.alternate() {
479         match m.primitive_locations.get(&prim) {
480             Some(&def_id) if def_id.is_local() => {
481                 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
482                 let len = if len == 0 {0} else {len - 1};
483                 write!(f, "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
484                        repeat("../").take(len).collect::<String>(),
485                        prim.to_url_str())?;
486                 needs_termination = true;
487             }
488             Some(&def_id) => {
489                 let loc = match m.extern_locations[&def_id.krate] {
490                     (ref cname, _, render::Remote(ref s)) => {
491                         Some((cname, s.to_string()))
492                     }
493                     (ref cname, _, render::Local) => {
494                         let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
495                         Some((cname, repeat("../").take(len).collect::<String>()))
496                     }
497                     (.., render::Unknown) => None,
498                 };
499                 if let Some((cname, root)) = loc {
500                     write!(f, "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
501                            root,
502                            cname,
503                            prim.to_url_str())?;
504                     needs_termination = true;
505                 }
506             }
507             None => {}
508         }
509     }
510     write!(f, "{}", name)?;
511     if needs_termination {
512         write!(f, "</a>")?;
513     }
514     Ok(())
515 }
516
517 /// Helper to render type parameters
518 fn tybounds(w: &mut fmt::Formatter,
519             typarams: &Option<Vec<clean::GenericBound>>) -> fmt::Result {
520     match *typarams {
521         Some(ref params) => {
522             for param in params {
523                 write!(w, " + ")?;
524                 fmt::Display::fmt(param, w)?;
525             }
526             Ok(())
527         }
528         None => Ok(())
529     }
530 }
531
532 impl<'a> HRef<'a> {
533     pub fn new(did: DefId, text: &'a str) -> HRef<'a> {
534         HRef { did: did, text: text }
535     }
536 }
537
538 impl<'a> fmt::Display for HRef<'a> {
539     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
540         match href(self.did) {
541             Some((url, shortty, fqp)) => if !f.alternate() {
542                 write!(f, "<a class=\"{}\" href=\"{}\" title=\"{} {}\">{}</a>",
543                        shortty, url, shortty, fqp.join("::"), self.text)
544             } else {
545                 write!(f, "{}", self.text)
546             },
547             _ => write!(f, "{}", self.text),
548         }
549     }
550 }
551
552 fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt::Result {
553     match *t {
554         clean::Generic(ref name) => {
555             f.write_str(name)
556         }
557         clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
558             // Paths like T::Output and Self::Output should be rendered with all segments
559             resolved_path(f, did, path, is_generic, use_absolute)?;
560             tybounds(f, typarams)
561         }
562         clean::Infer => write!(f, "_"),
563         clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
564         clean::BareFunction(ref decl) => {
565             if f.alternate() {
566                 write!(f, "{}{:#}fn{:#}{:#}",
567                        UnsafetySpace(decl.unsafety),
568                        AbiSpace(decl.abi),
569                        CommaSep(&decl.generic_params),
570                        decl.decl)
571             } else {
572                 write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
573                 primitive_link(f, PrimitiveType::Fn, "fn")?;
574                 write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl)
575             }
576         }
577         clean::Tuple(ref typs) => {
578             match &typs[..] {
579                 &[] => primitive_link(f, PrimitiveType::Unit, "()"),
580                 &[ref one] => {
581                     primitive_link(f, PrimitiveType::Tuple, "(")?;
582                     //carry f.alternate() into this display w/o branching manually
583                     fmt::Display::fmt(one, f)?;
584                     primitive_link(f, PrimitiveType::Tuple, ",)")
585                 }
586                 many => {
587                     primitive_link(f, PrimitiveType::Tuple, "(")?;
588                     fmt::Display::fmt(&CommaSep(many), f)?;
589                     primitive_link(f, PrimitiveType::Tuple, ")")
590                 }
591             }
592         }
593         clean::Slice(ref t) => {
594             primitive_link(f, PrimitiveType::Slice, "[")?;
595             fmt::Display::fmt(t, f)?;
596             primitive_link(f, PrimitiveType::Slice, "]")
597         }
598         clean::Array(ref t, ref n) => {
599             primitive_link(f, PrimitiveType::Array, "[")?;
600             fmt::Display::fmt(t, f)?;
601             primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
602         }
603         clean::Never => primitive_link(f, PrimitiveType::Never, "!"),
604         clean::RawPointer(m, ref t) => {
605             match **t {
606                 clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
607                     if f.alternate() {
608                         primitive_link(f, clean::PrimitiveType::RawPointer,
609                                        &format!("*{}{:#}", RawMutableSpace(m), t))
610                     } else {
611                         primitive_link(f, clean::PrimitiveType::RawPointer,
612                                        &format!("*{}{}", RawMutableSpace(m), t))
613                     }
614                 }
615                 _ => {
616                     primitive_link(f, clean::PrimitiveType::RawPointer,
617                                    &format!("*{}", RawMutableSpace(m)))?;
618                     fmt::Display::fmt(t, f)
619                 }
620             }
621         }
622         clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
623             let lt = match *l {
624                 Some(ref l) => format!("{} ", *l),
625                 _ => "".to_string(),
626             };
627             let m = MutableSpace(mutability);
628             let amp = if f.alternate() {
629                 "&".to_string()
630             } else {
631                 "&amp;".to_string()
632             };
633             match **ty {
634                 clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T]
635                     match **bt {
636                         clean::Generic(_) => {
637                             if f.alternate() {
638                                 primitive_link(f, PrimitiveType::Slice,
639                                     &format!("{}{}{}[{:#}]", amp, lt, m, **bt))
640                             } else {
641                                 primitive_link(f, PrimitiveType::Slice,
642                                     &format!("{}{}{}[{}]", amp, lt, m, **bt))
643                             }
644                         }
645                         _ => {
646                             primitive_link(f, PrimitiveType::Slice,
647                                            &format!("{}{}{}[", amp, lt, m))?;
648                             if f.alternate() {
649                                 write!(f, "{:#}", **bt)?;
650                             } else {
651                                 write!(f, "{}", **bt)?;
652                             }
653                             primitive_link(f, PrimitiveType::Slice, "]")
654                         }
655                     }
656                 }
657                 clean::ResolvedPath { typarams: Some(ref v), .. } if !v.is_empty() => {
658                     write!(f, "{}{}{}(", amp, lt, m)?;
659                     fmt_type(&ty, f, use_absolute)?;
660                     write!(f, ")")
661                 }
662                 clean::Generic(..) => {
663                     primitive_link(f, PrimitiveType::Reference,
664                                    &format!("{}{}{}", amp, lt, m))?;
665                     fmt_type(&ty, f, use_absolute)
666                 }
667                 _ => {
668                     write!(f, "{}{}{}", amp, lt, m)?;
669                     fmt_type(&ty, f, use_absolute)
670                 }
671             }
672         }
673         clean::ImplTrait(ref bounds) => {
674             write!(f, "impl {}", GenericBounds(bounds))
675         }
676         clean::QPath { ref name, ref self_type, ref trait_ } => {
677             let should_show_cast = match *trait_ {
678                 box clean::ResolvedPath { ref path, .. } => {
679                     !path.segments.is_empty() && !self_type.is_self_type()
680                 }
681                 _ => true,
682             };
683             if f.alternate() {
684                 if should_show_cast {
685                     write!(f, "<{:#} as {:#}>::", self_type, trait_)?
686                 } else {
687                     write!(f, "{:#}::", self_type)?
688                 }
689             } else {
690                 if should_show_cast {
691                     write!(f, "&lt;{} as {}&gt;::", self_type, trait_)?
692                 } else {
693                     write!(f, "{}::", self_type)?
694                 }
695             };
696             match *trait_ {
697                 // It's pretty unsightly to look at `<A as B>::C` in output, and
698                 // we've got hyperlinking on our side, so try to avoid longer
699                 // notation as much as possible by making `C` a hyperlink to trait
700                 // `B` to disambiguate.
701                 //
702                 // FIXME: this is still a lossy conversion and there should probably
703                 //        be a better way of representing this in general? Most of
704                 //        the ugliness comes from inlining across crates where
705                 //        everything comes in as a fully resolved QPath (hard to
706                 //        look at).
707                 box clean::ResolvedPath { did, ref typarams, .. } => {
708                     match href(did) {
709                         Some((ref url, _, ref path)) if !f.alternate() => {
710                             write!(f,
711                                    "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
712                                    title=\"type {path}::{name}\">{name}</a>",
713                                    url = url,
714                                    shortty = ItemType::AssociatedType,
715                                    name = name,
716                                    path = path.join("::"))?;
717                         }
718                         _ => write!(f, "{}", name)?,
719                     }
720
721                     // FIXME: `typarams` are not rendered, and this seems bad?
722                     drop(typarams);
723                     Ok(())
724                 }
725                 _ => {
726                     write!(f, "{}", name)
727                 }
728             }
729         }
730         clean::Unique(..) => {
731             panic!("should have been cleaned")
732         }
733     }
734 }
735
736 impl fmt::Display for clean::Type {
737     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
738         fmt_type(self, f, false)
739     }
740 }
741
742 fn fmt_impl(i: &clean::Impl,
743             f: &mut fmt::Formatter,
744             link_trait: bool,
745             use_absolute: bool) -> fmt::Result {
746     if f.alternate() {
747         write!(f, "impl{:#} ", i.generics)?;
748     } else {
749         write!(f, "impl{} ", i.generics)?;
750     }
751
752     if let Some(ref ty) = i.trait_ {
753         if i.polarity == Some(clean::ImplPolarity::Negative) {
754             write!(f, "!")?;
755         }
756
757         if link_trait {
758             fmt::Display::fmt(ty, f)?;
759         } else {
760             match *ty {
761                 clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
762                     let last = path.segments.last().unwrap();
763                     fmt::Display::fmt(&last.name, f)?;
764                     fmt::Display::fmt(&last.args, f)?;
765                 }
766                 _ => unreachable!(),
767             }
768         }
769         write!(f, " for ")?;
770     }
771
772     if let Some(ref ty) = i.blanket_impl {
773         fmt_type(ty, f, use_absolute)?;
774     } else {
775         fmt_type(&i.for_, f, use_absolute)?;
776     }
777
778     fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
779     Ok(())
780 }
781
782 impl fmt::Display for clean::Impl {
783     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
784         fmt_impl(self, f, true, false)
785     }
786 }
787
788 // The difference from above is that trait is not hyperlinked.
789 pub fn fmt_impl_for_trait_page(i: &clean::Impl,
790                                f: &mut fmt::Formatter,
791                                use_absolute: bool) -> fmt::Result {
792     fmt_impl(i, f, false, use_absolute)
793 }
794
795 impl fmt::Display for clean::Arguments {
796     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
797         for (i, input) in self.values.iter().enumerate() {
798             if !input.name.is_empty() {
799                 write!(f, "{}: ", input.name)?;
800             }
801             if f.alternate() {
802                 write!(f, "{:#}", input.type_)?;
803             } else {
804                 write!(f, "{}", input.type_)?;
805             }
806             if i + 1 < self.values.len() { write!(f, ", ")?; }
807         }
808         Ok(())
809     }
810 }
811
812 impl fmt::Display for clean::FunctionRetTy {
813     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
814         match *self {
815             clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
816             clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty),
817             clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
818             clean::DefaultReturn => Ok(()),
819         }
820     }
821 }
822
823 impl fmt::Display for clean::FnDecl {
824     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
825         if self.variadic {
826             if f.alternate() {
827                 write!(f, "({args:#}, ...){arrow:#}", args = self.inputs, arrow = self.output)
828             } else {
829                 write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output)
830             }
831         } else {
832             if f.alternate() {
833                 write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output)
834             } else {
835                 write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
836             }
837         }
838     }
839 }
840
841 impl<'a> fmt::Display for Method<'a> {
842     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
843         let &Method { decl, name_len, indent } = self;
844         let amp = if f.alternate() { "&" } else { "&amp;" };
845         let mut args = String::new();
846         let mut args_plain = String::new();
847         for (i, input) in decl.inputs.values.iter().enumerate() {
848             if i == 0 {
849                 args.push_str("<br>");
850             }
851
852             if let Some(selfty) = input.to_self() {
853                 match selfty {
854                     clean::SelfValue => {
855                         args.push_str("self");
856                         args_plain.push_str("self");
857                     }
858                     clean::SelfBorrowed(Some(ref lt), mtbl) => {
859                         args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl)));
860                         args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl)));
861                     }
862                     clean::SelfBorrowed(None, mtbl) => {
863                         args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl)));
864                         args_plain.push_str(&format!("&{}self", MutableSpace(mtbl)));
865                     }
866                     clean::SelfExplicit(ref typ) => {
867                         if f.alternate() {
868                             args.push_str(&format!("self: {:#}", *typ));
869                         } else {
870                             args.push_str(&format!("self: {}", *typ));
871                         }
872                         args_plain.push_str(&format!("self: {:#}", *typ));
873                     }
874                 }
875             } else {
876                 if i > 0 {
877                     args.push_str(" <br>");
878                     args_plain.push_str(" ");
879                 }
880                 if !input.name.is_empty() {
881                     args.push_str(&format!("{}: ", input.name));
882                     args_plain.push_str(&format!("{}: ", input.name));
883                 }
884
885                 if f.alternate() {
886                     args.push_str(&format!("{:#}", input.type_));
887                 } else {
888                     args.push_str(&format!("{}", input.type_));
889                 }
890                 args_plain.push_str(&format!("{:#}", input.type_));
891             }
892             if i + 1 < decl.inputs.values.len() {
893                 args.push(',');
894                 args_plain.push(',');
895             }
896         }
897
898         if decl.variadic {
899             args.push_str(",<br> ...");
900             args_plain.push_str(", ...");
901         }
902
903         let arrow_plain = format!("{:#}", decl.output);
904         let arrow = if f.alternate() {
905             format!("{:#}", decl.output)
906         } else {
907             format!("{}", decl.output)
908         };
909
910         let pad = repeat(" ").take(name_len).collect::<String>();
911         let plain = format!("{pad}({args}){arrow}",
912                         pad = pad,
913                         args = args_plain,
914                         arrow = arrow_plain);
915
916         let output = if plain.len() > 80 {
917             let full_pad = format!("<br>{}", repeat("&nbsp;").take(indent + 4).collect::<String>());
918             let close_pad = format!("<br>{}", repeat("&nbsp;").take(indent).collect::<String>());
919             format!("({args}{close}){arrow}",
920                     args = args.replace("<br>", &full_pad),
921                     close = close_pad,
922                     arrow = arrow)
923         } else {
924             format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
925         };
926
927         if f.alternate() {
928             write!(f, "{}", output.replace("<br>", "\n"))
929         } else {
930             write!(f, "{}", output)
931         }
932     }
933 }
934
935 impl<'a> fmt::Display for VisSpace<'a> {
936     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
937         match *self.get() {
938             Some(clean::Public) => f.write_str("pub "),
939             Some(clean::Inherited) | None => Ok(()),
940             Some(clean::Visibility::Crate) => write!(f, "pub(crate) "),
941             Some(clean::Visibility::Restricted(did, ref path)) => {
942                 f.write_str("pub(")?;
943                 if path.segments.len() != 1
944                     || (path.segments[0].name != "self" && path.segments[0].name != "super")
945                 {
946                     f.write_str("in ")?;
947                 }
948                 resolved_path(f, did, path, true, false)?;
949                 f.write_str(") ")
950             }
951         }
952     }
953 }
954
955 impl fmt::Display for UnsafetySpace {
956     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
957         match self.get() {
958             hir::Unsafety::Unsafe => write!(f, "unsafe "),
959             hir::Unsafety::Normal => Ok(())
960         }
961     }
962 }
963
964 impl fmt::Display for ConstnessSpace {
965     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
966         match self.get() {
967             hir::Constness::Const => write!(f, "const "),
968             hir::Constness::NotConst => Ok(())
969         }
970     }
971 }
972
973 impl fmt::Display for AsyncSpace {
974     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
975         match self.0 {
976             hir::IsAsync::Async => write!(f, "async "),
977             hir::IsAsync::NotAsync => Ok(()),
978         }
979     }
980 }
981
982 impl fmt::Display for clean::Import {
983     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
984         match *self {
985             clean::Import::Simple(ref name, ref src) => {
986                 if *name == src.path.last_name() {
987                     write!(f, "use {};", *src)
988                 } else {
989                     write!(f, "use {} as {};", *src, *name)
990                 }
991             }
992             clean::Import::Glob(ref src) => {
993                 if src.path.segments.is_empty() {
994                     write!(f, "use *;")
995                 } else {
996                     write!(f, "use {}::*;", *src)
997                 }
998             }
999         }
1000     }
1001 }
1002
1003 impl fmt::Display for clean::ImportSource {
1004     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1005         match self.did {
1006             Some(did) => resolved_path(f, did, &self.path, true, false),
1007             _ => {
1008                 for (i, seg) in self.path.segments.iter().enumerate() {
1009                     if i > 0 {
1010                         write!(f, "::")?
1011                     }
1012                     write!(f, "{}", seg.name)?;
1013                 }
1014                 Ok(())
1015             }
1016         }
1017     }
1018 }
1019
1020 impl fmt::Display for clean::TypeBinding {
1021     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1022         if f.alternate() {
1023             write!(f, "{} = {:#}", self.name, self.ty)
1024         } else {
1025             write!(f, "{} = {}", self.name, self.ty)
1026         }
1027     }
1028 }
1029
1030 impl fmt::Display for MutableSpace {
1031     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1032         match *self {
1033             MutableSpace(clean::Immutable) => Ok(()),
1034             MutableSpace(clean::Mutable) => write!(f, "mut "),
1035         }
1036     }
1037 }
1038
1039 impl fmt::Display for RawMutableSpace {
1040     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1041         match *self {
1042             RawMutableSpace(clean::Immutable) => write!(f, "const "),
1043             RawMutableSpace(clean::Mutable) => write!(f, "mut "),
1044         }
1045     }
1046 }
1047
1048 impl fmt::Display for AbiSpace {
1049     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1050         let quot = if f.alternate() { "\"" } else { "&quot;" };
1051         match self.0 {
1052             Abi::Rust => Ok(()),
1053             abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
1054         }
1055     }
1056 }