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