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