]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/format.rs
Rollup merge of #90202 - matthewjasper:xcrate-hygiene, r=petrochenkov
[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::cell::Cell;
9 use std::fmt;
10 use std::iter;
11
12 use rustc_attr::{ConstStability, StabilityLevel};
13 use rustc_data_structures::captures::Captures;
14 use rustc_data_structures::fx::FxHashSet;
15 use rustc_hir as hir;
16 use rustc_hir::def_id::DefId;
17 use rustc_middle::ty::TyCtxt;
18 use rustc_span::def_id::CRATE_DEF_INDEX;
19 use rustc_target::spec::abi::Abi;
20
21 use crate::clean::{self, utils::find_nearest_parent_module, ExternalCrate, ItemId, PrimitiveType};
22 use crate::formats::item_type::ItemType;
23 use crate::html::escape::Escape;
24 use crate::html::render::cache::ExternalLocation;
25 use crate::html::render::Context;
26
27 crate trait Print {
28     fn print(self, buffer: &mut Buffer);
29 }
30
31 impl<F> Print for F
32 where
33     F: FnOnce(&mut Buffer),
34 {
35     fn print(self, buffer: &mut Buffer) {
36         (self)(buffer)
37     }
38 }
39
40 impl Print for String {
41     fn print(self, buffer: &mut Buffer) {
42         buffer.write_str(&self);
43     }
44 }
45
46 impl Print for &'_ str {
47     fn print(self, buffer: &mut Buffer) {
48         buffer.write_str(self);
49     }
50 }
51
52 #[derive(Debug, Clone)]
53 crate struct Buffer {
54     for_html: bool,
55     buffer: String,
56 }
57
58 impl Buffer {
59     crate fn empty_from(v: &Buffer) -> Buffer {
60         Buffer { for_html: v.for_html, buffer: String::new() }
61     }
62
63     crate fn html() -> Buffer {
64         Buffer { for_html: true, buffer: String::new() }
65     }
66
67     crate fn new() -> Buffer {
68         Buffer { for_html: false, buffer: String::new() }
69     }
70
71     crate fn is_empty(&self) -> bool {
72         self.buffer.is_empty()
73     }
74
75     crate fn into_inner(self) -> String {
76         self.buffer
77     }
78
79     crate fn insert_str(&mut self, idx: usize, s: &str) {
80         self.buffer.insert_str(idx, s);
81     }
82
83     crate fn push_str(&mut self, s: &str) {
84         self.buffer.push_str(s);
85     }
86
87     crate fn push_buffer(&mut self, other: Buffer) {
88         self.buffer.push_str(&other.buffer);
89     }
90
91     // Intended for consumption by write! and writeln! (std::fmt) but without
92     // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
93     // import).
94     crate fn write_str(&mut self, s: &str) {
95         self.buffer.push_str(s);
96     }
97
98     // Intended for consumption by write! and writeln! (std::fmt) but without
99     // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
100     // import).
101     crate fn write_fmt(&mut self, v: fmt::Arguments<'_>) {
102         use fmt::Write;
103         self.buffer.write_fmt(v).unwrap();
104     }
105
106     crate fn to_display<T: Print>(mut self, t: T) -> String {
107         t.print(&mut self);
108         self.into_inner()
109     }
110
111     crate fn is_for_html(&self) -> bool {
112         self.for_html
113     }
114
115     crate fn reserve(&mut self, additional: usize) {
116         self.buffer.reserve(additional)
117     }
118 }
119
120 fn comma_sep<T: fmt::Display>(items: impl Iterator<Item = T>) -> impl fmt::Display {
121     display_fn(move |f| {
122         for (i, item) in items.enumerate() {
123             if i != 0 {
124                 write!(f, ", ")?;
125             }
126             fmt::Display::fmt(&item, f)?;
127         }
128         Ok(())
129     })
130 }
131
132 crate fn print_generic_bounds<'a, 'tcx: 'a>(
133     bounds: &'a [clean::GenericBound],
134     cx: &'a Context<'tcx>,
135 ) -> impl fmt::Display + 'a + Captures<'tcx> {
136     display_fn(move |f| {
137         let mut bounds_dup = FxHashSet::default();
138
139         for (i, bound) in
140             bounds.iter().filter(|b| bounds_dup.insert(b.print(cx).to_string())).enumerate()
141         {
142             if i > 0 {
143                 f.write_str(" + ")?;
144             }
145             fmt::Display::fmt(&bound.print(cx), f)?;
146         }
147         Ok(())
148     })
149 }
150
151 impl clean::GenericParamDef {
152     crate fn print<'a, 'tcx: 'a>(
153         &'a self,
154         cx: &'a Context<'tcx>,
155     ) -> impl fmt::Display + 'a + Captures<'tcx> {
156         display_fn(move |f| match &self.kind {
157             clean::GenericParamDefKind::Lifetime { outlives } => {
158                 write!(f, "{}", self.name)?;
159
160                 if !outlives.is_empty() {
161                     f.write_str(": ")?;
162                     for (i, lt) in outlives.iter().enumerate() {
163                         if i != 0 {
164                             f.write_str(" + ")?;
165                         }
166                         write!(f, "{}", lt.print())?;
167                     }
168                 }
169
170                 Ok(())
171             }
172             clean::GenericParamDefKind::Type { bounds, default, .. } => {
173                 f.write_str(&*self.name.as_str())?;
174
175                 if !bounds.is_empty() {
176                     if f.alternate() {
177                         write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
178                     } else {
179                         write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cx))?;
180                     }
181                 }
182
183                 if let Some(ref ty) = default {
184                     if f.alternate() {
185                         write!(f, " = {:#}", ty.print(cx))?;
186                     } else {
187                         write!(f, "&nbsp;=&nbsp;{}", ty.print(cx))?;
188                     }
189                 }
190
191                 Ok(())
192             }
193             clean::GenericParamDefKind::Const { ty, default, .. } => {
194                 if f.alternate() {
195                     write!(f, "const {}: {:#}", self.name, ty.print(cx))?;
196                 } else {
197                     write!(f, "const {}:&nbsp;{}", self.name, ty.print(cx))?;
198                 }
199
200                 if let Some(default) = default {
201                     if f.alternate() {
202                         write!(f, " = {:#}", default)?;
203                     } else {
204                         write!(f, "&nbsp;=&nbsp;{}", default)?;
205                     }
206                 }
207
208                 Ok(())
209             }
210         })
211     }
212 }
213
214 impl clean::Generics {
215     crate fn print<'a, 'tcx: 'a>(
216         &'a self,
217         cx: &'a Context<'tcx>,
218     ) -> impl fmt::Display + 'a + Captures<'tcx> {
219         display_fn(move |f| {
220             let real_params =
221                 self.params.iter().filter(|p| !p.is_synthetic_type_param()).collect::<Vec<_>>();
222             if real_params.is_empty() {
223                 return Ok(());
224             }
225             if f.alternate() {
226                 write!(f, "<{:#}>", comma_sep(real_params.iter().map(|g| g.print(cx))))
227             } else {
228                 write!(f, "&lt;{}&gt;", comma_sep(real_params.iter().map(|g| g.print(cx))))
229             }
230         })
231     }
232 }
233
234 /// * The Generics from which to emit a where-clause.
235 /// * The number of spaces to indent each line with.
236 /// * Whether the where-clause needs to add a comma and newline after the last bound.
237 crate fn print_where_clause<'a, 'tcx: 'a>(
238     gens: &'a clean::Generics,
239     cx: &'a Context<'tcx>,
240     indent: usize,
241     end_newline: bool,
242 ) -> impl fmt::Display + 'a + Captures<'tcx> {
243     display_fn(move |f| {
244         if gens.where_predicates.is_empty() {
245             return Ok(());
246         }
247         let mut clause = String::new();
248         if f.alternate() {
249             clause.push_str(" where");
250         } else {
251             if end_newline {
252                 clause.push_str(" <span class=\"where fmt-newline\">where");
253             } else {
254                 clause.push_str(" <span class=\"where\">where");
255             }
256         }
257         for (i, pred) in gens.where_predicates.iter().enumerate() {
258             if f.alternate() {
259                 clause.push(' ');
260             } else {
261                 clause.push_str("<br>");
262             }
263
264             match pred {
265                 clean::WherePredicate::BoundPredicate { ty, bounds, bound_params } => {
266                     let bounds = bounds;
267                     let for_prefix = match bound_params.len() {
268                         0 => String::new(),
269                         _ if f.alternate() => {
270                             format!(
271                                 "for&lt;{:#}&gt; ",
272                                 comma_sep(bound_params.iter().map(|lt| lt.print()))
273                             )
274                         }
275                         _ => format!(
276                             "for&lt;{}&gt; ",
277                             comma_sep(bound_params.iter().map(|lt| lt.print()))
278                         ),
279                     };
280
281                     if f.alternate() {
282                         clause.push_str(&format!(
283                             "{}{:#}: {:#}",
284                             for_prefix,
285                             ty.print(cx),
286                             print_generic_bounds(bounds, cx)
287                         ));
288                     } else {
289                         clause.push_str(&format!(
290                             "{}{}: {}",
291                             for_prefix,
292                             ty.print(cx),
293                             print_generic_bounds(bounds, cx)
294                         ));
295                     }
296                 }
297                 clean::WherePredicate::RegionPredicate { lifetime, bounds } => {
298                     clause.push_str(&format!(
299                         "{}: {}",
300                         lifetime.print(),
301                         bounds
302                             .iter()
303                             .map(|b| b.print(cx).to_string())
304                             .collect::<Vec<_>>()
305                             .join(" + ")
306                     ));
307                 }
308                 clean::WherePredicate::EqPredicate { lhs, rhs } => {
309                     if f.alternate() {
310                         clause.push_str(&format!("{:#} == {:#}", lhs.print(cx), rhs.print(cx),));
311                     } else {
312                         clause.push_str(&format!("{} == {}", lhs.print(cx), rhs.print(cx),));
313                     }
314                 }
315             }
316
317             if i < gens.where_predicates.len() - 1 || end_newline {
318                 clause.push(',');
319             }
320         }
321
322         if end_newline {
323             // add a space so stripping <br> tags and breaking spaces still renders properly
324             if f.alternate() {
325                 clause.push(' ');
326             } else {
327                 clause.push_str("&nbsp;");
328             }
329         }
330
331         if !f.alternate() {
332             clause.push_str("</span>");
333             let padding = "&nbsp;".repeat(indent + 4);
334             clause = clause.replace("<br>", &format!("<br>{}", padding));
335             clause.insert_str(0, &"&nbsp;".repeat(indent.saturating_sub(1)));
336             if !end_newline {
337                 clause.insert_str(0, "<br>");
338             }
339         }
340         write!(f, "{}", clause)
341     })
342 }
343
344 impl clean::Lifetime {
345     crate fn print(&self) -> impl fmt::Display + '_ {
346         self.get_ref()
347     }
348 }
349
350 impl clean::Constant {
351     crate fn print(&self, tcx: TyCtxt<'_>) -> impl fmt::Display + '_ {
352         let expr = self.expr(tcx);
353         display_fn(
354             move |f| {
355                 if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) }
356             },
357         )
358     }
359 }
360
361 impl clean::PolyTrait {
362     fn print<'a, 'tcx: 'a>(
363         &'a self,
364         cx: &'a Context<'tcx>,
365     ) -> impl fmt::Display + 'a + Captures<'tcx> {
366         display_fn(move |f| {
367             if !self.generic_params.is_empty() {
368                 if f.alternate() {
369                     write!(
370                         f,
371                         "for<{:#}> ",
372                         comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
373                     )?;
374                 } else {
375                     write!(
376                         f,
377                         "for&lt;{}&gt; ",
378                         comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
379                     )?;
380                 }
381             }
382             if f.alternate() {
383                 write!(f, "{:#}", self.trait_.print(cx))
384             } else {
385                 write!(f, "{}", self.trait_.print(cx))
386             }
387         })
388     }
389 }
390
391 impl clean::GenericBound {
392     crate fn print<'a, 'tcx: 'a>(
393         &'a self,
394         cx: &'a Context<'tcx>,
395     ) -> impl fmt::Display + 'a + Captures<'tcx> {
396         display_fn(move |f| match self {
397             clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()),
398             clean::GenericBound::TraitBound(ty, modifier) => {
399                 let modifier_str = match modifier {
400                     hir::TraitBoundModifier::None => "",
401                     hir::TraitBoundModifier::Maybe => "?",
402                     hir::TraitBoundModifier::MaybeConst => "~const",
403                 };
404                 if f.alternate() {
405                     write!(f, "{}{:#}", modifier_str, ty.print(cx))
406                 } else {
407                     write!(f, "{}{}", modifier_str, ty.print(cx))
408                 }
409             }
410         })
411     }
412 }
413
414 impl clean::GenericArgs {
415     fn print<'a, 'tcx: 'a>(
416         &'a self,
417         cx: &'a Context<'tcx>,
418     ) -> impl fmt::Display + 'a + Captures<'tcx> {
419         display_fn(move |f| {
420             match self {
421                 clean::GenericArgs::AngleBracketed { args, bindings } => {
422                     if !args.is_empty() || !bindings.is_empty() {
423                         if f.alternate() {
424                             f.write_str("<")?;
425                         } else {
426                             f.write_str("&lt;")?;
427                         }
428                         let mut comma = false;
429                         for arg in args {
430                             if comma {
431                                 f.write_str(", ")?;
432                             }
433                             comma = true;
434                             if f.alternate() {
435                                 write!(f, "{:#}", arg.print(cx))?;
436                             } else {
437                                 write!(f, "{}", arg.print(cx))?;
438                             }
439                         }
440                         for binding in bindings {
441                             if comma {
442                                 f.write_str(", ")?;
443                             }
444                             comma = true;
445                             if f.alternate() {
446                                 write!(f, "{:#}", binding.print(cx))?;
447                             } else {
448                                 write!(f, "{}", binding.print(cx))?;
449                             }
450                         }
451                         if f.alternate() {
452                             f.write_str(">")?;
453                         } else {
454                             f.write_str("&gt;")?;
455                         }
456                     }
457                 }
458                 clean::GenericArgs::Parenthesized { inputs, output } => {
459                     f.write_str("(")?;
460                     let mut comma = false;
461                     for ty in inputs {
462                         if comma {
463                             f.write_str(", ")?;
464                         }
465                         comma = true;
466                         if f.alternate() {
467                             write!(f, "{:#}", ty.print(cx))?;
468                         } else {
469                             write!(f, "{}", ty.print(cx))?;
470                         }
471                     }
472                     f.write_str(")")?;
473                     if let Some(ref ty) = *output {
474                         if f.alternate() {
475                             write!(f, " -> {:#}", ty.print(cx))?;
476                         } else {
477                             write!(f, " -&gt; {}", ty.print(cx))?;
478                         }
479                     }
480                 }
481             }
482             Ok(())
483         })
484     }
485 }
486
487 // Possible errors when computing href link source for a `DefId`
488 crate enum HrefError {
489     /// This item is known to rustdoc, but from a crate that does not have documentation generated.
490     ///
491     /// This can only happen for non-local items.
492     DocumentationNotBuilt,
493     /// This can only happen for non-local items when `--document-private-items` is not passed.
494     Private,
495     // Not in external cache, href link should be in same page
496     NotInExternalCache,
497 }
498
499 crate fn href_with_root_path(
500     did: DefId,
501     cx: &Context<'_>,
502     root_path: Option<&str>,
503 ) -> Result<(String, ItemType, Vec<String>), HrefError> {
504     let cache = &cx.cache();
505     let relative_to = &cx.current;
506     fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
507         if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] }
508     }
509
510     if !did.is_local()
511         && !cache.access_levels.is_public(did)
512         && !cache.document_private
513         && !cache.primitive_locations.values().any(|&id| id == did)
514     {
515         return Err(HrefError::Private);
516     }
517
518     let mut is_remote = false;
519     let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
520         Some(&(ref fqp, shortty)) => (fqp, shortty, {
521             let module_fqp = to_module_fqp(shortty, fqp);
522             debug!(?fqp, ?shortty, ?module_fqp);
523             href_relative_parts(module_fqp, relative_to)
524         }),
525         None => {
526             if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&did) {
527                 let module_fqp = to_module_fqp(shortty, fqp);
528                 (
529                     fqp,
530                     shortty,
531                     match cache.extern_locations[&did.krate] {
532                         ExternalLocation::Remote(ref s) => {
533                             is_remote = true;
534                             let s = s.trim_end_matches('/');
535                             let mut s = vec![s];
536                             s.extend(module_fqp[..].iter().map(String::as_str));
537                             s
538                         }
539                         ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
540                         ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt),
541                     },
542                 )
543             } else {
544                 return Err(HrefError::NotInExternalCache);
545             }
546         }
547     };
548     if !is_remote {
549         if let Some(root_path) = root_path {
550             let root = root_path.trim_end_matches('/');
551             url_parts.insert(0, root);
552         }
553     }
554     debug!(?url_parts);
555     let last = &fqp.last().unwrap()[..];
556     let filename;
557     match shortty {
558         ItemType::Module => {
559             url_parts.push("index.html");
560         }
561         _ => {
562             filename = format!("{}.{}.html", shortty.as_str(), last);
563             url_parts.push(&filename);
564         }
565     }
566     Ok((url_parts.join("/"), shortty, fqp.to_vec()))
567 }
568
569 crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
570     href_with_root_path(did, cx, None)
571 }
572
573 /// Both paths should only be modules.
574 /// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
575 /// both need `../iter/trait.Iterator.html` to get at the iterator trait.
576 crate fn href_relative_parts<'a>(fqp: &'a [String], relative_to_fqp: &'a [String]) -> Vec<&'a str> {
577     for (i, (f, r)) in fqp.iter().zip(relative_to_fqp.iter()).enumerate() {
578         // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
579         if f != r {
580             let dissimilar_part_count = relative_to_fqp.len() - i;
581             let fqp_module = fqp[i..fqp.len()].iter().map(String::as_str);
582             return iter::repeat("..").take(dissimilar_part_count).chain(fqp_module).collect();
583         }
584     }
585     // e.g. linking to std::sync::atomic from std::sync
586     if relative_to_fqp.len() < fqp.len() {
587         fqp[relative_to_fqp.len()..fqp.len()].iter().map(String::as_str).collect()
588     // e.g. linking to std::sync from std::sync::atomic
589     } else if fqp.len() < relative_to_fqp.len() {
590         let dissimilar_part_count = relative_to_fqp.len() - fqp.len();
591         iter::repeat("..").take(dissimilar_part_count).collect()
592     // linking to the same module
593     } else {
594         Vec::new()
595     }
596 }
597
598 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
599 /// rendering function with the necessary arguments for linking to a local path.
600 fn resolved_path<'cx>(
601     w: &mut fmt::Formatter<'_>,
602     did: DefId,
603     path: &clean::Path,
604     print_all: bool,
605     use_absolute: bool,
606     cx: &'cx Context<'_>,
607 ) -> fmt::Result {
608     let last = path.segments.last().unwrap();
609
610     if print_all {
611         for seg in &path.segments[..path.segments.len() - 1] {
612             write!(w, "{}::", seg.name)?;
613         }
614     }
615     if w.alternate() {
616         write!(w, "{}{:#}", &last.name, last.args.print(cx))?;
617     } else {
618         let path = if use_absolute {
619             if let Ok((_, _, fqp)) = href(did, cx) {
620                 format!(
621                     "{}::{}",
622                     fqp[..fqp.len() - 1].join("::"),
623                     anchor(did, fqp.last().unwrap(), cx)
624                 )
625             } else {
626                 last.name.to_string()
627             }
628         } else {
629             anchor(did, &*last.name.as_str(), cx).to_string()
630         };
631         write!(w, "{}{}", path, last.args.print(cx))?;
632     }
633     Ok(())
634 }
635
636 fn primitive_link(
637     f: &mut fmt::Formatter<'_>,
638     prim: clean::PrimitiveType,
639     name: &str,
640     cx: &Context<'_>,
641 ) -> fmt::Result {
642     let m = &cx.cache();
643     let mut needs_termination = false;
644     if !f.alternate() {
645         match m.primitive_locations.get(&prim) {
646             Some(&def_id) if def_id.is_local() => {
647                 let len = cx.current.len();
648                 let len = if len == 0 { 0 } else { len - 1 };
649                 write!(
650                     f,
651                     "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
652                     "../".repeat(len),
653                     prim.as_sym()
654                 )?;
655                 needs_termination = true;
656             }
657             Some(&def_id) => {
658                 let cname_str;
659                 let loc = match m.extern_locations[&def_id.krate] {
660                     ExternalLocation::Remote(ref s) => {
661                         cname_str =
662                             ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
663                         Some(vec![s.trim_end_matches('/'), &cname_str[..]])
664                     }
665                     ExternalLocation::Local => {
666                         cname_str =
667                             ExternalCrate { crate_num: def_id.krate }.name(cx.tcx()).as_str();
668                         Some(if cx.current.first().map(|x| &x[..]) == Some(&cname_str[..]) {
669                             iter::repeat("..").take(cx.current.len() - 1).collect()
670                         } else {
671                             let cname = iter::once(&cname_str[..]);
672                             iter::repeat("..").take(cx.current.len()).chain(cname).collect()
673                         })
674                     }
675                     ExternalLocation::Unknown => None,
676                 };
677                 if let Some(loc) = loc {
678                     write!(
679                         f,
680                         "<a class=\"primitive\" href=\"{}/primitive.{}.html\">",
681                         loc.join("/"),
682                         prim.as_sym()
683                     )?;
684                     needs_termination = true;
685                 }
686             }
687             None => {}
688         }
689     }
690     write!(f, "{}", name)?;
691     if needs_termination {
692         write!(f, "</a>")?;
693     }
694     Ok(())
695 }
696
697 /// Helper to render type parameters
698 fn tybounds<'a, 'tcx: 'a>(
699     bounds: &'a [clean::PolyTrait],
700     lt: &'a Option<clean::Lifetime>,
701     cx: &'a Context<'tcx>,
702 ) -> impl fmt::Display + 'a + Captures<'tcx> {
703     display_fn(move |f| {
704         for (i, bound) in bounds.iter().enumerate() {
705             if i > 0 {
706                 write!(f, " + ")?;
707             }
708
709             fmt::Display::fmt(&bound.print(cx), f)?;
710         }
711
712         if let Some(lt) = lt {
713             write!(f, " + ")?;
714             fmt::Display::fmt(&lt.print(), f)?;
715         }
716         Ok(())
717     })
718 }
719
720 crate fn anchor<'a, 'cx: 'a>(
721     did: DefId,
722     text: &'a str,
723     cx: &'cx Context<'_>,
724 ) -> impl fmt::Display + 'a {
725     let parts = href(did, cx);
726     display_fn(move |f| {
727         if let Ok((url, short_ty, fqp)) = parts {
728             write!(
729                 f,
730                 r#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
731                 short_ty,
732                 url,
733                 short_ty,
734                 fqp.join("::"),
735                 text
736             )
737         } else {
738             write!(f, "{}", text)
739         }
740     })
741 }
742
743 fn fmt_type<'cx>(
744     t: &clean::Type,
745     f: &mut fmt::Formatter<'_>,
746     use_absolute: bool,
747     cx: &'cx Context<'_>,
748 ) -> fmt::Result {
749     trace!("fmt_type(t = {:?})", t);
750
751     match *t {
752         clean::Generic(name) => write!(f, "{}", name),
753         clean::ResolvedPath { did, ref path } => {
754             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
755             resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx)
756         }
757         clean::DynTrait(ref bounds, ref lt) => {
758             f.write_str("dyn ")?;
759             fmt::Display::fmt(&tybounds(bounds, lt, cx), f)
760         }
761         clean::Infer => write!(f, "_"),
762         clean::Primitive(clean::PrimitiveType::Never) => {
763             primitive_link(f, PrimitiveType::Never, "!", cx)
764         }
765         clean::Primitive(prim) => primitive_link(f, prim, &*prim.as_sym().as_str(), cx),
766         clean::BareFunction(ref decl) => {
767             if f.alternate() {
768                 write!(
769                     f,
770                     "{:#}{}{:#}fn{:#}",
771                     decl.print_hrtb_with_space(cx),
772                     decl.unsafety.print_with_space(),
773                     print_abi_with_space(decl.abi),
774                     decl.decl.print(cx),
775                 )
776             } else {
777                 write!(
778                     f,
779                     "{}{}{}",
780                     decl.print_hrtb_with_space(cx),
781                     decl.unsafety.print_with_space(),
782                     print_abi_with_space(decl.abi)
783                 )?;
784                 primitive_link(f, PrimitiveType::Fn, "fn", cx)?;
785                 write!(f, "{}", decl.decl.print(cx))
786             }
787         }
788         clean::Tuple(ref typs) => {
789             match &typs[..] {
790                 &[] => primitive_link(f, PrimitiveType::Unit, "()", cx),
791                 &[ref one] => {
792                     primitive_link(f, PrimitiveType::Tuple, "(", cx)?;
793                     // Carry `f.alternate()` into this display w/o branching manually.
794                     fmt::Display::fmt(&one.print(cx), f)?;
795                     primitive_link(f, PrimitiveType::Tuple, ",)", cx)
796                 }
797                 many => {
798                     primitive_link(f, PrimitiveType::Tuple, "(", cx)?;
799                     for (i, item) in many.iter().enumerate() {
800                         if i != 0 {
801                             write!(f, ", ")?;
802                         }
803                         fmt::Display::fmt(&item.print(cx), f)?;
804                     }
805                     primitive_link(f, PrimitiveType::Tuple, ")", cx)
806                 }
807             }
808         }
809         clean::Slice(ref t) => {
810             primitive_link(f, PrimitiveType::Slice, "[", cx)?;
811             fmt::Display::fmt(&t.print(cx), f)?;
812             primitive_link(f, PrimitiveType::Slice, "]", cx)
813         }
814         clean::Array(ref t, ref n) => {
815             primitive_link(f, PrimitiveType::Array, "[", cx)?;
816             fmt::Display::fmt(&t.print(cx), f)?;
817             if f.alternate() {
818                 primitive_link(f, PrimitiveType::Array, &format!("; {}]", n), cx)
819             } else {
820                 primitive_link(f, PrimitiveType::Array, &format!("; {}]", Escape(n)), cx)
821             }
822         }
823         clean::RawPointer(m, ref t) => {
824             let m = match m {
825                 hir::Mutability::Mut => "mut",
826                 hir::Mutability::Not => "const",
827             };
828
829             if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
830                 let text = if f.alternate() {
831                     format!("*{} {:#}", m, t.print(cx))
832                 } else {
833                     format!("*{} {}", m, t.print(cx))
834                 };
835                 primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx)
836             } else {
837                 primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?;
838                 fmt::Display::fmt(&t.print(cx), f)
839             }
840         }
841         clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
842             let lt = match l {
843                 Some(l) => format!("{} ", l.print()),
844                 _ => String::new(),
845             };
846             let m = mutability.print_with_space();
847             let amp = if f.alternate() { "&".to_string() } else { "&amp;".to_string() };
848             match **ty {
849                 clean::Slice(ref bt) => {
850                     // `BorrowedRef{ ... Slice(T) }` is `&[T]`
851                     match **bt {
852                         clean::Generic(_) => {
853                             if f.alternate() {
854                                 primitive_link(
855                                     f,
856                                     PrimitiveType::Slice,
857                                     &format!("{}{}{}[{:#}]", amp, lt, m, bt.print(cx)),
858                                     cx,
859                                 )
860                             } else {
861                                 primitive_link(
862                                     f,
863                                     PrimitiveType::Slice,
864                                     &format!("{}{}{}[{}]", amp, lt, m, bt.print(cx)),
865                                     cx,
866                                 )
867                             }
868                         }
869                         _ => {
870                             primitive_link(
871                                 f,
872                                 PrimitiveType::Slice,
873                                 &format!("{}{}{}[", amp, lt, m),
874                                 cx,
875                             )?;
876                             if f.alternate() {
877                                 write!(f, "{:#}", bt.print(cx))?;
878                             } else {
879                                 write!(f, "{}", bt.print(cx))?;
880                             }
881                             primitive_link(f, PrimitiveType::Slice, "]", cx)
882                         }
883                     }
884                 }
885                 clean::DynTrait(ref bounds, ref trait_lt)
886                     if bounds.len() > 1 || trait_lt.is_some() =>
887                 {
888                     write!(f, "{}{}{}(", amp, lt, m)?;
889                     fmt_type(ty, f, use_absolute, cx)?;
890                     write!(f, ")")
891                 }
892                 clean::Generic(..) => {
893                     primitive_link(
894                         f,
895                         PrimitiveType::Reference,
896                         &format!("{}{}{}", amp, lt, m),
897                         cx,
898                     )?;
899                     fmt_type(ty, f, use_absolute, cx)
900                 }
901                 _ => {
902                     write!(f, "{}{}{}", amp, lt, m)?;
903                     fmt_type(ty, f, use_absolute, cx)
904                 }
905             }
906         }
907         clean::ImplTrait(ref bounds) => {
908             if f.alternate() {
909                 write!(f, "impl {:#}", print_generic_bounds(bounds, cx))
910             } else {
911                 write!(f, "impl {}", print_generic_bounds(bounds, cx))
912             }
913         }
914         clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => {
915             let should_show_cast = !trait_.segments.is_empty()
916                 && self_def_id
917                     .zip(Some(trait_.def_id()))
918                     .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_);
919             if f.alternate() {
920                 if should_show_cast {
921                     write!(f, "<{:#} as {:#}>::", self_type.print(cx), trait_.print(cx))?
922                 } else {
923                     write!(f, "{:#}::", self_type.print(cx))?
924                 }
925             } else {
926                 if should_show_cast {
927                     write!(f, "&lt;{} as {}&gt;::", self_type.print(cx), trait_.print(cx))?
928                 } else {
929                     write!(f, "{}::", self_type.print(cx))?
930                 }
931             };
932             // It's pretty unsightly to look at `<A as B>::C` in output, and
933             // we've got hyperlinking on our side, so try to avoid longer
934             // notation as much as possible by making `C` a hyperlink to trait
935             // `B` to disambiguate.
936             //
937             // FIXME: this is still a lossy conversion and there should probably
938             //        be a better way of representing this in general? Most of
939             //        the ugliness comes from inlining across crates where
940             //        everything comes in as a fully resolved QPath (hard to
941             //        look at).
942             match href(trait_.def_id(), cx) {
943                 Ok((ref url, _, ref path)) if !f.alternate() => {
944                     write!(
945                         f,
946                         "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
947                                     title=\"type {path}::{name}\">{name}</a>",
948                         url = url,
949                         shortty = ItemType::AssocType,
950                         name = name,
951                         path = path.join("::")
952                     )?;
953                 }
954                 _ => write!(f, "{}", name)?,
955             }
956             Ok(())
957         }
958     }
959 }
960
961 impl clean::Type {
962     crate fn print<'b, 'a: 'b, 'tcx: 'a>(
963         &'a self,
964         cx: &'a Context<'tcx>,
965     ) -> impl fmt::Display + 'b + Captures<'tcx> {
966         display_fn(move |f| fmt_type(self, f, false, cx))
967     }
968 }
969
970 impl clean::Path {
971     crate fn print<'b, 'a: 'b, 'tcx: 'a>(
972         &'a self,
973         cx: &'a Context<'tcx>,
974     ) -> impl fmt::Display + 'b + Captures<'tcx> {
975         display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx))
976     }
977 }
978
979 impl clean::Impl {
980     crate fn print<'a, 'tcx: 'a>(
981         &'a self,
982         use_absolute: bool,
983         cx: &'a Context<'tcx>,
984     ) -> impl fmt::Display + 'a + Captures<'tcx> {
985         display_fn(move |f| {
986             if f.alternate() {
987                 write!(f, "impl{:#} ", self.generics.print(cx))?;
988             } else {
989                 write!(f, "impl{} ", self.generics.print(cx))?;
990             }
991
992             if let Some(ref ty) = self.trait_ {
993                 if self.negative_polarity {
994                     write!(f, "!")?;
995                 }
996                 fmt::Display::fmt(&ty.print(cx), f)?;
997                 write!(f, " for ")?;
998             }
999
1000             if let Some(ref ty) = self.blanket_impl {
1001                 fmt_type(ty, f, use_absolute, cx)?;
1002             } else {
1003                 fmt_type(&self.for_, f, use_absolute, cx)?;
1004             }
1005
1006             fmt::Display::fmt(&print_where_clause(&self.generics, cx, 0, true), f)?;
1007             Ok(())
1008         })
1009     }
1010 }
1011
1012 impl clean::Arguments {
1013     crate fn print<'a, 'tcx: 'a>(
1014         &'a self,
1015         cx: &'a Context<'tcx>,
1016     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1017         display_fn(move |f| {
1018             for (i, input) in self.values.iter().enumerate() {
1019                 if !input.name.is_empty() {
1020                     write!(f, "{}: ", input.name)?;
1021                 }
1022                 if f.alternate() {
1023                     write!(f, "{:#}", input.type_.print(cx))?;
1024                 } else {
1025                     write!(f, "{}", input.type_.print(cx))?;
1026                 }
1027                 if i + 1 < self.values.len() {
1028                     write!(f, ", ")?;
1029                 }
1030             }
1031             Ok(())
1032         })
1033     }
1034 }
1035
1036 impl clean::FnRetTy {
1037     crate fn print<'a, 'tcx: 'a>(
1038         &'a self,
1039         cx: &'a Context<'tcx>,
1040     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1041         display_fn(move |f| match self {
1042             clean::Return(clean::Tuple(tys)) if tys.is_empty() => Ok(()),
1043             clean::Return(ty) if f.alternate() => {
1044                 write!(f, " -> {:#}", ty.print(cx))
1045             }
1046             clean::Return(ty) => write!(f, " -&gt; {}", ty.print(cx)),
1047             clean::DefaultReturn => Ok(()),
1048         })
1049     }
1050 }
1051
1052 impl clean::BareFunctionDecl {
1053     fn print_hrtb_with_space<'a, 'tcx: 'a>(
1054         &'a self,
1055         cx: &'a Context<'tcx>,
1056     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1057         display_fn(move |f| {
1058             if !self.generic_params.is_empty() {
1059                 write!(
1060                     f,
1061                     "for&lt;{}&gt; ",
1062                     comma_sep(self.generic_params.iter().map(|g| g.print(cx)))
1063                 )
1064             } else {
1065                 Ok(())
1066             }
1067         })
1068     }
1069 }
1070
1071 impl clean::FnDecl {
1072     crate fn print<'b, 'a: 'b, 'tcx: 'a>(
1073         &'a self,
1074         cx: &'a Context<'tcx>,
1075     ) -> impl fmt::Display + 'b + Captures<'tcx> {
1076         display_fn(move |f| {
1077             let ellipsis = if self.c_variadic { ", ..." } else { "" };
1078             if f.alternate() {
1079                 write!(
1080                     f,
1081                     "({args:#}{ellipsis}){arrow:#}",
1082                     args = self.inputs.print(cx),
1083                     ellipsis = ellipsis,
1084                     arrow = self.output.print(cx)
1085                 )
1086             } else {
1087                 write!(
1088                     f,
1089                     "({args}{ellipsis}){arrow}",
1090                     args = self.inputs.print(cx),
1091                     ellipsis = ellipsis,
1092                     arrow = self.output.print(cx)
1093                 )
1094             }
1095         })
1096     }
1097
1098     /// * `header_len`: The length of the function header and name. In other words, the number of
1099     ///   characters in the function declaration up to but not including the parentheses.
1100     ///   <br>Used to determine line-wrapping.
1101     /// * `indent`: The number of spaces to indent each successive line with, if line-wrapping is
1102     ///   necessary.
1103     /// * `asyncness`: Whether the function is async or not.
1104     crate fn full_print<'a, 'tcx: 'a>(
1105         &'a self,
1106         header_len: usize,
1107         indent: usize,
1108         asyncness: hir::IsAsync,
1109         cx: &'a Context<'tcx>,
1110     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1111         display_fn(move |f| self.inner_full_print(header_len, indent, asyncness, f, cx))
1112     }
1113
1114     fn inner_full_print(
1115         &self,
1116         header_len: usize,
1117         indent: usize,
1118         asyncness: hir::IsAsync,
1119         f: &mut fmt::Formatter<'_>,
1120         cx: &Context<'_>,
1121     ) -> fmt::Result {
1122         let amp = if f.alternate() { "&" } else { "&amp;" };
1123         let mut args = String::new();
1124         let mut args_plain = String::new();
1125         for (i, input) in self.inputs.values.iter().enumerate() {
1126             if i == 0 {
1127                 args.push_str("<br>");
1128             }
1129
1130             if let Some(selfty) = input.to_self() {
1131                 match selfty {
1132                     clean::SelfValue => {
1133                         args.push_str("self");
1134                         args_plain.push_str("self");
1135                     }
1136                     clean::SelfBorrowed(Some(ref lt), mtbl) => {
1137                         args.push_str(&format!(
1138                             "{}{} {}self",
1139                             amp,
1140                             lt.print(),
1141                             mtbl.print_with_space()
1142                         ));
1143                         args_plain.push_str(&format!(
1144                             "&{} {}self",
1145                             lt.print(),
1146                             mtbl.print_with_space()
1147                         ));
1148                     }
1149                     clean::SelfBorrowed(None, mtbl) => {
1150                         args.push_str(&format!("{}{}self", amp, mtbl.print_with_space()));
1151                         args_plain.push_str(&format!("&{}self", mtbl.print_with_space()));
1152                     }
1153                     clean::SelfExplicit(ref typ) => {
1154                         if f.alternate() {
1155                             args.push_str(&format!("self: {:#}", typ.print(cx)));
1156                         } else {
1157                             args.push_str(&format!("self: {}", typ.print(cx)));
1158                         }
1159                         args_plain.push_str(&format!("self: {:#}", typ.print(cx)));
1160                     }
1161                 }
1162             } else {
1163                 if i > 0 {
1164                     args.push_str(" <br>");
1165                     args_plain.push(' ');
1166                 }
1167                 if !input.name.is_empty() {
1168                     args.push_str(&format!("{}: ", input.name));
1169                     args_plain.push_str(&format!("{}: ", input.name));
1170                 }
1171
1172                 if f.alternate() {
1173                     args.push_str(&format!("{:#}", input.type_.print(cx)));
1174                 } else {
1175                     args.push_str(&input.type_.print(cx).to_string());
1176                 }
1177                 args_plain.push_str(&format!("{:#}", input.type_.print(cx)));
1178             }
1179             if i + 1 < self.inputs.values.len() {
1180                 args.push(',');
1181                 args_plain.push(',');
1182             }
1183         }
1184
1185         let mut args_plain = format!("({})", args_plain);
1186
1187         if self.c_variadic {
1188             args.push_str(",<br> ...");
1189             args_plain.push_str(", ...");
1190         }
1191
1192         let arrow_plain;
1193         let arrow = if let hir::IsAsync::Async = asyncness {
1194             let output = self.sugared_async_return_type();
1195             arrow_plain = format!("{:#}", output.print(cx));
1196             if f.alternate() { arrow_plain.clone() } else { format!("{}", output.print(cx)) }
1197         } else {
1198             arrow_plain = format!("{:#}", self.output.print(cx));
1199             if f.alternate() { arrow_plain.clone() } else { format!("{}", self.output.print(cx)) }
1200         };
1201
1202         let declaration_len = header_len + args_plain.len() + arrow_plain.len();
1203         let output = if declaration_len > 80 {
1204             let full_pad = format!("<br>{}", "&nbsp;".repeat(indent + 4));
1205             let close_pad = format!("<br>{}", "&nbsp;".repeat(indent));
1206             format!(
1207                 "({args}{close}){arrow}",
1208                 args = args.replace("<br>", &full_pad),
1209                 close = close_pad,
1210                 arrow = arrow
1211             )
1212         } else {
1213             format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
1214         };
1215
1216         if f.alternate() {
1217             write!(f, "{}", output.replace("<br>", "\n"))
1218         } else {
1219             write!(f, "{}", output)
1220         }
1221     }
1222 }
1223
1224 impl clean::Visibility {
1225     crate fn print_with_space<'a, 'tcx: 'a>(
1226         self,
1227         item_did: ItemId,
1228         cx: &'a Context<'tcx>,
1229     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1230         let to_print = match self {
1231             clean::Public => "pub ".to_owned(),
1232             clean::Inherited => String::new(),
1233             clean::Visibility::Restricted(vis_did) => {
1234                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
1235                 //                 However, rustdoc currently never displays a module's
1236                 //                 visibility, so it shouldn't matter.
1237                 let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
1238
1239                 if vis_did.index == CRATE_DEF_INDEX {
1240                     "pub(crate) ".to_owned()
1241                 } else if parent_module == Some(vis_did) {
1242                     // `pub(in foo)` where `foo` is the parent module
1243                     // is the same as no visibility modifier
1244                     String::new()
1245                 } else if parent_module
1246                     .map(|parent| find_nearest_parent_module(cx.tcx(), parent))
1247                     .flatten()
1248                     == Some(vis_did)
1249                 {
1250                     "pub(super) ".to_owned()
1251                 } else {
1252                     let path = cx.tcx().def_path(vis_did);
1253                     debug!("path={:?}", path);
1254                     // modified from `resolved_path()` to work with `DefPathData`
1255                     let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
1256                     let anchor = anchor(vis_did, &last_name.as_str(), cx).to_string();
1257
1258                     let mut s = "pub(in ".to_owned();
1259                     for seg in &path.data[..path.data.len() - 1] {
1260                         s.push_str(&format!("{}::", seg.data.get_opt_name().unwrap()));
1261                     }
1262                     s.push_str(&format!("{}) ", anchor));
1263                     s
1264                 }
1265             }
1266         };
1267         display_fn(move |f| f.write_str(&to_print))
1268     }
1269
1270     /// This function is the same as print_with_space, except that it renders no links.
1271     /// It's used for macros' rendered source view, which is syntax highlighted and cannot have
1272     /// any HTML in it.
1273     crate fn to_src_with_space<'a, 'tcx: 'a>(
1274         self,
1275         tcx: TyCtxt<'tcx>,
1276         item_did: DefId,
1277     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1278         let to_print = match self {
1279             clean::Public => "pub ".to_owned(),
1280             clean::Inherited => String::new(),
1281             clean::Visibility::Restricted(vis_did) => {
1282                 // FIXME(camelid): This may not work correctly if `item_did` is a module.
1283                 //                 However, rustdoc currently never displays a module's
1284                 //                 visibility, so it shouldn't matter.
1285                 let parent_module = find_nearest_parent_module(tcx, item_did);
1286
1287                 if vis_did.index == CRATE_DEF_INDEX {
1288                     "pub(crate) ".to_owned()
1289                 } else if parent_module == Some(vis_did) {
1290                     // `pub(in foo)` where `foo` is the parent module
1291                     // is the same as no visibility modifier
1292                     String::new()
1293                 } else if parent_module
1294                     .map(|parent| find_nearest_parent_module(tcx, parent))
1295                     .flatten()
1296                     == Some(vis_did)
1297                 {
1298                     "pub(super) ".to_owned()
1299                 } else {
1300                     format!("pub(in {}) ", tcx.def_path_str(vis_did))
1301                 }
1302             }
1303         };
1304         display_fn(move |f| f.write_str(&to_print))
1305     }
1306 }
1307
1308 crate trait PrintWithSpace {
1309     fn print_with_space(&self) -> &str;
1310 }
1311
1312 impl PrintWithSpace for hir::Unsafety {
1313     fn print_with_space(&self) -> &str {
1314         match self {
1315             hir::Unsafety::Unsafe => "unsafe ",
1316             hir::Unsafety::Normal => "",
1317         }
1318     }
1319 }
1320
1321 impl PrintWithSpace for hir::IsAsync {
1322     fn print_with_space(&self) -> &str {
1323         match self {
1324             hir::IsAsync::Async => "async ",
1325             hir::IsAsync::NotAsync => "",
1326         }
1327     }
1328 }
1329
1330 impl PrintWithSpace for hir::Mutability {
1331     fn print_with_space(&self) -> &str {
1332         match self {
1333             hir::Mutability::Not => "",
1334             hir::Mutability::Mut => "mut ",
1335         }
1336     }
1337 }
1338
1339 crate fn print_constness_with_space(
1340     c: &hir::Constness,
1341     s: Option<&ConstStability>,
1342 ) -> &'static str {
1343     match (c, s) {
1344         // const stable or when feature(staged_api) is not set
1345         (
1346             hir::Constness::Const,
1347             Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }),
1348         )
1349         | (hir::Constness::Const, None) => "const ",
1350         // const unstable or not const
1351         _ => "",
1352     }
1353 }
1354
1355 impl clean::Import {
1356     crate fn print<'a, 'tcx: 'a>(
1357         &'a self,
1358         cx: &'a Context<'tcx>,
1359     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1360         display_fn(move |f| match self.kind {
1361             clean::ImportKind::Simple(name) => {
1362                 if name == self.source.path.last() {
1363                     write!(f, "use {};", self.source.print(cx))
1364                 } else {
1365                     write!(f, "use {} as {};", self.source.print(cx), name)
1366                 }
1367             }
1368             clean::ImportKind::Glob => {
1369                 if self.source.path.segments.is_empty() {
1370                     write!(f, "use *;")
1371                 } else {
1372                     write!(f, "use {}::*;", self.source.print(cx))
1373                 }
1374             }
1375         })
1376     }
1377 }
1378
1379 impl clean::ImportSource {
1380     crate fn print<'a, 'tcx: 'a>(
1381         &'a self,
1382         cx: &'a Context<'tcx>,
1383     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1384         display_fn(move |f| match self.did {
1385             Some(did) => resolved_path(f, did, &self.path, true, false, cx),
1386             _ => {
1387                 for seg in &self.path.segments[..self.path.segments.len() - 1] {
1388                     write!(f, "{}::", seg.name)?;
1389                 }
1390                 let name = self.path.last_name();
1391                 if let hir::def::Res::PrimTy(p) = self.path.res {
1392                     primitive_link(f, PrimitiveType::from(p), &*name, cx)?;
1393                 } else {
1394                     write!(f, "{}", name)?;
1395                 }
1396                 Ok(())
1397             }
1398         })
1399     }
1400 }
1401
1402 impl clean::TypeBinding {
1403     crate fn print<'a, 'tcx: 'a>(
1404         &'a self,
1405         cx: &'a Context<'tcx>,
1406     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1407         display_fn(move |f| {
1408             f.write_str(&*self.name.as_str())?;
1409             match self.kind {
1410                 clean::TypeBindingKind::Equality { ref ty } => {
1411                     if f.alternate() {
1412                         write!(f, " = {:#}", ty.print(cx))?;
1413                     } else {
1414                         write!(f, " = {}", ty.print(cx))?;
1415                     }
1416                 }
1417                 clean::TypeBindingKind::Constraint { ref bounds } => {
1418                     if !bounds.is_empty() {
1419                         if f.alternate() {
1420                             write!(f, ": {:#}", print_generic_bounds(bounds, cx))?;
1421                         } else {
1422                             write!(f, ":&nbsp;{}", print_generic_bounds(bounds, cx))?;
1423                         }
1424                     }
1425                 }
1426             }
1427             Ok(())
1428         })
1429     }
1430 }
1431
1432 crate fn print_abi_with_space(abi: Abi) -> impl fmt::Display {
1433     display_fn(move |f| {
1434         let quot = if f.alternate() { "\"" } else { "&quot;" };
1435         match abi {
1436             Abi::Rust => Ok(()),
1437             abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
1438         }
1439     })
1440 }
1441
1442 crate fn print_default_space<'a>(v: bool) -> &'a str {
1443     if v { "default " } else { "" }
1444 }
1445
1446 impl clean::GenericArg {
1447     crate fn print<'a, 'tcx: 'a>(
1448         &'a self,
1449         cx: &'a Context<'tcx>,
1450     ) -> impl fmt::Display + 'a + Captures<'tcx> {
1451         display_fn(move |f| match self {
1452             clean::GenericArg::Lifetime(lt) => fmt::Display::fmt(&lt.print(), f),
1453             clean::GenericArg::Type(ty) => fmt::Display::fmt(&ty.print(cx), f),
1454             clean::GenericArg::Const(ct) => fmt::Display::fmt(&ct.print(cx.tcx()), f),
1455             clean::GenericArg::Infer => fmt::Display::fmt("_", f),
1456         })
1457     }
1458 }
1459
1460 crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
1461     struct WithFormatter<F>(Cell<Option<F>>);
1462
1463     impl<F> fmt::Display for WithFormatter<F>
1464     where
1465         F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result,
1466     {
1467         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1468             (self.0.take()).unwrap()(f)
1469         }
1470     }
1471
1472     WithFormatter(Cell::new(Some(f)))
1473 }