Skip to main content

rustdoc/formats/
item_type.rs

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