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