term_rustdoc/type_name/
mod.rs1use crate::util::{xformat, XString};
2use itertools::intersperse;
3use rustdoc_types::{DynTrait, Path, PolyTrait, Type};
4use std::fmt::Write;
5
6mod short_or_long;
7pub use short_or_long::{long_path, short_path};
8
9mod generic;
10pub use generic::generics;
11
12mod funcion;
13pub(crate) use funcion::{fn_decl, fn_header};
14
15trait TypeName: Copy + FnOnce(&Type) -> XString {}
16impl<F> TypeName for F where F: Copy + FnOnce(&Type) -> XString {}
17trait ResolvePath: Copy + FnOnce(&Path) -> XString {}
18impl<F> ResolvePath for F where F: Copy + FnOnce(&Path) -> XString {}
19
20trait FindName {
21 fn type_name() -> impl TypeName;
22 fn resolve_path() -> impl ResolvePath;
23 }
27
28struct Short;
29
30impl FindName for Short {
31 fn type_name() -> impl TypeName {
32 short
33 }
34 fn resolve_path() -> impl ResolvePath {
35 short_path
36 }
37}
38
39struct Long;
40
41impl FindName for Long {
42 fn type_name() -> impl TypeName {
43 long
44 }
45 fn resolve_path() -> impl ResolvePath {
46 long_path
47 }
48}
49
50const COMMA: XString = XString::new_inline(", ");
51const PLUS: XString = XString::new_inline(" + ");
52const INFER: XString = XString::new_inline("_");
53const COLON: &str = ": ";
54
55fn typename<Kind: FindName>(ty: &Type) -> XString {
56 let resolve_path = Kind::resolve_path();
57 match ty {
58 Type::ResolvedPath(p) => resolve_path(p),
59 Type::Generic(t) | Type::Primitive(t) => t.as_str().into(),
60 Type::BorrowedRef {
61 lifetime,
62 mutable,
63 type_,
64 } => borrow_ref::<Kind>(type_, lifetime, mutable),
65 Type::RawPointer { mutable, type_ } => xformat!(
66 "*{} {}",
67 if *mutable { "mut" } else { "const" },
68 typename::<Kind>(type_)
69 ),
70 Type::QualifiedPath {
71 name,
72 args,
73 self_type,
74 trait_,
75 } => {
76 let self_ = typename::<Kind>(self_type);
77 if let Some(trait_) = trait_.as_ref().map(resolve_path).filter(|s| !s.is_empty()) {
78 if let Some(args) = generic::generic_args::<Kind>(args) {
79 xformat!("<{self_} as {trait_}>::{name}{args}")
80 } else {
81 xformat!("<{self_} as {trait_}>::{name}")
82 }
83 } else if let Some(args) = generic::generic_args::<Kind>(args) {
84 xformat!("{self_}::{name}{args}")
85 } else {
86 xformat!("{self_}::{name}")
87 }
88 }
89 Type::Slice(ty) => typename::<Kind>(ty),
90 Type::DynTrait(poly) => dyn_trait::<Kind>(poly),
91 Type::ImplTrait(b) => xformat!(
92 "impl {}",
93 generic::generic_bound_for_slice::<Kind>(b).unwrap_or_default()
94 ),
95 Type::Tuple(v) => {
96 let iter = v.iter().map(|ty| typename::<Kind>(ty));
97 let ty = XString::from_iter(intersperse(iter, COMMA));
98 xformat!("({ty})")
99 }
100 Type::Array { type_, len } => {
101 let ty = typename::<Kind>(type_);
102 xformat!("[{ty}; {len}]")
103 }
104 Type::FunctionPointer(f) => funcion::fn_pointer(f),
105 Type::Infer => INFER,
106 }
107}
108
109fn borrow_ref<Kind: FindName>(type_: &Type, lifetime: &Option<String>, mutable: &bool) -> XString {
110 let mut buf = match (lifetime, mutable) {
111 (None, false) => xformat!("&"),
112 (None, true) => xformat!("&mut "),
113 (Some(life), false) => xformat!("&{life} "),
114 (Some(life), true) => xformat!("&{life} mut "),
115 };
116 if let Type::DynTrait(d) = type_ {
117 let (ty, add) = parenthesized_type::<Kind>(d);
118 if add {
119 write!(buf, "({ty})").unwrap();
120 } else {
121 buf.push_str(&ty);
122 }
123 } else {
124 buf.push_str(&typename::<Kind>(type_));
125 }
126 buf
127}
128
129pub fn long(ty: &Type) -> XString {
131 typename::<Long>(ty)
132}
133
134pub fn short(ty: &Type) -> XString {
136 typename::<Short>(ty)
137}
138
139fn dyn_trait<Kind: FindName>(DynTrait { traits, lifetime }: &DynTrait) -> XString {
140 let resolve_path = Kind::resolve_path();
141 let iter = traits.iter().map(
142 |PolyTrait {
143 trait_,
144 generic_params,
145 }| {
146 let hrtb = generic::generic_param_def_for_slice::<Kind>(generic_params);
147 let [sep, hrtb] = if let Some(b) = &hrtb {
148 [" ", b]
149 } else {
150 [""; 2]
151 };
152 let ty = resolve_path(trait_);
153 xformat!("{hrtb}{sep}{ty}")
154 },
155 );
156 let path = intersperse(iter, PLUS).collect::<XString>();
157 lifetime.as_deref().map_or_else(
158 || xformat!("dyn {path}"),
159 |life| xformat!("dyn {life} + {path}"),
160 )
161}
162
163fn parenthesized_type<Kind: FindName>(d: &DynTrait) -> (XString, bool) {
169 let s = dyn_trait::<Kind>(d);
170 (s, d.traits.len() + d.lifetime.is_some() as usize > 1)
171}