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