rustdoc/formats/
item_type.rs

1//! Item types.
2
3use std::fmt;
4
5use rustc_hir::def::{CtorOf, DefKind, MacroKinds};
6use rustc_span::hygiene::MacroKind;
7use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
8
9use crate::clean;
10
11/// Item type. Corresponds to `clean::ItemEnum` variants.
12///
13/// The search index uses item types encoded as smaller numbers which equal to
14/// discriminants. JavaScript then is used to decode them into the original value.
15/// Consequently, every change to this type should be synchronized to
16/// the `itemTypes` mapping table in `html/static/js/search.js`.
17///
18/// The search engine in search.js also uses item type numbers as a tie breaker when
19/// sorting results. Keywords and primitives are given first because we want them to be easily
20/// found by new users who don't know about advanced features like type filters. The rest are
21/// mostly in an arbitrary order, but it's easier to test the search engine when
22/// it's deterministic, and these are strictly finer-grained than language namespaces, so
23/// using the path and the item type together to sort ensures that search sorting is stable.
24///
25/// In addition, code in `html::render` uses this enum to generate CSS classes, page prefixes, and
26/// module headings. If you are adding to this enum and want to ensure that the sidebar also prints
27/// a heading, edit the listing in `html/render.rs`, function `sidebar_module`. This uses an
28/// ordering based on a helper function inside `item_module`, in the same file.
29#[derive(Copy, PartialEq, Eq, Hash, Clone, Debug, PartialOrd, Ord)]
30#[repr(u8)]
31pub(crate) enum ItemType {
32    Keyword = 0,
33    Primitive = 1,
34    Module = 2,
35    ExternCrate = 3,
36    Import = 4,
37    Struct = 5,
38    Enum = 6,
39    Function = 7,
40    TypeAlias = 8,
41    Static = 9,
42    Trait = 10,
43    Impl = 11,
44    TyMethod = 12,
45    Method = 13,
46    StructField = 14,
47    Variant = 15,
48    Macro = 16,
49    AssocType = 17,
50    Constant = 18,
51    AssocConst = 19,
52    Union = 20,
53    ForeignType = 21,
54    // OpaqueTy used to be here, but it was removed in #127276
55    ProcAttribute = 23,
56    ProcDerive = 24,
57    TraitAlias = 25,
58    // This number is reserved for use in JavaScript
59    // Generic = 26,
60}
61
62impl Serialize for ItemType {
63    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
64    where
65        S: Serializer,
66    {
67        (*self as u8).serialize(serializer)
68    }
69}
70
71impl<'de> Deserialize<'de> for ItemType {
72    fn deserialize<D>(deserializer: D) -> Result<ItemType, D::Error>
73    where
74        D: Deserializer<'de>,
75    {
76        struct ItemTypeVisitor;
77        impl<'de> de::Visitor<'de> for ItemTypeVisitor {
78            type Value = ItemType;
79            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80                write!(formatter, "an integer between 0 and 25")
81            }
82            fn visit_u64<E: de::Error>(self, v: u64) -> Result<ItemType, E> {
83                Ok(match v {
84                    0 => ItemType::Keyword,
85                    1 => ItemType::Primitive,
86                    2 => ItemType::Module,
87                    3 => ItemType::ExternCrate,
88                    4 => ItemType::Import,
89                    5 => ItemType::Struct,
90                    6 => ItemType::Enum,
91                    7 => ItemType::Function,
92                    8 => ItemType::TypeAlias,
93                    9 => ItemType::Static,
94                    10 => ItemType::Trait,
95                    11 => ItemType::Impl,
96                    12 => ItemType::TyMethod,
97                    13 => ItemType::Method,
98                    14 => ItemType::StructField,
99                    15 => ItemType::Variant,
100                    16 => ItemType::Macro,
101                    17 => ItemType::AssocType,
102                    18 => ItemType::Constant,
103                    19 => ItemType::AssocConst,
104                    20 => ItemType::Union,
105                    21 => ItemType::ForeignType,
106                    23 => ItemType::ProcAttribute,
107                    24 => ItemType::ProcDerive,
108                    25 => ItemType::TraitAlias,
109                    _ => return Err(E::missing_field("unknown number")),
110                })
111            }
112        }
113        deserializer.deserialize_any(ItemTypeVisitor)
114    }
115}
116
117impl<'a> From<&'a clean::Item> for ItemType {
118    fn from(item: &'a clean::Item) -> ItemType {
119        let kind = match &item.kind {
120            clean::StrippedItem(box item) => item,
121            kind => kind,
122        };
123
124        match kind {
125            clean::ModuleItem(..) => ItemType::Module,
126            clean::ExternCrateItem { .. } => ItemType::ExternCrate,
127            clean::ImportItem(..) => ItemType::Import,
128            clean::StructItem(..) => ItemType::Struct,
129            clean::UnionItem(..) => ItemType::Union,
130            clean::EnumItem(..) => ItemType::Enum,
131            clean::FunctionItem(..) => ItemType::Function,
132            clean::TypeAliasItem(..) => ItemType::TypeAlias,
133            clean::StaticItem(..) => ItemType::Static,
134            clean::ConstantItem(..) => ItemType::Constant,
135            clean::TraitItem(..) => ItemType::Trait,
136            clean::ImplItem(..) => ItemType::Impl,
137            clean::RequiredMethodItem(..) => ItemType::TyMethod,
138            clean::MethodItem(..) => ItemType::Method,
139            clean::StructFieldItem(..) => ItemType::StructField,
140            clean::VariantItem(..) => ItemType::Variant,
141            clean::ForeignFunctionItem(..) => ItemType::Function, // no ForeignFunction
142            clean::ForeignStaticItem(..) => ItemType::Static,     // no ForeignStatic
143            clean::MacroItem(..) => ItemType::Macro,
144            clean::PrimitiveItem(..) => ItemType::Primitive,
145            clean::RequiredAssocConstItem(..)
146            | clean::ProvidedAssocConstItem(..)
147            | clean::ImplAssocConstItem(..) => ItemType::AssocConst,
148            clean::RequiredAssocTypeItem(..) | clean::AssocTypeItem(..) => ItemType::AssocType,
149            clean::ForeignTypeItem => ItemType::ForeignType,
150            clean::KeywordItem => ItemType::Keyword,
151            clean::TraitAliasItem(..) => ItemType::TraitAlias,
152            clean::ProcMacroItem(mac) => match mac.kind {
153                MacroKind::Bang => ItemType::Macro,
154                MacroKind::Attr => ItemType::ProcAttribute,
155                MacroKind::Derive => ItemType::ProcDerive,
156            },
157            clean::StrippedItem(..) => unreachable!(),
158        }
159    }
160}
161
162impl From<DefKind> for ItemType {
163    fn from(other: DefKind) -> Self {
164        Self::from_def_kind(other, None)
165    }
166}
167
168impl ItemType {
169    /// Depending on the parent kind, some variants have a different translation (like a `Method`
170    /// becoming a `TyMethod`).
171    pub(crate) fn from_def_kind(kind: DefKind, parent_kind: Option<DefKind>) -> Self {
172        match kind {
173            DefKind::Enum => Self::Enum,
174            DefKind::Fn => Self::Function,
175            DefKind::Mod => Self::Module,
176            DefKind::Const => Self::Constant,
177            DefKind::Static { .. } => Self::Static,
178            DefKind::Struct => Self::Struct,
179            DefKind::Union => Self::Union,
180            DefKind::Trait => Self::Trait,
181            DefKind::TyAlias => Self::TypeAlias,
182            DefKind::TraitAlias => Self::TraitAlias,
183            DefKind::Macro(MacroKinds::BANG) => ItemType::Macro,
184            DefKind::Macro(MacroKinds::ATTR) => ItemType::ProcAttribute,
185            DefKind::Macro(MacroKinds::DERIVE) => ItemType::ProcDerive,
186            DefKind::Macro(_) => todo!("Handle macros with multiple kinds"),
187            DefKind::ForeignTy => Self::ForeignType,
188            DefKind::Variant => Self::Variant,
189            DefKind::Field => Self::StructField,
190            DefKind::AssocTy => Self::AssocType,
191            DefKind::AssocFn if let Some(DefKind::Trait) = parent_kind => Self::TyMethod,
192            DefKind::AssocFn => Self::Method,
193            DefKind::Ctor(CtorOf::Struct, _) => Self::Struct,
194            DefKind::Ctor(CtorOf::Variant, _) => Self::Variant,
195            DefKind::AssocConst => Self::AssocConst,
196            DefKind::TyParam
197            | DefKind::ConstParam
198            | DefKind::ExternCrate
199            | DefKind::Use
200            | DefKind::ForeignMod
201            | DefKind::AnonConst
202            | DefKind::InlineConst
203            | DefKind::OpaqueTy
204            | DefKind::LifetimeParam
205            | DefKind::GlobalAsm
206            | DefKind::Impl { .. }
207            | DefKind::Closure
208            | DefKind::SyntheticCoroutineBody => Self::ForeignType,
209        }
210    }
211
212    pub(crate) fn as_str(&self) -> &'static str {
213        match self {
214            ItemType::Module => "mod",
215            ItemType::ExternCrate => "externcrate",
216            ItemType::Import => "import",
217            ItemType::Struct => "struct",
218            ItemType::Union => "union",
219            ItemType::Enum => "enum",
220            ItemType::Function => "fn",
221            ItemType::TypeAlias => "type",
222            ItemType::Static => "static",
223            ItemType::Trait => "trait",
224            ItemType::Impl => "impl",
225            ItemType::TyMethod => "tymethod",
226            ItemType::Method => "method",
227            ItemType::StructField => "structfield",
228            ItemType::Variant => "variant",
229            ItemType::Macro => "macro",
230            ItemType::Primitive => "primitive",
231            ItemType::AssocType => "associatedtype",
232            ItemType::Constant => "constant",
233            ItemType::AssocConst => "associatedconstant",
234            ItemType::ForeignType => "foreigntype",
235            ItemType::Keyword => "keyword",
236            ItemType::ProcAttribute => "attr",
237            ItemType::ProcDerive => "derive",
238            ItemType::TraitAlias => "traitalias",
239        }
240    }
241    pub(crate) fn is_method(&self) -> bool {
242        matches!(self, ItemType::Method | ItemType::TyMethod)
243    }
244    pub(crate) fn is_adt(&self) -> bool {
245        matches!(self, ItemType::Struct | ItemType::Union | ItemType::Enum)
246    }
247    /// Keep this the same as isFnLikeTy in search.js
248    pub(crate) fn is_fn_like(&self) -> bool {
249        matches!(self, ItemType::Function | ItemType::Method | ItemType::TyMethod)
250    }
251}
252
253impl fmt::Display for ItemType {
254    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        f.write_str(self.as_str())
256    }
257}