1 //! HTML formatting module
3 //! This module contains a large number of `fmt::Display` implementations for
4 //! various types in `rustdoc::clean`. These implementations all currently
5 //! assume that HTML output is desired, although it may be possible to redesign
6 //! them in the future to instead emit any format desired.
12 use rustc
::hir
::def_id
::DefId
;
13 use rustc
::util
::nodemap
::FxHashSet
;
14 use rustc_target
::spec
::abi
::Abi
;
17 use crate::clean
::{self, PrimitiveType}
;
18 use crate::html
::item_type
::ItemType
;
19 use crate::html
::render
::{self, cache, CURRENT_DEPTH}
;
22 fn print(self, buffer
: &mut Buffer
);
26 where F
: FnOnce(&mut Buffer
),
28 fn print(self, buffer
: &mut Buffer
) {
33 impl Print
for String
{
34 fn print(self, buffer
: &mut Buffer
) {
35 buffer
.write_str(&self);
39 impl Print
for &'_
str {
40 fn print(self, buffer
: &mut Buffer
) {
41 buffer
.write_str(self);
45 #[derive(Debug, Clone)]
52 crate fn empty_from(v
: &Buffer
) -> Buffer
{
55 buffer
: String
::new(),
59 crate fn html() -> Buffer
{
62 buffer
: String
::new(),
66 crate fn new() -> Buffer
{
69 buffer
: String
::new(),
73 crate fn is_empty(&self) -> bool
{
74 self.buffer
.is_empty()
77 crate fn into_inner(self) -> String
{
81 crate fn insert_str(&mut self, idx
: usize, s
: &str) {
82 self.buffer
.insert_str(idx
, s
);
85 crate fn push_str(&mut self, s
: &str) {
86 self.buffer
.push_str(s
);
89 // Intended for consumption by write! and writeln! (std::fmt) but without
90 // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
92 crate fn write_str(&mut self, s
: &str) {
93 self.buffer
.push_str(s
);
96 // Intended for consumption by write! and writeln! (std::fmt) but without
97 // the fmt::Result return type imposed by fmt::Write (and avoiding the trait
99 crate fn write_fmt(&mut self, v
: fmt
::Arguments
<'_
>) {
101 self.buffer
.write_fmt(v
).unwrap();
104 crate fn to_display
<T
: Print
>(mut self, t
: T
) -> String
{
109 crate fn from_display
<T
: std
::fmt
::Display
>(&mut self, t
: T
) {
111 write
!(self, "{}", t
);
113 write
!(self, "{:#}", t
);
117 crate fn is_for_html(&self) -> bool
{
122 /// Wrapper struct for properly emitting a function or method declaration.
123 pub struct Function
<'a
> {
124 /// The declaration to emit.
125 pub decl
: &'a clean
::FnDecl
,
126 /// The length of the function header and name. In other words, the number of characters in the
127 /// function declaration up to but not including the parentheses.
129 /// Used to determine line-wrapping.
130 pub header_len
: usize,
131 /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
133 /// Whether the function is async or not.
134 pub asyncness
: hir
::IsAsync
,
137 /// Wrapper struct for emitting a where-clause from Generics.
138 pub struct WhereClause
<'a
>{
139 /// The Generics from which to emit a where-clause.
140 pub gens
: &'a clean
::Generics
,
141 /// The number of spaces to indent each line with.
143 /// Whether the where-clause needs to add a comma and newline after the last bound.
144 pub end_newline
: bool
,
147 fn comma_sep
<T
: fmt
::Display
>(items
: impl Iterator
<Item
=T
>) -> impl fmt
::Display
{
148 display_fn(move |f
| {
149 for (i
, item
) in items
.enumerate() {
150 if i
!= 0 { write!(f, ", ")?; }
151 fmt
::Display
::fmt(&item
, f
)?
;
157 crate fn print_generic_bounds(bounds
: &[clean
::GenericBound
]) -> impl fmt
::Display
+ '_
{
158 display_fn(move |f
| {
159 let mut bounds_dup
= FxHashSet
::default();
161 for (i
, bound
) in bounds
.iter().filter(|b
| {
162 bounds_dup
.insert(b
.print().to_string())
167 fmt
::Display
::fmt(&bound
.print(), f
)?
;
173 impl clean
::GenericParamDef
{
174 crate fn print(&self) -> impl fmt
::Display
+ '_
{
175 display_fn(move |f
| {
177 clean
::GenericParamDefKind
::Lifetime
=> write
!(f
, "{}", self.name
),
178 clean
::GenericParamDefKind
::Type { ref bounds, ref default, .. }
=> {
179 f
.write_str(&self.name
)?
;
181 if !bounds
.is_empty() {
183 write
!(f
, ": {:#}", print_generic_bounds(bounds
))?
;
185 write
!(f
, ": {}", print_generic_bounds(bounds
))?
;
189 if let Some(ref ty
) = default {
191 write
!(f
, " = {:#}", ty
.print())?
;
193 write
!(f
, " = {}", ty
.print())?
;
199 clean
::GenericParamDefKind
::Const { ref ty, .. }
=> {
200 f
.write_str("const ")?
;
201 f
.write_str(&self.name
)?
;
204 write
!(f
, ": {:#}", ty
.print())
206 write
!(f
, ": {}", ty
.print())
214 impl clean
::Generics
{
215 crate fn print(&self) -> impl fmt
::Display
+ '_
{
216 display_fn(move |f
| {
217 let real_params
= self.params
219 .filter(|p
| !p
.is_synthetic_type_param())
220 .collect
::<Vec
<_
>>();
221 if real_params
.is_empty() {
225 write
!(f
, "<{:#}>", comma_sep(real_params
.iter().map(|g
| g
.print())))
227 write
!(f
, "<{}>", comma_sep(real_params
.iter().map(|g
| g
.print())))
233 impl<'a
> fmt
::Display
for WhereClause
<'a
> {
234 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
235 let &WhereClause { gens, indent, end_newline }
= self;
236 if gens
.where_predicates
.is_empty() {
239 let mut clause
= String
::new();
241 clause
.push_str(" where");
244 clause
.push_str(" <span class=\"where fmt-newline\">where");
246 clause
.push_str(" <span class=\"where\">where");
249 for (i
, pred
) in gens
.where_predicates
.iter().enumerate() {
253 clause
.push_str("<br>");
257 &clean
::WherePredicate
::BoundPredicate { ref ty, ref bounds }
=> {
260 clause
.push_str(&format
!("{:#}: {:#}",
261 ty
.print(), print_generic_bounds(bounds
)));
263 clause
.push_str(&format
!("{}: {}",
264 ty
.print(), print_generic_bounds(bounds
)));
267 &clean
::WherePredicate
::RegionPredicate { ref lifetime, ref bounds }
=> {
268 clause
.push_str(&format
!("{}: {}",
271 .map(|b
| b
.print().to_string())
275 &clean
::WherePredicate
::EqPredicate { ref lhs, ref rhs }
=> {
277 clause
.push_str(&format
!("{:#} == {:#}", lhs
.print(), rhs
.print()));
279 clause
.push_str(&format
!("{} == {}", lhs
.print(), rhs
.print()));
284 if i
< gens
.where_predicates
.len() - 1 || end_newline
{
290 // add a space so stripping <br> tags and breaking spaces still renders properly
294 clause
.push_str(" ");
299 clause
.push_str("</span>");
300 let padding
= " ".repeat(indent
+ 4);
301 clause
= clause
.replace("<br>", &format
!("<br>{}", padding
));
302 clause
.insert_str(0, &" ".repeat(indent
.saturating_sub(1)));
304 clause
.insert_str(0, "<br>");
307 write
!(f
, "{}", clause
)
311 impl clean
::Lifetime
{
312 crate fn print(&self) -> &str {
317 impl clean
::Constant
{
318 crate fn print(&self) -> &str {
323 impl clean
::PolyTrait
{
324 fn print(&self) -> impl fmt
::Display
+ '_
{
325 display_fn(move |f
| {
326 if !self.generic_params
.is_empty() {
328 write
!(f
, "for<{:#}> ",
329 comma_sep(self.generic_params
.iter().map(|g
| g
.print())))?
;
331 write
!(f
, "for<{}> ",
332 comma_sep(self.generic_params
.iter().map(|g
| g
.print())))?
;
336 write
!(f
, "{:#}", self.trait_
.print())
338 write
!(f
, "{}", self.trait_
.print())
344 impl clean
::GenericBound
{
345 crate fn print(&self) -> impl fmt
::Display
+ '_
{
346 display_fn(move |f
| {
348 clean
::GenericBound
::Outlives(lt
) => {
349 write
!(f
, "{}", lt
.print())
351 clean
::GenericBound
::TraitBound(ty
, modifier
) => {
352 let modifier_str
= match modifier
{
353 hir
::TraitBoundModifier
::None
=> "",
354 hir
::TraitBoundModifier
::Maybe
=> "?",
357 write
!(f
, "{}{:#}", modifier_str
, ty
.print())
359 write
!(f
, "{}{}", modifier_str
, ty
.print())
367 impl clean
::GenericArgs
{
368 fn print(&self) -> impl fmt
::Display
+ '_
{
369 display_fn(move |f
| {
371 clean
::GenericArgs
::AngleBracketed { ref args, ref bindings }
=> {
372 if !args
.is_empty() || !bindings
.is_empty() {
376 f
.write_str("<")?
;
378 let mut comma
= false;
385 write
!(f
, "{:#}", arg
.print())?
;
387 write
!(f
, "{}", arg
.print())?
;
390 for binding
in bindings
{
396 write
!(f
, "{:#}", binding
.print())?
;
398 write
!(f
, "{}", binding
.print())?
;
404 f
.write_str(">")?
;
408 clean
::GenericArgs
::Parenthesized { ref inputs, ref output }
=> {
410 let mut comma
= false;
417 write
!(f
, "{:#}", ty
.print())?
;
419 write
!(f
, "{}", ty
.print())?
;
423 if let Some(ref ty
) = *output
{
425 write
!(f
, " -> {:#}", ty
.print())?
;
427 write
!(f
, " -> {}", ty
.print())?
;
437 impl clean
::PathSegment
{
438 crate fn print(&self) -> impl fmt
::Display
+ '_
{
439 display_fn(move |f
| {
440 f
.write_str(&self.name
)?
;
442 write
!(f
, "{:#}", self.args
.print())
444 write
!(f
, "{}", self.args
.print())
451 crate fn print(&self) -> impl fmt
::Display
+ '_
{
452 display_fn(move |f
| {
457 for (i
, seg
) in self.segments
.iter().enumerate() {
462 write
!(f
, "{:#}", seg
.print())?
;
464 write
!(f
, "{}", seg
.print())?
;
472 pub fn href(did
: DefId
) -> Option
<(String
, ItemType
, Vec
<String
>)> {
474 if !did
.is_local() && !cache
.access_levels
.is_public(did
) {
478 let depth
= CURRENT_DEPTH
.with(|l
| l
.get());
479 let (fqp
, shortty
, mut url
) = match cache
.paths
.get(&did
) {
480 Some(&(ref fqp
, shortty
)) => {
481 (fqp
, shortty
, "../".repeat(depth
))
484 let &(ref fqp
, shortty
) = cache
.external_paths
.get(&did
)?
;
485 (fqp
, shortty
, match cache
.extern_locations
[&did
.krate
] {
486 (.., render
::Remote(ref s
)) => s
.to_string(),
487 (.., render
::Local
) => "../".repeat(depth
),
488 (.., render
::Unknown
) => return None
,
492 for component
in &fqp
[..fqp
.len() - 1] {
493 url
.push_str(component
);
497 ItemType
::Module
=> {
498 url
.push_str(fqp
.last().unwrap());
499 url
.push_str("/index.html");
502 url
.push_str(shortty
.as_str());
504 url
.push_str(fqp
.last().unwrap());
505 url
.push_str(".html");
508 Some((url
, shortty
, fqp
.to_vec()))
511 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
512 /// rendering function with the necessary arguments for linking to a local path.
513 fn resolved_path(w
: &mut fmt
::Formatter
<'_
>, did
: DefId
, path
: &clean
::Path
,
514 print_all
: bool
, use_absolute
: bool
) -> fmt
::Result
{
515 let last
= path
.segments
.last().unwrap();
518 for seg
in &path
.segments
[..path
.segments
.len() - 1] {
519 write
!(w
, "{}::", seg
.name
)?
;
523 write
!(w
, "{}{:#}", &last
.name
, last
.args
.print())?
;
525 let path
= if use_absolute
{
526 if let Some((_
, _
, fqp
)) = href(did
) {
528 fqp
[..fqp
.len() - 1].join("::"),
529 anchor(did
, fqp
.last().unwrap()))
531 last
.name
.to_string()
534 anchor(did
, &last
.name
).to_string()
536 write
!(w
, "{}{}", path
, last
.args
.print())?
;
541 fn primitive_link(f
: &mut fmt
::Formatter
<'_
>,
542 prim
: clean
::PrimitiveType
,
543 name
: &str) -> fmt
::Result
{
545 let mut needs_termination
= false;
547 match m
.primitive_locations
.get(&prim
) {
548 Some(&def_id
) if def_id
.is_local() => {
549 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
550 let len
= if len
== 0 {0}
else {len - 1}
;
551 write
!(f
, "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
554 needs_termination
= true;
557 let loc
= match m
.extern_locations
[&def_id
.krate
] {
558 (ref cname
, _
, render
::Remote(ref s
)) => {
559 Some((cname
, s
.to_string()))
561 (ref cname
, _
, render
::Local
) => {
562 let len
= CURRENT_DEPTH
.with(|s
| s
.get());
563 Some((cname
, "../".repeat(len
)))
565 (.., render
::Unknown
) => None
,
567 if let Some((cname
, root
)) = loc
{
568 write
!(f
, "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
572 needs_termination
= true;
578 write
!(f
, "{}", name
)?
;
579 if needs_termination
{
585 /// Helper to render type parameters
586 fn tybounds(param_names
: &Option
<Vec
<clean
::GenericBound
>>) -> impl fmt
::Display
+ '_
{
587 display_fn(move |f
| {
589 Some(ref params
) => {
590 for param
in params
{
592 fmt
::Display
::fmt(¶m
.print(), f
)?
;
601 pub fn anchor(did
: DefId
, text
: &str) -> impl fmt
::Display
+ '_
{
602 display_fn(move |f
| {
603 if let Some((url
, short_ty
, fqp
)) = href(did
) {
604 write
!(f
, r
#"<a class="{}" href="{}" title="{} {}">{}</a>"#,
605 short_ty
, url
, short_ty
, fqp
.join("::"), text
)
607 write
!(f
, "{}", text
)
612 fn fmt_type(t
: &clean
::Type
, f
: &mut fmt
::Formatter
<'_
>, use_absolute
: bool
) -> fmt
::Result
{
614 clean
::Generic(ref name
) => {
617 clean
::ResolvedPath{ did, ref param_names, ref path, is_generic }
=> {
618 if param_names
.is_some() {
619 f
.write_str("dyn ")?
;
621 // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
622 resolved_path(f
, did
, path
, is_generic
, use_absolute
)?
;
623 fmt
::Display
::fmt(&tybounds(param_names
), f
)
625 clean
::Infer
=> write
!(f
, "_"),
626 clean
::Primitive(prim
) => primitive_link(f
, prim
, prim
.as_str()),
627 clean
::BareFunction(ref decl
) => {
629 write
!(f
, "{}{:#}fn{:#}{:#}",
630 decl
.unsafety
.print_with_space(),
631 print_abi_with_space(decl
.abi
),
632 decl
.print_generic_params(),
636 decl
.unsafety
.print_with_space(), print_abi_with_space(decl
.abi
))?
;
637 primitive_link(f
, PrimitiveType
::Fn
, "fn")?
;
638 write
!(f
, "{}{}", decl
.print_generic_params(), decl
.decl
.print())
641 clean
::Tuple(ref typs
) => {
643 &[] => primitive_link(f
, PrimitiveType
::Unit
, "()"),
645 primitive_link(f
, PrimitiveType
::Tuple
, "(")?
;
646 // Carry `f.alternate()` into this display w/o branching manually.
647 fmt
::Display
::fmt(&one
.print(), f
)?
;
648 primitive_link(f
, PrimitiveType
::Tuple
, ",)")
651 primitive_link(f
, PrimitiveType
::Tuple
, "(")?
;
652 for (i
, item
) in many
.iter().enumerate() {
653 if i
!= 0 { write!(f, ", ")?; }
654 fmt
::Display
::fmt(&item
.print(), f
)?
;
656 primitive_link(f
, PrimitiveType
::Tuple
, ")")
660 clean
::Slice(ref t
) => {
661 primitive_link(f
, PrimitiveType
::Slice
, "[")?
;
662 fmt
::Display
::fmt(&t
.print(), f
)?
;
663 primitive_link(f
, PrimitiveType
::Slice
, "]")
665 clean
::Array(ref t
, ref n
) => {
666 primitive_link(f
, PrimitiveType
::Array
, "[")?
;
667 fmt
::Display
::fmt(&t
.print(), f
)?
;
668 primitive_link(f
, PrimitiveType
::Array
, &format
!("; {}]", n
))
670 clean
::Never
=> primitive_link(f
, PrimitiveType
::Never
, "!"),
671 clean
::RawPointer(m
, ref t
) => {
673 clean
::Immutable
=> "const",
674 clean
::Mutable
=> "mut",
677 clean
::Generic(_
) | clean
::ResolvedPath {is_generic: true, ..}
=> {
679 primitive_link(f
, clean
::PrimitiveType
::RawPointer
,
680 &format
!("*{} {:#}", m
, t
.print()))
682 primitive_link(f
, clean
::PrimitiveType
::RawPointer
,
683 &format
!("*{} {}", m
, t
.print()))
687 primitive_link(f
, clean
::PrimitiveType
::RawPointer
, &format
!("*{} ", m
))?
;
688 fmt
::Display
::fmt(&t
.print(), f
)
692 clean
::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty}
=> {
694 Some(l
) => format
!("{} ", l
.print()),
697 let m
= mutability
.print_with_space();
698 let amp
= if f
.alternate() {
704 clean
::Slice(ref bt
) => { // `BorrowedRef{ ... Slice(T) }` is `
&[T
]`
706 clean
::Generic(_
) => {
708 primitive_link(f
, PrimitiveType
::Slice
,
709 &format
!("{}{}{}[{:#}]", amp
, lt
, m
, bt
.print()))
711 primitive_link(f
, PrimitiveType
::Slice
,
712 &format
!("{}{}{}[{}]", amp
, lt
, m
, bt
.print()))
716 primitive_link(f
, PrimitiveType
::Slice
,
717 &format
!("{}{}{}[", amp
, lt
, m
))?
;
719 write
!(f
, "{:#}", bt
.print())?
;
721 write
!(f
, "{}", bt
.print())?
;
723 primitive_link(f
, PrimitiveType
::Slice
, "]")
727 clean
::ResolvedPath { param_names: Some(ref v), .. }
if !v
.is_empty() => {
728 write
!(f
, "{}{}{}(", amp
, lt
, m
)?
;
729 fmt_type(&ty
, f
, use_absolute
)?
;
732 clean
::Generic(..) => {
733 primitive_link(f
, PrimitiveType
::Reference
,
734 &format
!("{}{}{}", amp
, lt
, m
))?
;
735 fmt_type(&ty
, f
, use_absolute
)
738 write
!(f
, "{}{}{}", amp
, lt
, m
)?
;
739 fmt_type(&ty
, f
, use_absolute
)
743 clean
::ImplTrait(ref bounds
) => {
745 write
!(f
, "impl {:#}", print_generic_bounds(bounds
))
747 write
!(f
, "impl {}", print_generic_bounds(bounds
))
750 clean
::QPath { ref name, ref self_type, ref trait_ }
=> {
751 let should_show_cast
= match *trait_
{
752 box clean
::ResolvedPath { ref path, .. }
=> {
753 !path
.segments
.is_empty() && !self_type
.is_self_type()
758 if should_show_cast
{
759 write
!(f
, "<{:#} as {:#}>::", self_type
.print(), trait_
.print())?
761 write
!(f
, "{:#}::", self_type
.print())?
764 if should_show_cast
{
765 write
!(f
, "<{} as {}>::", self_type
.print(), trait_
.print())?
767 write
!(f
, "{}::", self_type
.print())?
771 // It's pretty unsightly to look at `<A as B>::C` in output, and
772 // we've got hyperlinking on our side, so try to avoid longer
773 // notation as much as possible by making `C` a hyperlink to trait
774 // `B` to disambiguate.
776 // FIXME: this is still a lossy conversion and there should probably
777 // be a better way of representing this in general? Most of
778 // the ugliness comes from inlining across crates where
779 // everything comes in as a fully resolved QPath (hard to
781 box clean
::ResolvedPath { did, ref param_names, .. }
=> {
783 Some((ref url
, _
, ref path
)) if !f
.alternate() => {
785 "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
786 title=\"type {path}::{name}\">{name}</a>",
788 shortty
= ItemType
::AssocType
,
790 path
= path
.join("::"))?
;
792 _
=> write
!(f
, "{}", name
)?
,
795 // FIXME: `param_names` are not rendered, and this seems bad?
800 write
!(f
, "{}", name
)
808 crate fn print(&self) -> impl fmt
::Display
+ '_
{
809 display_fn(move |f
| {
810 fmt_type(self, f
, false)
816 crate fn print(&self) -> impl fmt
::Display
+ '_
{
817 self.print_inner(true, false)
824 ) -> impl fmt
::Display
+ '_
{
825 display_fn(move |f
| {
827 write
!(f
, "impl{:#} ", self.generics
.print())?
;
829 write
!(f
, "impl{} ", self.generics
.print())?
;
832 if let Some(ref ty
) = self.trait_
{
833 if self.polarity
== Some(clean
::ImplPolarity
::Negative
) {
838 fmt
::Display
::fmt(&ty
.print(), f
)?
;
841 clean
::ResolvedPath { param_names: None, path, is_generic: false, .. }
=> {
842 let last
= path
.segments
.last().unwrap();
843 fmt
::Display
::fmt(&last
.name
, f
)?
;
844 fmt
::Display
::fmt(&last
.args
.print(), f
)?
;
852 if let Some(ref ty
) = self.blanket_impl
{
853 fmt_type(ty
, f
, use_absolute
)?
;
855 fmt_type(&self.for_
, f
, use_absolute
)?
;
858 fmt
::Display
::fmt(&WhereClause
{
859 gens
: &self.generics
,
868 // The difference from above is that trait is not hyperlinked.
869 pub fn fmt_impl_for_trait_page(i
: &clean
::Impl
,
871 use_absolute
: bool
) {
872 f
.from_display(i
.print_inner(false, use_absolute
))
875 impl clean
::Arguments
{
876 crate fn print(&self) -> impl fmt
::Display
+ '_
{
877 display_fn(move |f
| {
878 for (i
, input
) in self.values
.iter().enumerate() {
879 if !input
.name
.is_empty() {
880 write
!(f
, "{}: ", input
.name
)?
;
883 write
!(f
, "{:#}", input
.type_
.print())?
;
885 write
!(f
, "{}", input
.type_
.print())?
;
887 if i
+ 1 < self.values
.len() { write!(f, ", ")?; }
894 impl clean
::FunctionRetTy
{
895 crate fn print(&self) -> impl fmt
::Display
+ '_
{
896 display_fn(move |f
| {
898 clean
::Return(clean
::Tuple(tys
)) if tys
.is_empty() => Ok(()),
899 clean
::Return(ty
) if f
.alternate() => write
!(f
, " -> {:#}", ty
.print()),
900 clean
::Return(ty
) => write
!(f
, " -> {}", ty
.print()),
901 clean
::DefaultReturn
=> Ok(()),
907 impl clean
::BareFunctionDecl
{
908 fn print_generic_params(&self) -> impl fmt
::Display
+ '_
{
909 comma_sep(self.generic_params
.iter().map(|g
| g
.print()))
914 crate fn print(&self) -> impl fmt
::Display
+ '_
{
915 display_fn(move |f
| {
916 let ellipsis
= if self.c_variadic { ", ..." }
else { "" }
;
919 "({args:#}{ellipsis}){arrow:#}",
920 args
= self.inputs
.print(), ellipsis
= ellipsis
, arrow
= self.output
.print())
923 "({args}{ellipsis}){arrow}",
924 args
= self.inputs
.print(), ellipsis
= ellipsis
, arrow
= self.output
.print())
932 crate fn print(&self) -> impl fmt
::Display
+ '_
{
933 display_fn(move |f
| {
934 let &Function { decl, header_len, indent, asyncness }
= self;
935 let amp
= if f
.alternate() { "&" }
else { "&" }
;
936 let mut args
= String
::new();
937 let mut args_plain
= String
::new();
938 for (i
, input
) in decl
.inputs
.values
.iter().enumerate() {
940 args
.push_str("<br>");
943 if let Some(selfty
) = input
.to_self() {
945 clean
::SelfValue
=> {
946 args
.push_str("self");
947 args_plain
.push_str("self");
949 clean
::SelfBorrowed(Some(ref lt
), mtbl
) => {
951 &format
!("{}{} {}self", amp
, lt
.print(), mtbl
.print_with_space()));
953 &format
!("&{} {}self", lt
.print(), mtbl
.print_with_space()));
955 clean
::SelfBorrowed(None
, mtbl
) => {
956 args
.push_str(&format
!("{}{}self", amp
, mtbl
.print_with_space()));
957 args_plain
.push_str(&format
!("&{}self", mtbl
.print_with_space()));
959 clean
::SelfExplicit(ref typ
) => {
961 args
.push_str(&format
!("self: {:#}", typ
.print()));
963 args
.push_str(&format
!("self: {}", typ
.print()));
965 args_plain
.push_str(&format
!("self: {:#}", typ
.print()));
970 args
.push_str(" <br>");
971 args_plain
.push_str(" ");
973 if !input
.name
.is_empty() {
974 args
.push_str(&format
!("{}: ", input
.name
));
975 args_plain
.push_str(&format
!("{}: ", input
.name
));
979 args
.push_str(&format
!("{:#}", input
.type_
.print()));
981 args
.push_str(&input
.type_
.print().to_string());
983 args_plain
.push_str(&format
!("{:#}", input
.type_
.print()));
985 if i
+ 1 < decl
.inputs
.values
.len() {
987 args_plain
.push('
,'
);
991 let mut args_plain
= format
!("({})", args_plain
);
994 args
.push_str(",<br> ...");
995 args_plain
.push_str(", ...");
998 let output
= if let hir
::IsAsync
::Async
= asyncness
{
999 Cow
::Owned(decl
.sugared_async_return_type())
1001 Cow
::Borrowed(&decl
.output
)
1004 let arrow_plain
= format
!("{:#}", &output
.print());
1005 let arrow
= if f
.alternate() {
1006 format
!("{:#}", &output
.print())
1008 output
.print().to_string()
1011 let declaration_len
= header_len
+ args_plain
.len() + arrow_plain
.len();
1012 let output
= if declaration_len
> 80 {
1013 let full_pad
= format
!("<br>{}", " ".repeat(indent
+ 4));
1014 let close_pad
= format
!("<br>{}", " ".repeat(indent
));
1015 format
!("({args}{close}){arrow}",
1016 args
= args
.replace("<br>", &full_pad
),
1020 format
!("({args}){arrow}", args
= args
.replace("<br>", ""), arrow
= arrow
)
1024 write
!(f
, "{}", output
.replace("<br>", "\n"))
1026 write
!(f
, "{}", output
)
1032 impl clean
::Visibility
{
1033 crate fn print_with_space(&self) -> impl fmt
::Display
+ '_
{
1034 display_fn(move |f
| {
1036 clean
::Public
=> f
.write_str("pub "),
1037 clean
::Inherited
=> Ok(()),
1038 clean
::Visibility
::Crate
=> write
!(f
, "pub(crate) "),
1039 clean
::Visibility
::Restricted(did
, ref path
) => {
1040 f
.write_str("pub(")?
;
1041 if path
.segments
.len() != 1
1042 || (path
.segments
[0].name
!= "self" && path
.segments
[0].name
!= "super")
1044 f
.write_str("in ")?
;
1046 resolved_path(f
, did
, path
, true, false)?
;
1054 crate trait PrintWithSpace
{
1055 fn print_with_space(&self) -> &str;
1058 impl PrintWithSpace
for hir
::Unsafety
{
1059 fn print_with_space(&self) -> &str {
1061 hir
::Unsafety
::Unsafe
=> "unsafe ",
1062 hir
::Unsafety
::Normal
=> ""
1067 impl PrintWithSpace
for hir
::Constness
{
1068 fn print_with_space(&self) -> &str {
1070 hir
::Constness
::Const
=> "const ",
1071 hir
::Constness
::NotConst
=> ""
1076 impl PrintWithSpace
for hir
::IsAsync
{
1077 fn print_with_space(&self) -> &str {
1079 hir
::IsAsync
::Async
=> "async ",
1080 hir
::IsAsync
::NotAsync
=> "",
1085 impl clean
::Import
{
1086 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1087 display_fn(move |f
| {
1089 clean
::Import
::Simple(ref name
, ref src
) => {
1090 if *name
== src
.path
.last_name() {
1091 write
!(f
, "use {};", src
.print())
1093 write
!(f
, "use {} as {};", src
.print(), *name
)
1096 clean
::Import
::Glob(ref src
) => {
1097 if src
.path
.segments
.is_empty() {
1100 write
!(f
, "use {}::*;", src
.print())
1108 impl clean
::ImportSource
{
1109 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1110 display_fn(move |f
| {
1112 Some(did
) => resolved_path(f
, did
, &self.path
, true, false),
1114 for (i
, seg
) in self.path
.segments
.iter().enumerate() {
1118 write
!(f
, "{}", seg
.name
)?
;
1127 impl clean
::TypeBinding
{
1128 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1129 display_fn(move |f
| {
1130 f
.write_str(&self.name
)?
;
1132 clean
::TypeBindingKind
::Equality { ref ty }
=> {
1134 write
!(f
, " = {:#}", ty
.print())?
;
1136 write
!(f
, " = {}", ty
.print())?
;
1139 clean
::TypeBindingKind
::Constraint { ref bounds }
=> {
1140 if !bounds
.is_empty() {
1142 write
!(f
, ": {:#}", print_generic_bounds(bounds
))?
;
1144 write
!(f
, ": {}", print_generic_bounds(bounds
))?
;
1154 impl clean
::Mutability
{
1155 crate fn print_with_space(&self) -> &str {
1157 clean
::Immutable
=> "",
1158 clean
::Mutable
=> "mut ",
1163 crate fn print_abi_with_space(abi
: Abi
) -> impl fmt
::Display
{
1164 display_fn(move |f
| {
1165 let quot
= if f
.alternate() { "\"" }
else { """ }
;
1167 Abi
::Rust
=> Ok(()),
1168 abi
=> write
!(f
, "extern {0}{1}{0} ", quot
, abi
.name()),
1173 crate fn print_default_space
<'a
>(v
: bool
) -> &'a
str {
1181 impl clean
::GenericArg
{
1182 crate fn print(&self) -> impl fmt
::Display
+ '_
{
1183 display_fn(move |f
| {
1185 clean
::GenericArg
::Lifetime(lt
) => fmt
::Display
::fmt(<
.print(), f
),
1186 clean
::GenericArg
::Type(ty
) => fmt
::Display
::fmt(&ty
.print(), f
),
1187 clean
::GenericArg
::Const(ct
) => fmt
::Display
::fmt(&ct
.print(), f
),
1193 crate fn display_fn(
1194 f
: impl FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
,
1195 ) -> impl fmt
::Display
{
1196 WithFormatter(Cell
::new(Some(f
)))
1199 struct WithFormatter
<F
>(Cell
<Option
<F
>>);
1201 impl<F
> fmt
::Display
for WithFormatter
<F
>
1202 where F
: FnOnce(&mut fmt
::Formatter
<'_
>) -> fmt
::Result
,
1204 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1205 (self.0.take()).unwrap()(f
)