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