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