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