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