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