]> git.proxmox.com Git - rustc.git/blob - src/librustdoc/html/format.rs
9439fc3c5f405ffedf729376462f0dc3f5c491e6
[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 use std::iter::repeat;
20
21 use syntax::abi::Abi;
22 use syntax::ast;
23 use syntax::ast_util;
24
25 use clean;
26 use html::item_type::ItemType;
27 use html::render;
28 use html::render::{cache, CURRENT_LOCATION_KEY};
29
30 /// Helper to render an optional visibility with a space after it (if the
31 /// visibility is preset)
32 #[derive(Copy, Clone)]
33 pub struct VisSpace(pub Option<ast::Visibility>);
34 /// Similarly to VisSpace, this structure is used to render a function style with a
35 /// space after it.
36 #[derive(Copy, Clone)]
37 pub struct UnsafetySpace(pub ast::Unsafety);
38 /// Similarly to VisSpace, this structure is used to render a function constness
39 /// with a space after it.
40 #[derive(Copy, Clone)]
41 pub struct ConstnessSpace(pub ast::Constness);
42 /// Wrapper struct for properly emitting a method declaration.
43 pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
44 /// Similar to VisSpace, but used for mutability
45 #[derive(Copy, Clone)]
46 pub struct MutableSpace(pub clean::Mutability);
47 /// Similar to VisSpace, but used for mutability
48 #[derive(Copy, Clone)]
49 pub struct RawMutableSpace(pub clean::Mutability);
50 /// Wrapper struct for emitting a where clause from Generics.
51 pub struct WhereClause<'a>(pub &'a clean::Generics);
52 /// Wrapper struct for emitting type parameter bounds.
53 pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
54 /// Wrapper struct for emitting a comma-separated list of items
55 pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
56 pub struct AbiSpace(pub Abi);
57
58 impl VisSpace {
59 pub fn get(&self) -> Option<ast::Visibility> {
60 let VisSpace(v) = *self; v
61 }
62 }
63
64 impl UnsafetySpace {
65 pub fn get(&self) -> ast::Unsafety {
66 let UnsafetySpace(v) = *self; v
67 }
68 }
69
70 impl ConstnessSpace {
71 pub fn get(&self) -> ast::Constness {
72 let ConstnessSpace(v) = *self; v
73 }
74 }
75
76 impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 for (i, item) in self.0.iter().enumerate() {
79 if i != 0 { try!(write!(f, ", ")); }
80 try!(write!(f, "{}", item));
81 }
82 Ok(())
83 }
84 }
85
86 impl<'a> fmt::Display for TyParamBounds<'a> {
87 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
88 let &TyParamBounds(bounds) = self;
89 for (i, bound) in bounds.iter().enumerate() {
90 if i > 0 {
91 try!(f.write_str(" + "));
92 }
93 try!(write!(f, "{}", *bound));
94 }
95 Ok(())
96 }
97 }
98
99 impl fmt::Display for clean::Generics {
100 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101 if self.lifetimes.is_empty() && self.type_params.is_empty() { return Ok(()) }
102 try!(f.write_str("&lt;"));
103
104 for (i, life) in self.lifetimes.iter().enumerate() {
105 if i > 0 {
106 try!(f.write_str(", "));
107 }
108 try!(write!(f, "{}", *life));
109 }
110
111 if !self.type_params.is_empty() {
112 if !self.lifetimes.is_empty() {
113 try!(f.write_str(", "));
114 }
115 for (i, tp) in self.type_params.iter().enumerate() {
116 if i > 0 {
117 try!(f.write_str(", "))
118 }
119 try!(f.write_str(&tp.name));
120
121 if !tp.bounds.is_empty() {
122 try!(write!(f, ": {}", TyParamBounds(&tp.bounds)));
123 }
124
125 match tp.default {
126 Some(ref ty) => { try!(write!(f, " = {}", ty)); },
127 None => {}
128 };
129 }
130 }
131 try!(f.write_str("&gt;"));
132 Ok(())
133 }
134 }
135
136 impl<'a> fmt::Display for WhereClause<'a> {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 let &WhereClause(gens) = self;
139 if gens.where_predicates.is_empty() {
140 return Ok(());
141 }
142 try!(f.write_str(" <span class='where'>where "));
143 for (i, pred) in gens.where_predicates.iter().enumerate() {
144 if i > 0 {
145 try!(f.write_str(", "));
146 }
147 match pred {
148 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
149 let bounds = bounds;
150 try!(write!(f, "{}: {}", ty, TyParamBounds(bounds)));
151 }
152 &clean::WherePredicate::RegionPredicate { ref lifetime,
153 ref bounds } => {
154 try!(write!(f, "{}: ", lifetime));
155 for (i, lifetime) in bounds.iter().enumerate() {
156 if i > 0 {
157 try!(f.write_str(" + "));
158 }
159
160 try!(write!(f, "{}", lifetime));
161 }
162 }
163 &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
164 try!(write!(f, "{} == {}", lhs, rhs));
165 }
166 }
167 }
168 try!(f.write_str("</span>"));
169 Ok(())
170 }
171 }
172
173 impl fmt::Display for clean::Lifetime {
174 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
175 try!(f.write_str(self.get_ref()));
176 Ok(())
177 }
178 }
179
180 impl fmt::Display for clean::PolyTrait {
181 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
182 if !self.lifetimes.is_empty() {
183 try!(f.write_str("for&lt;"));
184 for (i, lt) in self.lifetimes.iter().enumerate() {
185 if i > 0 {
186 try!(f.write_str(", "));
187 }
188 try!(write!(f, "{}", lt));
189 }
190 try!(f.write_str("&gt; "));
191 }
192 write!(f, "{}", self.trait_)
193 }
194 }
195
196 impl fmt::Display for clean::TyParamBound {
197 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
198 match *self {
199 clean::RegionBound(ref lt) => {
200 write!(f, "{}", *lt)
201 }
202 clean::TraitBound(ref ty, modifier) => {
203 let modifier_str = match modifier {
204 ast::TraitBoundModifier::None => "",
205 ast::TraitBoundModifier::Maybe => "?",
206 };
207 write!(f, "{}{}", modifier_str, *ty)
208 }
209 }
210 }
211 }
212
213 impl fmt::Display for clean::PathParameters {
214 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
215 match *self {
216 clean::PathParameters::AngleBracketed {
217 ref lifetimes, ref types, ref bindings
218 } => {
219 if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
220 try!(f.write_str("&lt;"));
221 let mut comma = false;
222 for lifetime in lifetimes {
223 if comma {
224 try!(f.write_str(", "));
225 }
226 comma = true;
227 try!(write!(f, "{}", *lifetime));
228 }
229 for ty in types {
230 if comma {
231 try!(f.write_str(", "));
232 }
233 comma = true;
234 try!(write!(f, "{}", *ty));
235 }
236 for binding in bindings {
237 if comma {
238 try!(f.write_str(", "));
239 }
240 comma = true;
241 try!(write!(f, "{}", *binding));
242 }
243 try!(f.write_str("&gt;"));
244 }
245 }
246 clean::PathParameters::Parenthesized { ref inputs, ref output } => {
247 try!(f.write_str("("));
248 let mut comma = false;
249 for ty in inputs {
250 if comma {
251 try!(f.write_str(", "));
252 }
253 comma = true;
254 try!(write!(f, "{}", *ty));
255 }
256 try!(f.write_str(")"));
257 if let Some(ref ty) = *output {
258 try!(f.write_str(" -&gt; "));
259 try!(write!(f, "{}", ty));
260 }
261 }
262 }
263 Ok(())
264 }
265 }
266
267 impl fmt::Display for clean::PathSegment {
268 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
269 try!(f.write_str(&self.name));
270 write!(f, "{}", self.params)
271 }
272 }
273
274 impl fmt::Display for clean::Path {
275 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 if self.global {
277 try!(f.write_str("::"))
278 }
279
280 for (i, seg) in self.segments.iter().enumerate() {
281 if i > 0 {
282 try!(f.write_str("::"))
283 }
284 try!(write!(f, "{}", seg));
285 }
286 Ok(())
287 }
288 }
289
290 pub fn href(did: ast::DefId) -> Option<(String, ItemType, Vec<String>)> {
291 let cache = cache();
292 let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
293 let &(ref fqp, shortty) = match cache.paths.get(&did) {
294 Some(p) => p,
295 None => return None,
296 };
297 let mut url = if ast_util::is_local(did) || cache.inlined.contains(&did) {
298 repeat("../").take(loc.len()).collect::<String>()
299 } else {
300 match cache.extern_locations[&did.krate] {
301 (_, render::Remote(ref s)) => s.to_string(),
302 (_, render::Local) => repeat("../").take(loc.len()).collect(),
303 (_, render::Unknown) => return None,
304 }
305 };
306 for component in &fqp[..fqp.len() - 1] {
307 url.push_str(component);
308 url.push_str("/");
309 }
310 match shortty {
311 ItemType::Module => {
312 url.push_str(fqp.last().unwrap());
313 url.push_str("/index.html");
314 }
315 _ => {
316 url.push_str(shortty.to_static_str());
317 url.push_str(".");
318 url.push_str(fqp.last().unwrap());
319 url.push_str(".html");
320 }
321 }
322 Some((url, shortty, fqp.to_vec()))
323 }
324
325 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
326 /// rendering function with the necessary arguments for linking to a local path.
327 fn resolved_path(w: &mut fmt::Formatter, did: ast::DefId, path: &clean::Path,
328 print_all: bool) -> fmt::Result {
329 let last = path.segments.last().unwrap();
330 let rel_root = match &*path.segments[0].name {
331 "self" => Some("./".to_string()),
332 _ => None,
333 };
334
335 if print_all {
336 let amt = path.segments.len() - 1;
337 match rel_root {
338 Some(mut root) => {
339 for seg in &path.segments[..amt] {
340 if "super" == seg.name || "self" == seg.name {
341 try!(write!(w, "{}::", seg.name));
342 } else {
343 root.push_str(&seg.name);
344 root.push_str("/");
345 try!(write!(w, "<a class='mod'
346 href='{}index.html'>{}</a>::",
347 root,
348 seg.name));
349 }
350 }
351 }
352 None => {
353 for seg in &path.segments[..amt] {
354 try!(write!(w, "{}::", seg.name));
355 }
356 }
357 }
358 }
359
360 match href(did) {
361 Some((url, shortty, fqp)) => {
362 try!(write!(w, "<a class='{}' href='{}' title='{}'>{}</a>",
363 shortty, url, fqp.connect("::"), last.name));
364 }
365 _ => try!(write!(w, "{}", last.name)),
366 }
367 try!(write!(w, "{}", last.params));
368 Ok(())
369 }
370
371 fn primitive_link(f: &mut fmt::Formatter,
372 prim: clean::PrimitiveType,
373 name: &str) -> fmt::Result {
374 let m = cache();
375 let mut needs_termination = false;
376 match m.primitive_locations.get(&prim) {
377 Some(&ast::LOCAL_CRATE) => {
378 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
379 let len = if len == 0 {0} else {len - 1};
380 try!(write!(f, "<a href='{}primitive.{}.html'>",
381 repeat("../").take(len).collect::<String>(),
382 prim.to_url_str()));
383 needs_termination = true;
384 }
385 Some(&cnum) => {
386 let path = &m.paths[&ast::DefId {
387 krate: cnum,
388 node: ast::CRATE_NODE_ID,
389 }];
390 let loc = match m.extern_locations[&cnum] {
391 (_, render::Remote(ref s)) => Some(s.to_string()),
392 (_, render::Local) => {
393 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
394 Some(repeat("../").take(len).collect::<String>())
395 }
396 (_, render::Unknown) => None,
397 };
398 match loc {
399 Some(root) => {
400 try!(write!(f, "<a href='{}{}/primitive.{}.html'>",
401 root,
402 path.0.first().unwrap(),
403 prim.to_url_str()));
404 needs_termination = true;
405 }
406 None => {}
407 }
408 }
409 None => {}
410 }
411 try!(write!(f, "{}", name));
412 if needs_termination {
413 try!(write!(f, "</a>"));
414 }
415 Ok(())
416 }
417
418 /// Helper to render type parameters
419 fn tybounds(w: &mut fmt::Formatter,
420 typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result {
421 match *typarams {
422 Some(ref params) => {
423 for param in params {
424 try!(write!(w, " + "));
425 try!(write!(w, "{}", *param));
426 }
427 Ok(())
428 }
429 None => Ok(())
430 }
431 }
432
433 impl fmt::Display for clean::Type {
434 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
435 match *self {
436 clean::Generic(ref name) => {
437 f.write_str(name)
438 }
439 clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
440 // Paths like T::Output and Self::Output should be rendered with all segments
441 try!(resolved_path(f, did, path, is_generic));
442 tybounds(f, typarams)
443 }
444 clean::Infer => write!(f, "_"),
445 clean::Primitive(prim) => primitive_link(f, prim, prim.to_string()),
446 clean::BareFunction(ref decl) => {
447 write!(f, "{}{}fn{}{}",
448 UnsafetySpace(decl.unsafety),
449 match &*decl.abi {
450 "" => " extern ".to_string(),
451 "\"Rust\"" => "".to_string(),
452 s => format!(" extern {} ", s)
453 },
454 decl.generics,
455 decl.decl)
456 }
457 clean::Tuple(ref typs) => {
458 primitive_link(f, clean::PrimitiveTuple,
459 &*match &**typs {
460 [ref one] => format!("({},)", one),
461 many => format!("({})", CommaSep(&many)),
462 })
463 }
464 clean::Vector(ref t) => {
465 primitive_link(f, clean::Slice, &format!("[{}]", **t))
466 }
467 clean::FixedVector(ref t, ref s) => {
468 primitive_link(f, clean::PrimitiveType::Array,
469 &format!("[{}; {}]", **t, *s))
470 }
471 clean::Bottom => f.write_str("!"),
472 clean::RawPointer(m, ref t) => {
473 primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
474 &format!("*{}{}", RawMutableSpace(m), **t))
475 }
476 clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
477 let lt = match *l {
478 Some(ref l) => format!("{} ", *l),
479 _ => "".to_string(),
480 };
481 let m = MutableSpace(mutability);
482 match **ty {
483 clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
484 match **bt {
485 clean::Generic(_) =>
486 primitive_link(f, clean::Slice,
487 &format!("&amp;{}{}[{}]", lt, m, **bt)),
488 _ => {
489 try!(primitive_link(f, clean::Slice,
490 &format!("&amp;{}{}[", lt, m)));
491 try!(write!(f, "{}", **bt));
492 primitive_link(f, clean::Slice, "]")
493 }
494 }
495 }
496 _ => {
497 write!(f, "&amp;{}{}{}", lt, m, **ty)
498 }
499 }
500 }
501 clean::PolyTraitRef(ref bounds) => {
502 for (i, bound) in bounds.iter().enumerate() {
503 if i != 0 {
504 try!(write!(f, " + "));
505 }
506 try!(write!(f, "{}", *bound));
507 }
508 Ok(())
509 }
510 // It's pretty unsightly to look at `<A as B>::C` in output, and
511 // we've got hyperlinking on our side, so try to avoid longer
512 // notation as much as possible by making `C` a hyperlink to trait
513 // `B` to disambiguate.
514 //
515 // FIXME: this is still a lossy conversion and there should probably
516 // be a better way of representing this in general? Most of
517 // the ugliness comes from inlining across crates where
518 // everything comes in as a fully resolved QPath (hard to
519 // look at).
520 clean::QPath {
521 ref name,
522 ref self_type,
523 trait_: box clean::ResolvedPath { did, ref typarams, .. },
524 } => {
525 try!(write!(f, "{}::", self_type));
526 let path = clean::Path::singleton(name.clone());
527 try!(resolved_path(f, did, &path, false));
528
529 // FIXME: `typarams` are not rendered, and this seems bad?
530 drop(typarams);
531 Ok(())
532 }
533 clean::QPath { ref name, ref self_type, ref trait_ } => {
534 write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
535 }
536 clean::Unique(..) => {
537 panic!("should have been cleaned")
538 }
539 }
540 }
541 }
542
543 impl fmt::Display for clean::Arguments {
544 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
545 for (i, input) in self.values.iter().enumerate() {
546 if i > 0 { try!(write!(f, ", ")); }
547 if !input.name.is_empty() {
548 try!(write!(f, "{}: ", input.name));
549 }
550 try!(write!(f, "{}", input.type_));
551 }
552 Ok(())
553 }
554 }
555
556 impl fmt::Display for clean::FunctionRetTy {
557 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558 match *self {
559 clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
560 clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
561 clean::DefaultReturn => Ok(()),
562 clean::NoReturn => write!(f, " -&gt; !")
563 }
564 }
565 }
566
567 impl fmt::Display for clean::FnDecl {
568 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
569 write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
570 }
571 }
572
573 impl<'a> fmt::Display for Method<'a> {
574 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
575 let Method(selfty, d) = *self;
576 let mut args = String::new();
577 match *selfty {
578 clean::SelfStatic => {},
579 clean::SelfValue => args.push_str("self"),
580 clean::SelfBorrowed(Some(ref lt), mtbl) => {
581 args.push_str(&format!("&amp;{} {}self", *lt, MutableSpace(mtbl)));
582 }
583 clean::SelfBorrowed(None, mtbl) => {
584 args.push_str(&format!("&amp;{}self", MutableSpace(mtbl)));
585 }
586 clean::SelfExplicit(ref typ) => {
587 args.push_str(&format!("self: {}", *typ));
588 }
589 }
590 for (i, input) in d.inputs.values.iter().enumerate() {
591 if i > 0 || !args.is_empty() { args.push_str(", "); }
592 if !input.name.is_empty() {
593 args.push_str(&format!("{}: ", input.name));
594 }
595 args.push_str(&format!("{}", input.type_));
596 }
597 write!(f, "({args}){arrow}", args = args, arrow = d.output)
598 }
599 }
600
601 impl fmt::Display for VisSpace {
602 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
603 match self.get() {
604 Some(ast::Public) => write!(f, "pub "),
605 Some(ast::Inherited) | None => Ok(())
606 }
607 }
608 }
609
610 impl fmt::Display for UnsafetySpace {
611 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
612 match self.get() {
613 ast::Unsafety::Unsafe => write!(f, "unsafe "),
614 ast::Unsafety::Normal => Ok(())
615 }
616 }
617 }
618
619 impl fmt::Display for ConstnessSpace {
620 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
621 match self.get() {
622 ast::Constness::Const => write!(f, "const "),
623 ast::Constness::NotConst => Ok(())
624 }
625 }
626 }
627
628 impl fmt::Display for clean::Import {
629 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
630 match *self {
631 clean::SimpleImport(ref name, ref src) => {
632 if *name == src.path.segments.last().unwrap().name {
633 write!(f, "use {};", *src)
634 } else {
635 write!(f, "use {} as {};", *src, *name)
636 }
637 }
638 clean::GlobImport(ref src) => {
639 write!(f, "use {}::*;", *src)
640 }
641 clean::ImportList(ref src, ref names) => {
642 try!(write!(f, "use {}::{{", *src));
643 for (i, n) in names.iter().enumerate() {
644 if i > 0 {
645 try!(write!(f, ", "));
646 }
647 try!(write!(f, "{}", *n));
648 }
649 write!(f, "}};")
650 }
651 }
652 }
653 }
654
655 impl fmt::Display for clean::ImportSource {
656 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657 match self.did {
658 Some(did) => resolved_path(f, did, &self.path, true),
659 _ => {
660 for (i, seg) in self.path.segments.iter().enumerate() {
661 if i > 0 {
662 try!(write!(f, "::"))
663 }
664 try!(write!(f, "{}", seg.name));
665 }
666 Ok(())
667 }
668 }
669 }
670 }
671
672 impl fmt::Display for clean::ViewListIdent {
673 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
674 match self.source {
675 Some(did) => {
676 let path = clean::Path::singleton(self.name.clone());
677 resolved_path(f, did, &path, false)
678 }
679 _ => write!(f, "{}", self.name),
680 }
681 }
682 }
683
684 impl fmt::Display for clean::TypeBinding {
685 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
686 write!(f, "{}={}", self.name, self.ty)
687 }
688 }
689
690 impl fmt::Display for MutableSpace {
691 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
692 match *self {
693 MutableSpace(clean::Immutable) => Ok(()),
694 MutableSpace(clean::Mutable) => write!(f, "mut "),
695 }
696 }
697 }
698
699 impl fmt::Display for RawMutableSpace {
700 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
701 match *self {
702 RawMutableSpace(clean::Immutable) => write!(f, "const "),
703 RawMutableSpace(clean::Mutable) => write!(f, "mut "),
704 }
705 }
706 }
707
708 impl fmt::Display for AbiSpace {
709 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
710 match self.0 {
711 Abi::Rust => Ok(()),
712 Abi::C => write!(f, "extern "),
713 abi => write!(f, "extern {} ", abi),
714 }
715 }
716 }