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