Skip to main content

rustdoc/html/render/
search_index.rs

1pub(crate) mod encode;
2mod serde;
3
4use std::collections::BTreeSet;
5use std::collections::hash_map::Entry;
6use std::path::Path;
7use std::string::FromUtf8Error;
8use std::{io, iter};
9
10use ::serde::de::{self, Deserializer, Error as _};
11use ::serde::ser::{SerializeSeq, Serializer};
12use ::serde::{Deserialize, Serialize};
13use rustc_ast::join_path_syms;
14use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
15use rustc_data_structures::thin_vec::ThinVec;
16use rustc_hir::def_id::LOCAL_CRATE;
17use rustc_hir::find_attr;
18use rustc_middle::ty::TyCtxt;
19use rustc_span::def_id::DefId;
20use rustc_span::sym;
21use rustc_span::symbol::{Symbol, kw};
22use stringdex::internals as stringdex_internals;
23use tracing::instrument;
24
25use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
26use crate::clean::{self, ExternalLocation, utils};
27use crate::config::ShouldMerge;
28use crate::error::Error;
29use crate::formats::cache::{Cache, OrphanImplItem};
30use crate::formats::item_type::ItemType;
31use crate::html::markdown::short_markdown_summary;
32use crate::html::render::{self, IndexItem, IndexItemFunctionType, RenderType, RenderTypeId};
33
34#[derive(Clone, Debug, Default, Deserialize, Serialize)]
35pub(crate) struct SerializedSearchIndex {
36    // data from disk
37    names: Vec<String>,
38    path_data: Vec<Option<PathData>>,
39    entry_data: Vec<Option<EntryData>>,
40    descs: Vec<String>,
41    function_data: Vec<Option<IndexItemFunctionType>>,
42    alias_pointers: Vec<Option<usize>>,
43    // inverted index for concrete types and generics
44    type_data: Vec<Option<TypeData>>,
45    /// inverted index of generics
46    ///
47    /// - The outermost list has one entry per alpha-normalized generic.
48    ///
49    /// - The second layer is sorted by number of types that appear in the
50    ///   type signature. The search engine iterates over these in order from
51    ///   smallest to largest. Functions with less stuff in their type
52    ///   signature are more likely to be what the user wants, because we never
53    ///   show functions that are *missing* parts of the query, so removing..
54    ///
55    /// - The final layer is the list of functions.
56    generic_inverted_index: Vec<Vec<Vec<u32>>>,
57    // generated in-memory backref cache
58    #[serde(skip)]
59    crate_paths_index: FxHashMap<(ItemType, Vec<Symbol>), usize>,
60}
61
62impl SerializedSearchIndex {
63    fn load(doc_root: &Path, resource_suffix: &str) -> Result<SerializedSearchIndex, Error> {
64        let mut names: Vec<String> = Vec::new();
65        let mut path_data: Vec<Option<PathData>> = Vec::new();
66        let mut entry_data: Vec<Option<EntryData>> = Vec::new();
67        let mut descs: Vec<String> = Vec::new();
68        let mut function_data: Vec<Option<IndexItemFunctionType>> = Vec::new();
69        let mut type_data: Vec<Option<TypeData>> = Vec::new();
70        let mut alias_pointers: Vec<Option<usize>> = Vec::new();
71
72        let mut generic_inverted_index: Vec<Vec<Vec<u32>>> = Vec::new();
73
74        match perform_read_strings(resource_suffix, doc_root, "name", &mut names) {
75            Ok(()) => {
76                perform_read_serde(resource_suffix, doc_root, "path", &mut path_data)?;
77                perform_read_serde(resource_suffix, doc_root, "entry", &mut entry_data)?;
78                perform_read_strings(resource_suffix, doc_root, "desc", &mut descs)?;
79                perform_read_serde(resource_suffix, doc_root, "function", &mut function_data)?;
80                perform_read_serde(resource_suffix, doc_root, "type", &mut type_data)?;
81                perform_read_serde(resource_suffix, doc_root, "alias", &mut alias_pointers)?;
82                perform_read_postings(
83                    resource_suffix,
84                    doc_root,
85                    "generic_inverted_index",
86                    &mut generic_inverted_index,
87                )?;
88            }
89            Err(_) => {
90                names.clear();
91            }
92        }
93        fn perform_read_strings(
94            resource_suffix: &str,
95            doc_root: &Path,
96            column_name: &str,
97            column: &mut Vec<String>,
98        ) -> Result<(), Error> {
99            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
100            let column_path = doc_root.join(format!("search.index/{column_name}/"));
101
102            let mut consume = |_, cell: &[u8]| {
103                column.push(String::from_utf8(cell.to_vec())?);
104                Ok::<_, FromUtf8Error>(())
105            };
106
107            stringdex_internals::read_data_from_disk_column(
108                root_path,
109                column_name.as_bytes(),
110                column_path.clone(),
111                &mut consume,
112            )
113            .map_err(|error| Error {
114                file: column_path,
115                error: format!("failed to read column from disk: {error}"),
116            })
117        }
118        fn perform_read_serde(
119            resource_suffix: &str,
120            doc_root: &Path,
121            column_name: &str,
122            column: &mut Vec<Option<impl for<'de> Deserialize<'de> + 'static>>,
123        ) -> Result<(), Error> {
124            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
125            let column_path = doc_root.join(format!("search.index/{column_name}/"));
126
127            let mut consume = |_, cell: &[u8]| {
128                if cell.is_empty() {
129                    column.push(None);
130                } else {
131                    column.push(Some(serde_json::from_slice(cell)?));
132                }
133                Ok::<_, serde_json::Error>(())
134            };
135
136            stringdex_internals::read_data_from_disk_column(
137                root_path,
138                column_name.as_bytes(),
139                column_path.clone(),
140                &mut consume,
141            )
142            .map_err(|error| Error {
143                file: column_path,
144                error: format!("failed to read column from disk: {error}"),
145            })
146        }
147        fn perform_read_postings(
148            resource_suffix: &str,
149            doc_root: &Path,
150            column_name: &str,
151            column: &mut Vec<Vec<Vec<u32>>>,
152        ) -> Result<(), Error> {
153            let root_path = doc_root.join(format!("search.index/root{resource_suffix}.js"));
154            let column_path = doc_root.join(format!("search.index/{column_name}/"));
155
156            fn consumer(
157                column: &mut Vec<Vec<Vec<u32>>>,
158            ) -> impl FnMut(u32, &[u8]) -> io::Result<()> {
159                |_, cell| {
160                    let mut postings = Vec::new();
161                    encode::read_postings_from_string(&mut postings, cell);
162                    column.push(postings);
163                    Ok(())
164                }
165            }
166
167            stringdex_internals::read_data_from_disk_column(
168                root_path,
169                column_name.as_bytes(),
170                column_path.clone(),
171                &mut consumer(column),
172            )
173            .map_err(|error| Error {
174                file: column_path,
175                error: format!("failed to read column from disk: {error}"),
176            })
177        }
178
179        assert_eq!(names.len(), path_data.len());
180        assert_eq!(path_data.len(), entry_data.len());
181        assert_eq!(entry_data.len(), descs.len());
182        assert_eq!(descs.len(), function_data.len());
183        assert_eq!(function_data.len(), type_data.len());
184        assert_eq!(type_data.len(), alias_pointers.len());
185
186        // generic_inverted_index is not the same length as other columns,
187        // because it's actually a completely different set of objects
188
189        let mut crate_paths_index: FxHashMap<(ItemType, Vec<Symbol>), usize> = FxHashMap::default();
190        for (i, (name, path_data)) in names.iter().zip(path_data.iter()).enumerate() {
191            if let Some(path_data) = path_data {
192                let full_path = if path_data.module_path.is_empty() {
193                    vec![Symbol::intern(name)]
194                } else {
195                    let mut full_path = path_data.module_path.to_vec();
196                    full_path.push(Symbol::intern(name));
197                    full_path
198                };
199                crate_paths_index.insert((path_data.ty, full_path), i);
200            }
201        }
202
203        Ok(SerializedSearchIndex {
204            names,
205            path_data,
206            entry_data,
207            descs,
208            function_data,
209            type_data,
210            alias_pointers,
211            generic_inverted_index,
212            crate_paths_index,
213        })
214    }
215    fn push(
216        &mut self,
217        name: String,
218        path_data: Option<PathData>,
219        entry_data: Option<EntryData>,
220        desc: String,
221        function_data: Option<IndexItemFunctionType>,
222        type_data: Option<TypeData>,
223        alias_pointer: Option<usize>,
224    ) -> usize {
225        let index = self.names.len();
226        assert_eq!(self.names.len(), self.path_data.len());
227        if let Some(path_data) = &path_data
228            && let name = Symbol::intern(&name)
229            && let fqp = if path_data.module_path.is_empty() {
230                vec![name]
231            } else {
232                let mut v = path_data.module_path.clone();
233                v.push(name);
234                v
235            }
236            && let Some(&other_path) = self.crate_paths_index.get(&(path_data.ty, fqp))
237            && self.path_data.get(other_path).map_or(false, Option::is_some)
238        {
239            self.path_data.push(None);
240        } else {
241            self.path_data.push(path_data);
242        }
243        self.names.push(name);
244        assert_eq!(self.entry_data.len(), self.descs.len());
245        self.entry_data.push(entry_data);
246        assert_eq!(self.descs.len(), self.function_data.len());
247        self.descs.push(desc);
248        assert_eq!(self.function_data.len(), self.type_data.len());
249        self.function_data.push(function_data);
250        assert_eq!(self.type_data.len(), self.alias_pointers.len());
251        self.type_data.push(type_data);
252        self.alias_pointers.push(alias_pointer);
253        index
254    }
255    /// Add potential search result to the database and return the row ID.
256    ///
257    /// The returned ID can be used to attach more data to the search result.
258    fn add_entry(&mut self, name: Symbol, entry_data: EntryData, desc: String) -> usize {
259        let fqp = if let Some(module_path_index) = entry_data.module_path {
260            self.path_data[module_path_index]
261                .as_ref()
262                .unwrap()
263                .module_path
264                .iter()
265                .copied()
266                .chain([Symbol::intern(&self.names[module_path_index]), name])
267                .collect()
268        } else {
269            vec![name]
270        };
271        // If a path with the same name already exists, but no entry does,
272        // we can fill in the entry without having to allocate a new row ID.
273        //
274        // Because paths and entries both share the same index, using the same
275        // ID saves space by making the tree smaller.
276        if let Some(&other_path) = self.crate_paths_index.get(&(entry_data.ty, fqp))
277            && self.entry_data[other_path].is_none()
278            && self.descs[other_path].is_empty()
279        {
280            self.entry_data[other_path] = Some(entry_data);
281            self.descs[other_path] = desc;
282            other_path
283        } else {
284            self.push(name.as_str().to_string(), None, Some(entry_data), desc, None, None, None)
285        }
286    }
287    fn push_path(&mut self, name: String, path_data: PathData) -> usize {
288        self.push(name, Some(path_data), None, String::new(), None, None, None)
289    }
290    fn push_type(&mut self, name: String, path_data: PathData, type_data: TypeData) -> usize {
291        self.push(name, Some(path_data), None, String::new(), None, Some(type_data), None)
292    }
293    fn push_alias(&mut self, name: String, alias_pointer: usize) -> usize {
294        self.push(name, None, None, String::new(), None, None, Some(alias_pointer))
295    }
296
297    fn get_id_by_module_path(&mut self, path: &[Symbol]) -> usize {
298        let ty = if path.len() == 1 { ItemType::ExternCrate } else { ItemType::Module };
299        match self.crate_paths_index.entry((ty, path.to_vec())) {
300            Entry::Occupied(index) => *index.get(),
301            Entry::Vacant(slot) => {
302                slot.insert(self.path_data.len());
303                let (name, module_path) = path.split_last().unwrap();
304                self.push_path(
305                    name.as_str().to_string(),
306                    PathData { ty, module_path: module_path.to_vec(), exact_module_path: None },
307                )
308            }
309        }
310    }
311
312    pub(crate) fn union(mut self, other: &SerializedSearchIndex) -> SerializedSearchIndex {
313        let other_entryid_offset = self.names.len();
314        let mut map_other_pathid_to_self_pathid = Vec::new();
315        let mut skips = FxHashSet::default();
316        for (other_pathid, other_path_data) in other.path_data.iter().enumerate() {
317            if let Some(other_path_data) = other_path_data {
318                let name = Symbol::intern(&other.names[other_pathid]);
319                let fqp =
320                    other_path_data.module_path.iter().copied().chain(iter::once(name)).collect();
321                let self_pathid = other_entryid_offset + other_pathid;
322                let self_pathid = match self.crate_paths_index.entry((other_path_data.ty, fqp)) {
323                    Entry::Vacant(slot) => {
324                        slot.insert(self_pathid);
325                        self_pathid
326                    }
327                    Entry::Occupied(existing_entryid) => {
328                        skips.insert(other_pathid);
329                        let self_pathid = *existing_entryid.get();
330                        let new_type_data = match (
331                            self.type_data[self_pathid].take(),
332                            other.type_data[other_pathid].as_ref(),
333                        ) {
334                            (Some(self_type_data), None) => Some(self_type_data),
335                            (None, Some(other_type_data)) => Some(TypeData {
336                                search_unbox: other_type_data.search_unbox,
337                                inverted_function_inputs_index: other_type_data
338                                    .inverted_function_inputs_index
339                                    .iter()
340                                    .cloned()
341                                    .map(|mut list: Vec<u32>| {
342                                        for fnid in &mut list {
343                                            assert!(
344                                                other.function_data
345                                                    [usize::try_from(*fnid).unwrap()]
346                                                .is_some(),
347                                            );
348                                            // this is valid because we call `self.push()` once, exactly, for every entry,
349                                            // even if we're just pushing a tombstone
350                                            *fnid += u32::try_from(other_entryid_offset).unwrap();
351                                        }
352                                        list
353                                    })
354                                    .collect(),
355                                inverted_function_output_index: other_type_data
356                                    .inverted_function_output_index
357                                    .iter()
358                                    .cloned()
359                                    .map(|mut list: Vec<u32>| {
360                                        for fnid in &mut list {
361                                            assert!(
362                                                other.function_data
363                                                    [usize::try_from(*fnid).unwrap()]
364                                                .is_some(),
365                                            );
366                                            // this is valid because we call `self.push()` once, exactly, for every entry,
367                                            // even if we're just pushing a tombstone
368                                            *fnid += u32::try_from(other_entryid_offset).unwrap();
369                                        }
370                                        list
371                                    })
372                                    .collect(),
373                            }),
374                            (Some(mut self_type_data), Some(other_type_data)) => {
375                                for (size, other_list) in other_type_data
376                                    .inverted_function_inputs_index
377                                    .iter()
378                                    .enumerate()
379                                {
380                                    while self_type_data.inverted_function_inputs_index.len()
381                                        <= size
382                                    {
383                                        self_type_data
384                                            .inverted_function_inputs_index
385                                            .push(Vec::new());
386                                    }
387                                    self_type_data.inverted_function_inputs_index[size].extend(
388                                        other_list.iter().copied().map(|fnid| {
389                                            assert!(
390                                                other.function_data[usize::try_from(fnid).unwrap()]
391                                                    .is_some(),
392                                            );
393                                            // this is valid because we call `self.push()` once, exactly, for every entry,
394                                            // even if we're just pushing a tombstone
395                                            fnid + u32::try_from(other_entryid_offset).unwrap()
396                                        }),
397                                    )
398                                }
399                                for (size, other_list) in other_type_data
400                                    .inverted_function_output_index
401                                    .iter()
402                                    .enumerate()
403                                {
404                                    while self_type_data.inverted_function_output_index.len()
405                                        <= size
406                                    {
407                                        self_type_data
408                                            .inverted_function_output_index
409                                            .push(Vec::new());
410                                    }
411                                    self_type_data.inverted_function_output_index[size].extend(
412                                        other_list.iter().copied().map(|fnid| {
413                                            assert!(
414                                                other.function_data[usize::try_from(fnid).unwrap()]
415                                                    .is_some(),
416                                            );
417                                            // this is valid because we call `self.push()` once, exactly, for every entry,
418                                            // even if we're just pushing a tombstone
419                                            fnid + u32::try_from(other_entryid_offset).unwrap()
420                                        }),
421                                    )
422                                }
423                                Some(self_type_data)
424                            }
425                            (None, None) => None,
426                        };
427                        self.type_data[self_pathid] = new_type_data;
428                        self_pathid
429                    }
430                };
431                map_other_pathid_to_self_pathid.push(self_pathid);
432            } else {
433                // if this gets used, we want it to crash
434                // this should be impossible as a valid index, since some of the
435                // memory must be used for stuff other than the list
436                map_other_pathid_to_self_pathid.push(!0);
437            }
438        }
439        for other_entryid in 0..other.names.len() {
440            if skips.contains(&other_entryid) {
441                // we push tombstone entries to keep the IDs lined up
442                self.push(String::new(), None, None, String::new(), None, None, None);
443            } else {
444                self.push(
445                    other.names[other_entryid].clone(),
446                    other.path_data[other_entryid].clone(),
447                    other.entry_data[other_entryid].as_ref().map(|other_entry_data| EntryData {
448                        parent: other_entry_data
449                            .parent
450                            .map(|parent| map_other_pathid_to_self_pathid[parent])
451                            .clone(),
452                        module_path: other_entry_data
453                            .module_path
454                            .map(|path| map_other_pathid_to_self_pathid[path])
455                            .clone(),
456                        exact_module_path: other_entry_data
457                            .exact_module_path
458                            .map(|exact_path| map_other_pathid_to_self_pathid[exact_path])
459                            .clone(),
460                        krate: map_other_pathid_to_self_pathid[other_entry_data.krate],
461                        ..other_entry_data.clone()
462                    }),
463                    other.descs[other_entryid].clone(),
464                    other.function_data[other_entryid].clone().map(|mut func| {
465                        fn map_fn_sig_item(
466                            map_other_pathid_to_self_pathid: &Vec<usize>,
467                            ty: &mut RenderType,
468                        ) {
469                            match ty.id {
470                                None => {}
471                                Some(RenderTypeId::Index(generic)) if generic < 0 => {}
472                                Some(RenderTypeId::Index(id)) => {
473                                    let id = usize::try_from(id).unwrap();
474                                    let id = map_other_pathid_to_self_pathid[id];
475                                    assert!(id != !0);
476                                    ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap()));
477                                }
478                                _ => unreachable!(),
479                            }
480                            if let Some(generics) = &mut ty.generics {
481                                for generic in generics {
482                                    map_fn_sig_item(map_other_pathid_to_self_pathid, generic);
483                                }
484                            }
485                            if let Some(bindings) = &mut ty.bindings {
486                                for (param, constraints) in bindings {
487                                    *param = match *param {
488                                        param @ RenderTypeId::Index(generic) if generic < 0 => {
489                                            param
490                                        }
491                                        RenderTypeId::Index(id) => {
492                                            let id = usize::try_from(id).unwrap();
493                                            let id = map_other_pathid_to_self_pathid[id];
494                                            assert!(id != !0);
495                                            RenderTypeId::Index(isize::try_from(id).unwrap())
496                                        }
497                                        _ => unreachable!(),
498                                    };
499                                    for constraint in constraints {
500                                        map_fn_sig_item(
501                                            map_other_pathid_to_self_pathid,
502                                            constraint,
503                                        );
504                                    }
505                                }
506                            }
507                        }
508                        for input in &mut func.inputs {
509                            map_fn_sig_item(&map_other_pathid_to_self_pathid, input);
510                        }
511                        for output in &mut func.output {
512                            map_fn_sig_item(&map_other_pathid_to_self_pathid, output);
513                        }
514                        for clause in &mut func.where_clause {
515                            for entry in clause {
516                                map_fn_sig_item(&map_other_pathid_to_self_pathid, entry);
517                            }
518                        }
519                        func
520                    }),
521                    other.type_data[other_entryid].as_ref().map(|type_data| TypeData {
522                        inverted_function_inputs_index: type_data
523                            .inverted_function_inputs_index
524                            .iter()
525                            .cloned()
526                            .map(|mut list| {
527                                for fnid in &mut list {
528                                    assert!(
529                                        other.function_data[usize::try_from(*fnid).unwrap()]
530                                            .is_some(),
531                                    );
532                                    // this is valid because we call `self.push()` once, exactly, for every entry,
533                                    // even if we're just pushing a tombstone
534                                    *fnid += u32::try_from(other_entryid_offset).unwrap();
535                                }
536                                list
537                            })
538                            .collect(),
539                        inverted_function_output_index: type_data
540                            .inverted_function_output_index
541                            .iter()
542                            .cloned()
543                            .map(|mut list| {
544                                for fnid in &mut list {
545                                    assert!(
546                                        other.function_data[usize::try_from(*fnid).unwrap()]
547                                            .is_some(),
548                                    );
549                                    // this is valid because we call `self.push()` once, exactly, for every entry,
550                                    // even if we're just pushing a tombstone
551                                    *fnid += u32::try_from(other_entryid_offset).unwrap();
552                                }
553                                list
554                            })
555                            .collect(),
556                        search_unbox: type_data.search_unbox,
557                    }),
558                    other.alias_pointers[other_entryid]
559                        .map(|alias_pointer| alias_pointer + other_entryid_offset),
560                );
561            }
562        }
563        if other.generic_inverted_index.len() > self.generic_inverted_index.len() {
564            self.generic_inverted_index.resize(other.generic_inverted_index.len(), Vec::new());
565        }
566        for (other_generic_inverted_index, self_generic_inverted_index) in
567            iter::zip(&other.generic_inverted_index, &mut self.generic_inverted_index)
568        {
569            if other_generic_inverted_index.len() > self_generic_inverted_index.len() {
570                self_generic_inverted_index.resize(other_generic_inverted_index.len(), Vec::new());
571            }
572            for (other_list, self_list) in
573                iter::zip(other_generic_inverted_index, self_generic_inverted_index)
574            {
575                self_list.extend(
576                    other_list
577                        .iter()
578                        .copied()
579                        .map(|fnid| fnid + u32::try_from(other_entryid_offset).unwrap()),
580                );
581            }
582        }
583        self
584    }
585
586    pub(crate) fn sort(self) -> SerializedSearchIndex {
587        let mut idlist: Vec<usize> = (0..self.names.len()).collect();
588        // nameless entries are tombstones, and will be removed after sorting
589        // sort shorter names first, so that we can present them in order out of search.js
590        idlist.sort_by_key(|&id| {
591            (
592                self.names[id].is_empty(),
593                self.names[id].len(),
594                &self.names[id],
595                self.entry_data[id].as_ref().map_or("", |entry| self.names[entry.krate].as_str()),
596                self.path_data[id].as_ref().map_or(&[][..], |entry| &entry.module_path[..]),
597            )
598        });
599        let map = FxHashMap::from_iter(
600            idlist.iter().enumerate().map(|(new_id, &old_id)| (old_id, new_id)),
601        );
602        let mut new = SerializedSearchIndex::default();
603        for &id in &idlist {
604            if self.names[id].is_empty() {
605                break;
606            }
607            new.push(
608                self.names[id].clone(),
609                self.path_data[id].clone(),
610                self.entry_data[id].as_ref().map(
611                    |EntryData {
612                         krate,
613                         ty,
614                         module_path,
615                         exact_module_path,
616                         parent,
617                         trait_parent,
618                         deprecated,
619                         unstable,
620                         associated_item_disambiguator_or_extern_crate_url:
621                             associated_item_disambiguator,
622                     }| EntryData {
623                        krate: *map.get(krate).unwrap(),
624                        ty: *ty,
625                        module_path: module_path.and_then(|path_id| map.get(&path_id).copied()),
626                        exact_module_path: exact_module_path
627                            .and_then(|path_id| map.get(&path_id).copied()),
628                        parent: parent.and_then(|path_id| map.get(&path_id).copied()),
629                        trait_parent: trait_parent.and_then(|path_id| map.get(&path_id).copied()),
630                        deprecated: *deprecated,
631                        unstable: *unstable,
632                        associated_item_disambiguator_or_extern_crate_url:
633                            associated_item_disambiguator.clone(),
634                    },
635                ),
636                self.descs[id].clone(),
637                self.function_data[id].clone().map(|mut func| {
638                    fn map_fn_sig_item(map: &FxHashMap<usize, usize>, ty: &mut RenderType) {
639                        match ty.id {
640                            None => {}
641                            Some(RenderTypeId::Index(generic)) if generic < 0 => {}
642                            Some(RenderTypeId::Index(id)) => {
643                                let id = usize::try_from(id).unwrap();
644                                let id = *map.get(&id).unwrap();
645                                assert!(id != !0);
646                                ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap()));
647                            }
648                            _ => unreachable!(),
649                        }
650                        if let Some(generics) = &mut ty.generics {
651                            for generic in generics {
652                                map_fn_sig_item(map, generic);
653                            }
654                        }
655                        if let Some(bindings) = &mut ty.bindings {
656                            for (param, constraints) in bindings {
657                                *param = match *param {
658                                    param @ RenderTypeId::Index(generic) if generic < 0 => param,
659                                    RenderTypeId::Index(id) => {
660                                        let id = usize::try_from(id).unwrap();
661                                        let id = *map.get(&id).unwrap();
662                                        assert!(id != !0);
663                                        RenderTypeId::Index(isize::try_from(id).unwrap())
664                                    }
665                                    _ => unreachable!(),
666                                };
667                                for constraint in constraints {
668                                    map_fn_sig_item(map, constraint);
669                                }
670                            }
671                        }
672                    }
673                    for input in &mut func.inputs {
674                        map_fn_sig_item(&map, input);
675                    }
676                    for output in &mut func.output {
677                        map_fn_sig_item(&map, output);
678                    }
679                    for clause in &mut func.where_clause {
680                        for entry in clause {
681                            map_fn_sig_item(&map, entry);
682                        }
683                    }
684                    func
685                }),
686                self.type_data[id].as_ref().map(
687                    |TypeData {
688                         search_unbox,
689                         inverted_function_inputs_index,
690                         inverted_function_output_index,
691                     }| {
692                        let inverted_function_inputs_index: Vec<Vec<u32>> =
693                            inverted_function_inputs_index
694                                .iter()
695                                .cloned()
696                                .map(|mut list| {
697                                    for id in &mut list {
698                                        *id = u32::try_from(
699                                            *map.get(&usize::try_from(*id).unwrap()).unwrap(),
700                                        )
701                                        .unwrap();
702                                    }
703                                    list.sort();
704                                    list
705                                })
706                                .collect();
707                        let inverted_function_output_index: Vec<Vec<u32>> =
708                            inverted_function_output_index
709                                .iter()
710                                .cloned()
711                                .map(|mut list| {
712                                    for id in &mut list {
713                                        *id = u32::try_from(
714                                            *map.get(&usize::try_from(*id).unwrap()).unwrap(),
715                                        )
716                                        .unwrap();
717                                    }
718                                    list.sort();
719                                    list
720                                })
721                                .collect();
722                        TypeData {
723                            search_unbox: *search_unbox,
724                            inverted_function_inputs_index,
725                            inverted_function_output_index,
726                        }
727                    },
728                ),
729                self.alias_pointers[id].and_then(|alias| {
730                    if self.names[alias].is_empty() { None } else { map.get(&alias).copied() }
731                }),
732            );
733        }
734        new.generic_inverted_index = self
735            .generic_inverted_index
736            .into_iter()
737            .map(|mut postings| {
738                for list in postings.iter_mut() {
739                    let mut new_list: Vec<u32> = list
740                        .iter()
741                        .copied()
742                        .filter_map(|id| u32::try_from(*map.get(&usize::try_from(id).ok()?)?).ok())
743                        .collect();
744                    new_list.sort();
745                    *list = new_list;
746                }
747                postings
748            })
749            .collect();
750        new
751    }
752
753    pub(crate) fn write_to(self, doc_root: &Path, resource_suffix: &str) -> Result<(), Error> {
754        let SerializedSearchIndex {
755            names,
756            path_data,
757            entry_data,
758            descs,
759            function_data,
760            type_data,
761            alias_pointers,
762            generic_inverted_index,
763            crate_paths_index: _,
764        } = self;
765        let mut serialized_root = Vec::new();
766        serialized_root.extend_from_slice(br#"rr_('{"normalizedName":{"I":""#);
767        let normalized_names = names
768            .iter()
769            .map(|name| {
770                if name.contains("_") {
771                    name.replace("_", "").to_ascii_lowercase()
772                } else {
773                    name.to_ascii_lowercase()
774                }
775            })
776            .collect::<Vec<String>>();
777        let names_search_tree = stringdex_internals::tree::encode_search_tree_ukkonen(
778            normalized_names.iter().map(|name| name.as_bytes()),
779        );
780        let dir_path = doc_root.join(format!("search.index/"));
781        let _ = std::fs::remove_dir_all(&dir_path); // if already missing, no problem
782        stringdex_internals::write_tree_to_disk(
783            &names_search_tree,
784            &dir_path,
785            &mut serialized_root,
786        )
787        .map_err(|error| Error {
788            file: dir_path,
789            error: format!("failed to write name tree to disk: {error}"),
790        })?;
791        std::mem::drop(names_search_tree);
792        serialized_root.extend_from_slice(br#"","#);
793        serialized_root.extend_from_slice(&perform_write_strings(
794            doc_root,
795            "normalizedName",
796            normalized_names.into_iter(),
797        )?);
798        serialized_root.extend_from_slice(br#"},"crateNames":{"#);
799        let mut crates: Vec<&[u8]> = entry_data
800            .iter()
801            .filter_map(|entry_data| Some(names[entry_data.as_ref()?.krate].as_bytes()))
802            .collect();
803        crates.sort();
804        crates.dedup();
805        serialized_root.extend_from_slice(&perform_write_strings(
806            doc_root,
807            "crateNames",
808            crates.into_iter(),
809        )?);
810        serialized_root.extend_from_slice(br#"},"name":{"#);
811        serialized_root.extend_from_slice(&perform_write_strings(doc_root, "name", names.iter())?);
812        serialized_root.extend_from_slice(br#"},"path":{"#);
813        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "path", path_data)?);
814        serialized_root.extend_from_slice(br#"},"entry":{"#);
815        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "entry", entry_data)?);
816        serialized_root.extend_from_slice(br#"},"desc":{"#);
817        serialized_root.extend_from_slice(&perform_write_strings(
818            doc_root,
819            "desc",
820            descs.into_iter(),
821        )?);
822        serialized_root.extend_from_slice(br#"},"function":{"#);
823        serialized_root.extend_from_slice(&perform_write_serde(
824            doc_root,
825            "function",
826            function_data,
827        )?);
828        serialized_root.extend_from_slice(br#"},"type":{"#);
829        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "type", type_data)?);
830        serialized_root.extend_from_slice(br#"},"alias":{"#);
831        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "alias", alias_pointers)?);
832        serialized_root.extend_from_slice(br#"},"generic_inverted_index":{"#);
833        serialized_root.extend_from_slice(&perform_write_postings(
834            doc_root,
835            "generic_inverted_index",
836            generic_inverted_index,
837        )?);
838        serialized_root.extend_from_slice(br#"}}')"#);
839        fn perform_write_strings(
840            doc_root: &Path,
841            dirname: &str,
842            mut column: impl Iterator<Item = impl AsRef<[u8]> + Clone> + ExactSizeIterator,
843        ) -> Result<Vec<u8>, Error> {
844            let dir_path = doc_root.join(format!("search.index/{dirname}"));
845            stringdex_internals::write_data_to_disk(&mut column, &dir_path).map_err(|error| Error {
846                file: dir_path,
847                error: format!("failed to write column to disk: {error}"),
848            })
849        }
850        fn perform_write_serde(
851            doc_root: &Path,
852            dirname: &str,
853            column: Vec<Option<impl Serialize>>,
854        ) -> Result<Vec<u8>, Error> {
855            perform_write_strings(
856                doc_root,
857                dirname,
858                column.into_iter().map(|value| {
859                    if let Some(value) = value {
860                        serde_json::to_vec(&value).unwrap()
861                    } else {
862                        Vec::new()
863                    }
864                }),
865            )
866        }
867        fn perform_write_postings(
868            doc_root: &Path,
869            dirname: &str,
870            column: Vec<Vec<Vec<u32>>>,
871        ) -> Result<Vec<u8>, Error> {
872            perform_write_strings(
873                doc_root,
874                dirname,
875                column.into_iter().map(|postings| {
876                    let mut buf = Vec::new();
877                    encode::write_postings_to_string(&postings, &mut buf);
878                    buf
879                }),
880            )
881        }
882        std::fs::write(
883            doc_root.join(format!("search.index/root{resource_suffix}.js")),
884            serialized_root,
885        )
886        .map_err(|error| Error {
887            file: doc_root.join(format!("search.index/root{resource_suffix}.js")),
888            error: format!("failed to write root to disk: {error}"),
889        })?;
890        Ok(())
891    }
892}
893
894#[derive(Clone, Debug)]
895struct EntryData {
896    krate: usize,
897    ty: ItemType,
898    module_path: Option<usize>,
899    exact_module_path: Option<usize>,
900    parent: Option<usize>,
901    trait_parent: Option<usize>,
902    deprecated: bool,
903    unstable: bool,
904    associated_item_disambiguator_or_extern_crate_url: Option<String>,
905}
906
907impl Serialize for EntryData {
908    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
909    where
910        S: Serializer,
911    {
912        let mut seq = serializer.serialize_seq(None)?;
913        seq.serialize_element(&self.krate)?;
914        seq.serialize_element(&self.ty)?;
915        seq.serialize_element(&self.module_path.map(|id| id + 1).unwrap_or(0))?;
916        seq.serialize_element(&self.exact_module_path.map(|id| id + 1).unwrap_or(0))?;
917        seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?;
918        seq.serialize_element(&self.trait_parent.map(|id| id + 1).unwrap_or(0))?;
919        seq.serialize_element(&if self.deprecated { 1 } else { 0 })?;
920        seq.serialize_element(&if self.unstable { 1 } else { 0 })?;
921        if let Some(disambig) = &self.associated_item_disambiguator_or_extern_crate_url {
922            seq.serialize_element(&disambig)?;
923        }
924        seq.end()
925    }
926}
927
928impl<'de> Deserialize<'de> for EntryData {
929    fn deserialize<D>(deserializer: D) -> Result<EntryData, D::Error>
930    where
931        D: Deserializer<'de>,
932    {
933        struct EntryDataVisitor;
934        impl<'de> de::Visitor<'de> for EntryDataVisitor {
935            type Value = EntryData;
936            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
937                write!(formatter, "path data")
938            }
939            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<EntryData, A::Error> {
940                let krate: usize =
941                    v.next_element()?.ok_or_else(|| A::Error::missing_field("krate"))?;
942                let ty: ItemType =
943                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
944                let module_path: SerializedOptional32 =
945                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
946                let exact_module_path: SerializedOptional32 = v
947                    .next_element()?
948                    .ok_or_else(|| A::Error::missing_field("exact_module_path"))?;
949                let parent: SerializedOptional32 =
950                    v.next_element()?.ok_or_else(|| A::Error::missing_field("parent"))?;
951                let trait_parent: SerializedOptional32 =
952                    v.next_element()?.ok_or_else(|| A::Error::missing_field("trait_parent"))?;
953
954                let deprecated: u32 = v.next_element()?.unwrap_or(0);
955                let unstable: u32 = v.next_element()?.unwrap_or(0);
956                let associated_item_disambiguator: Option<String> = v.next_element()?;
957                Ok(EntryData {
958                    krate,
959                    ty,
960                    module_path: Option::<i32>::from(module_path).map(|path| path as usize),
961                    exact_module_path: Option::<i32>::from(exact_module_path)
962                        .map(|path| path as usize),
963                    parent: Option::<i32>::from(parent).map(|path| path as usize),
964                    trait_parent: Option::<i32>::from(trait_parent).map(|path| path as usize),
965                    deprecated: deprecated != 0,
966                    unstable: unstable != 0,
967                    associated_item_disambiguator_or_extern_crate_url:
968                        associated_item_disambiguator,
969                })
970            }
971        }
972        deserializer.deserialize_any(EntryDataVisitor)
973    }
974}
975
976#[derive(Clone, Debug)]
977struct PathData {
978    ty: ItemType,
979    module_path: Vec<Symbol>,
980    exact_module_path: Option<Vec<Symbol>>,
981}
982
983impl Serialize for PathData {
984    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
985    where
986        S: Serializer,
987    {
988        let mut seq = serializer.serialize_seq(None)?;
989        seq.serialize_element(&self.ty)?;
990        seq.serialize_element(&if self.module_path.is_empty() {
991            String::new()
992        } else {
993            join_path_syms(&self.module_path)
994        })?;
995        if let Some(ref path) = self.exact_module_path {
996            seq.serialize_element(&if path.is_empty() {
997                String::new()
998            } else {
999                join_path_syms(path)
1000            })?;
1001        }
1002        seq.end()
1003    }
1004}
1005
1006impl<'de> Deserialize<'de> for PathData {
1007    fn deserialize<D>(deserializer: D) -> Result<PathData, D::Error>
1008    where
1009        D: Deserializer<'de>,
1010    {
1011        struct PathDataVisitor;
1012        impl<'de> de::Visitor<'de> for PathDataVisitor {
1013            type Value = PathData;
1014            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1015                write!(formatter, "path data")
1016            }
1017            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<PathData, A::Error> {
1018                let ty: ItemType =
1019                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
1020                let module_path: String =
1021                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
1022                let exact_module_path: Option<String> =
1023                    v.next_element()?.and_then(SerializedOptionalString::into);
1024                Ok(PathData {
1025                    ty,
1026                    module_path: if module_path.is_empty() {
1027                        vec![]
1028                    } else {
1029                        module_path.split("::").map(Symbol::intern).collect()
1030                    },
1031                    exact_module_path: exact_module_path.map(|path| {
1032                        if path.is_empty() {
1033                            vec![]
1034                        } else {
1035                            path.split("::").map(Symbol::intern).collect()
1036                        }
1037                    }),
1038                })
1039            }
1040        }
1041        deserializer.deserialize_any(PathDataVisitor)
1042    }
1043}
1044
1045#[derive(Clone, Debug)]
1046struct TypeData {
1047    /// If set to "true", the generics can be matched without having to
1048    /// mention the type itself. The truth table, assuming `Unboxable`
1049    /// has `search_unbox = true` and `Inner` has `search_unbox = false`
1050    ///
1051    /// | **query**          | `Unboxable<Inner>` | `Inner` | `Inner<Unboxable>` |
1052    /// |--------------------|--------------------|---------|--------------------|
1053    /// | `Inner`            | yes                | yes     | yes                |
1054    /// | `Unboxable`        | yes                | no      | no                 |
1055    /// | `Unboxable<Inner>` | yes                | no      | no                 |
1056    /// | `Inner<Unboxable>` | no                 | no      | yes                |
1057    search_unbox: bool,
1058    /// List of functions that mention this type in their type signature,
1059    /// on the left side of the `->` arrow.
1060    ///
1061    /// - The outer layer is sorted by number of types that appear in the
1062    ///   type signature. The search engine iterates over these in order from
1063    ///   smallest to largest. Functions with less stuff in their type
1064    ///   signature are more likely to be what the user wants, because we never
1065    ///   show functions that are *missing* parts of the query, so removing..
1066    ///
1067    /// - The inner layer is the list of functions.
1068    inverted_function_inputs_index: Vec<Vec<u32>>,
1069    /// List of functions that mention this type in their type signature,
1070    /// on the right side of the `->` arrow.
1071    inverted_function_output_index: Vec<Vec<u32>>,
1072}
1073
1074impl Serialize for TypeData {
1075    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1076    where
1077        S: Serializer,
1078    {
1079        let mut seq = serializer.serialize_seq(None)?;
1080        let mut buf = Vec::new();
1081        encode::write_postings_to_string(&self.inverted_function_inputs_index, &mut buf);
1082        let mut serialized_result = Vec::new();
1083        stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result).unwrap();
1084        seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?;
1085        buf.clear();
1086        serialized_result.clear();
1087        encode::write_postings_to_string(&self.inverted_function_output_index, &mut buf);
1088        stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result).unwrap();
1089        seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?;
1090        if self.search_unbox {
1091            seq.serialize_element(&1)?;
1092        }
1093        seq.end()
1094    }
1095}
1096
1097impl<'de> Deserialize<'de> for TypeData {
1098    fn deserialize<D>(deserializer: D) -> Result<TypeData, D::Error>
1099    where
1100        D: Deserializer<'de>,
1101    {
1102        struct TypeDataVisitor;
1103        impl<'de> de::Visitor<'de> for TypeDataVisitor {
1104            type Value = TypeData;
1105            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1106                write!(formatter, "type data")
1107            }
1108            fn visit_none<E>(self) -> Result<TypeData, E> {
1109                Ok(TypeData {
1110                    inverted_function_inputs_index: vec![],
1111                    inverted_function_output_index: vec![],
1112                    search_unbox: false,
1113                })
1114            }
1115            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<TypeData, A::Error> {
1116                let inverted_function_inputs_index: String =
1117                    v.next_element()?.unwrap_or(String::new());
1118                let inverted_function_output_index: String =
1119                    v.next_element()?.unwrap_or(String::new());
1120                let search_unbox: u32 = v.next_element()?.unwrap_or(0);
1121                let mut idx: Vec<u8> = Vec::new();
1122                stringdex_internals::decode::read_base64_from_bytes(
1123                    inverted_function_inputs_index.as_bytes(),
1124                    &mut idx,
1125                )
1126                .unwrap();
1127                let mut inverted_function_inputs_index = Vec::new();
1128                encode::read_postings_from_string(&mut inverted_function_inputs_index, &idx);
1129                idx.clear();
1130                stringdex_internals::decode::read_base64_from_bytes(
1131                    inverted_function_output_index.as_bytes(),
1132                    &mut idx,
1133                )
1134                .unwrap();
1135                let mut inverted_function_output_index = Vec::new();
1136                encode::read_postings_from_string(&mut inverted_function_output_index, &idx);
1137                Ok(TypeData {
1138                    inverted_function_inputs_index,
1139                    inverted_function_output_index,
1140                    search_unbox: search_unbox == 1,
1141                })
1142            }
1143        }
1144        deserializer.deserialize_any(TypeDataVisitor)
1145    }
1146}
1147
1148enum SerializedOptionalString {
1149    None,
1150    Some(String),
1151}
1152
1153impl From<SerializedOptionalString> for Option<String> {
1154    fn from(me: SerializedOptionalString) -> Option<String> {
1155        match me {
1156            SerializedOptionalString::Some(string) => Some(string),
1157            SerializedOptionalString::None => None,
1158        }
1159    }
1160}
1161
1162impl Serialize for SerializedOptionalString {
1163    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1164    where
1165        S: Serializer,
1166    {
1167        match self {
1168            SerializedOptionalString::Some(string) => string.serialize(serializer),
1169            SerializedOptionalString::None => 0.serialize(serializer),
1170        }
1171    }
1172}
1173impl<'de> Deserialize<'de> for SerializedOptionalString {
1174    fn deserialize<D>(deserializer: D) -> Result<SerializedOptionalString, D::Error>
1175    where
1176        D: Deserializer<'de>,
1177    {
1178        struct SerializedOptionalStringVisitor;
1179        impl<'de> de::Visitor<'de> for SerializedOptionalStringVisitor {
1180            type Value = SerializedOptionalString;
1181            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1182                write!(formatter, "0 or string")
1183            }
1184            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptionalString, E> {
1185                if v != 0 {
1186                    return Err(E::missing_field("not 0"));
1187                }
1188                Ok(SerializedOptionalString::None)
1189            }
1190            fn visit_string<E: de::Error>(self, v: String) -> Result<SerializedOptionalString, E> {
1191                Ok(SerializedOptionalString::Some(v))
1192            }
1193            fn visit_str<E: de::Error>(self, v: &str) -> Result<SerializedOptionalString, E> {
1194                Ok(SerializedOptionalString::Some(v.to_string()))
1195            }
1196        }
1197        deserializer.deserialize_any(SerializedOptionalStringVisitor)
1198    }
1199}
1200
1201enum SerializedOptional32 {
1202    None,
1203    Some(i32),
1204}
1205
1206impl From<SerializedOptional32> for Option<i32> {
1207    fn from(me: SerializedOptional32) -> Option<i32> {
1208        match me {
1209            SerializedOptional32::Some(number) => Some(number),
1210            SerializedOptional32::None => None,
1211        }
1212    }
1213}
1214
1215impl Serialize for SerializedOptional32 {
1216    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1217    where
1218        S: Serializer,
1219    {
1220        match self {
1221            &SerializedOptional32::Some(number) if number < 0 => number.serialize(serializer),
1222            &SerializedOptional32::Some(number) => (number + 1).serialize(serializer),
1223            &SerializedOptional32::None => 0.serialize(serializer),
1224        }
1225    }
1226}
1227impl<'de> Deserialize<'de> for SerializedOptional32 {
1228    fn deserialize<D>(deserializer: D) -> Result<SerializedOptional32, D::Error>
1229    where
1230        D: Deserializer<'de>,
1231    {
1232        struct SerializedOptional32Visitor;
1233        impl<'de> de::Visitor<'de> for SerializedOptional32Visitor {
1234            type Value = SerializedOptional32;
1235            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1236                write!(formatter, "integer")
1237            }
1238            fn visit_i64<E: de::Error>(self, v: i64) -> Result<SerializedOptional32, E> {
1239                Ok(match v {
1240                    0 => SerializedOptional32::None,
1241                    v if v < 0 => SerializedOptional32::Some(v as i32),
1242                    v => SerializedOptional32::Some(v as i32 - 1),
1243                })
1244            }
1245            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptional32, E> {
1246                Ok(match v {
1247                    0 => SerializedOptional32::None,
1248                    v => SerializedOptional32::Some(v as i32 - 1),
1249                })
1250            }
1251        }
1252        deserializer.deserialize_any(SerializedOptional32Visitor)
1253    }
1254}
1255
1256/// Builds the search index from the collected metadata
1257pub(crate) fn build_index(
1258    krate: &clean::Crate,
1259    cache: &mut Cache,
1260    tcx: TyCtxt<'_>,
1261    doc_root: &Path,
1262    resource_suffix: &str,
1263    should_merge: &ShouldMerge,
1264) -> Result<SerializedSearchIndex, Error> {
1265    let mut search_index = std::mem::take(&mut cache.search_index);
1266
1267    // Attach all orphan items to the type's definition if the type
1268    // has since been learned.
1269    for &OrphanImplItem { impl_id, parent, trait_parent, ref item, ref impl_generics } in
1270        &cache.orphan_impl_items
1271    {
1272        if let Some((fqp, _)) = cache.paths.get(&parent) {
1273            let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
1274            search_index.push(IndexItem {
1275                ty: item.type_(),
1276                defid: item.item_id.as_def_id(),
1277                name: item.name.unwrap(),
1278                module_path: fqp[..fqp.len() - 1].to_vec(),
1279                desc,
1280                parent: Some(parent),
1281                parent_idx: None,
1282                trait_parent,
1283                trait_parent_idx: None,
1284                exact_module_path: None,
1285                impl_id,
1286                search_type: get_function_type_for_search(
1287                    item,
1288                    tcx,
1289                    impl_generics.as_ref(),
1290                    Some(parent),
1291                    cache,
1292                ),
1293                aliases: item.attrs.get_doc_aliases(),
1294                is_deprecated: item.is_deprecated(tcx),
1295                is_unstable: item.is_unstable(),
1296            });
1297        }
1298    }
1299
1300    // Sort search index items. This improves the compressibility of the search index.
1301    search_index.sort_unstable_by(|k1, k2| {
1302        // `sort_unstable_by_key` produces lifetime errors
1303        // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too
1304        let k1 =
1305            (&k1.module_path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate)));
1306        let k2 =
1307            (&k2.module_path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate)));
1308        Ord::cmp(&k1, &k2)
1309    });
1310
1311    // Now, convert to an on-disk search index format
1312    //
1313    // if there's already a search index, load it into memory and add the new entries to it
1314    // otherwise, do nothing
1315    let mut serialized_index = if should_merge.read_rendered_cci {
1316        SerializedSearchIndex::load(doc_root, resource_suffix)?
1317    } else {
1318        SerializedSearchIndex::default()
1319    };
1320
1321    // The crate always goes first in this list
1322    let crate_name = krate.name(tcx);
1323    let crate_doc =
1324        short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache));
1325    let crate_idx = {
1326        let crate_path = (ItemType::ExternCrate, vec![crate_name]);
1327        match serialized_index.crate_paths_index.entry(crate_path) {
1328            Entry::Occupied(index) => {
1329                let index = *index.get();
1330                serialized_index.descs[index] = crate_doc;
1331                for type_data in serialized_index.type_data.iter_mut() {
1332                    if let Some(TypeData {
1333                        inverted_function_inputs_index,
1334                        inverted_function_output_index,
1335                        ..
1336                    }) = type_data
1337                    {
1338                        for list in inverted_function_inputs_index
1339                            .iter_mut()
1340                            .chain(inverted_function_output_index.iter_mut())
1341                        {
1342                            list.retain(|fnid| {
1343                                serialized_index.entry_data[usize::try_from(*fnid).unwrap()]
1344                                    .as_ref()
1345                                    .unwrap()
1346                                    .krate
1347                                    != index
1348                            });
1349                        }
1350                    }
1351                }
1352                for i in (index + 1)..serialized_index.entry_data.len() {
1353                    // if this crate has been built before, replace its stuff with new
1354                    if let Some(EntryData { krate, .. }) = serialized_index.entry_data[i]
1355                        && krate == index
1356                    {
1357                        serialized_index.entry_data[i] = None;
1358                        serialized_index.descs[i] = String::new();
1359                        serialized_index.function_data[i] = None;
1360                        if serialized_index.path_data[i].is_none() {
1361                            serialized_index.names[i] = String::new();
1362                        }
1363                    }
1364                    if let Some(alias_pointer) = serialized_index.alias_pointers[i]
1365                        && serialized_index.entry_data[alias_pointer].is_none()
1366                    {
1367                        serialized_index.alias_pointers[i] = None;
1368                        if serialized_index.path_data[i].is_none()
1369                            && serialized_index.entry_data[i].is_none()
1370                        {
1371                            serialized_index.names[i] = String::new();
1372                        }
1373                    }
1374                }
1375                index
1376            }
1377            Entry::Vacant(slot) => {
1378                let krate = serialized_index.names.len();
1379                slot.insert(krate);
1380                serialized_index.push(
1381                    crate_name.as_str().to_string(),
1382                    Some(PathData {
1383                        ty: ItemType::ExternCrate,
1384                        module_path: vec![],
1385                        exact_module_path: None,
1386                    }),
1387                    Some(EntryData {
1388                        krate,
1389                        ty: ItemType::ExternCrate,
1390                        module_path: None,
1391                        exact_module_path: None,
1392                        parent: None,
1393                        trait_parent: None,
1394                        deprecated: false,
1395                        unstable: false,
1396                        associated_item_disambiguator_or_extern_crate_url: None,
1397                    }),
1398                    crate_doc,
1399                    None,
1400                    None,
1401                    None,
1402                );
1403                krate
1404            }
1405        }
1406    };
1407
1408    // First, populate associated item parents and trait parents
1409    let crate_items: Vec<&mut IndexItem> = search_index
1410        .iter_mut()
1411        .map(|item| {
1412            let mut defid_to_rowid = |defid, check_external: bool| {
1413                cache
1414                    .paths
1415                    .get(&defid)
1416                    .or_else(|| check_external.then(|| cache.external_paths.get(&defid)).flatten())
1417                    .map(|&(ref fqp, ty)| {
1418                        let pathid = serialized_index.names.len();
1419                        match serialized_index.crate_paths_index.entry((ty, fqp.clone())) {
1420                            Entry::Occupied(entry) => *entry.get(),
1421                            Entry::Vacant(entry) => {
1422                                entry.insert(pathid);
1423                                let (name, path) = fqp.split_last().unwrap();
1424                                serialized_index.push_path(
1425                                    name.as_str().to_string(),
1426                                    PathData {
1427                                        ty,
1428                                        module_path: path.to_vec(),
1429                                        exact_module_path: if let Some(exact_path) =
1430                                            cache.exact_paths.get(&defid)
1431                                            && let Some((name2, exact_path)) =
1432                                                exact_path.split_last()
1433                                            && name == name2
1434                                        {
1435                                            Some(exact_path.to_vec())
1436                                        } else {
1437                                            None
1438                                        },
1439                                    },
1440                                );
1441                                usize::try_from(pathid).unwrap()
1442                            }
1443                        }
1444                    })
1445            };
1446            item.parent_idx = item.parent.and_then(|p| defid_to_rowid(p, false));
1447            item.trait_parent_idx = item.trait_parent.and_then(|p| defid_to_rowid(p, true));
1448
1449            if let Some(defid) = item.defid
1450                && item.parent_idx.is_none()
1451            {
1452                // If this is a re-export, retain the original path.
1453                // Associated items don't use this.
1454                // Their parent carries the exact fqp instead.
1455                let exact_fqp = cache
1456                    .exact_paths
1457                    .get(&defid)
1458                    .or_else(|| cache.external_paths.get(&defid).map(|(fqp, _)| fqp));
1459                item.exact_module_path = exact_fqp.and_then(|fqp| {
1460                    // Re-exports only count if the name is exactly the same.
1461                    // This is a size optimization, since it means we only need
1462                    // to store the name once (and the path is re-used for everything
1463                    // exported from this same module). It's also likely to Do
1464                    // What I Mean, since if a re-export changes the name, it might
1465                    // also be a change in semantic meaning.
1466                    if fqp.last() != Some(&item.name) {
1467                        return None;
1468                    }
1469                    let path = if item.ty == ItemType::Macro
1470                        && find_attr!(tcx, defid, MacroExport { .. })
1471                    {
1472                        // `#[macro_export]` always exports to the crate root.
1473                        vec![tcx.crate_name(defid.krate)]
1474                    } else {
1475                        if fqp.len() < 2 {
1476                            return None;
1477                        }
1478                        fqp[..fqp.len() - 1].to_vec()
1479                    };
1480                    if path == item.module_path {
1481                        return None;
1482                    }
1483                    Some(path)
1484                });
1485            } else if let Some(parent_idx) = item.parent_idx {
1486                let i = usize::try_from(parent_idx).unwrap();
1487                item.module_path =
1488                    serialized_index.path_data[i].as_ref().unwrap().module_path.clone();
1489                item.exact_module_path =
1490                    serialized_index.path_data[i].as_ref().unwrap().exact_module_path.clone();
1491            }
1492
1493            &mut *item
1494        })
1495        .collect();
1496
1497    // Now, find anywhere that the same name is used for two different items
1498    // these need a disambiguator hash for lints
1499    let mut associated_item_duplicates = FxHashMap::<(usize, ItemType, Symbol), usize>::default();
1500    for item in crate_items.iter().map(|x| &*x) {
1501        if item.impl_id.is_some()
1502            && let Some(parent_idx) = item.parent_idx
1503        {
1504            let count =
1505                associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0);
1506            *count += 1;
1507        }
1508    }
1509
1510    // now populate the actual entries, type data, and function data
1511    for item in crate_items {
1512        assert_eq!(
1513            item.parent.is_some(),
1514            item.parent_idx.is_some(),
1515            "`{}` is missing idx",
1516            item.name
1517        );
1518
1519        let module_path = Some(serialized_index.get_id_by_module_path(&item.module_path));
1520        let exact_module_path = item
1521            .exact_module_path
1522            .as_ref()
1523            .map(|path| serialized_index.get_id_by_module_path(path));
1524
1525        let new_entry_id = serialized_index.add_entry(
1526            item.name,
1527            EntryData {
1528                ty: item.ty,
1529                parent: item.parent_idx,
1530                trait_parent: item.trait_parent_idx,
1531                module_path,
1532                exact_module_path,
1533                deprecated: item.is_deprecated,
1534                unstable: item.is_unstable,
1535                associated_item_disambiguator_or_extern_crate_url: if let Some(impl_id) =
1536                    item.impl_id
1537                    && let Some(parent_idx) = item.parent_idx
1538                    && associated_item_duplicates
1539                        .get(&(parent_idx, item.ty, item.name))
1540                        .copied()
1541                        .unwrap_or(0)
1542                        > 1
1543                {
1544                    Some(render::get_id_for_impl(tcx, ItemId::DefId(impl_id)))
1545                } else if item.ty == ItemType::ExternCrate
1546                    && let Some(local_def_id) = item.defid.and_then(|def_id| def_id.as_local())
1547                    && let cnum = tcx.extern_mod_stmt_cnum(local_def_id).unwrap_or(LOCAL_CRATE)
1548                    && let Some(ExternalLocation::Remote { url, is_absolute }) =
1549                        cache.extern_locations.get(&cnum)
1550                    && *is_absolute
1551                {
1552                    Some(format!("{}{}", url, tcx.crate_name(cnum).as_str()))
1553                } else {
1554                    None
1555                },
1556                krate: crate_idx,
1557            },
1558            item.desc.to_string(),
1559        );
1560
1561        // Aliases
1562        // -------
1563        for alias in &item.aliases[..] {
1564            serialized_index.push_alias(alias.as_str().to_string(), new_entry_id);
1565        }
1566
1567        // Function signature reverse index
1568        // --------------------------------
1569        fn insert_into_map(
1570            ty: ItemType,
1571            path: &[Symbol],
1572            exact_path: Option<&[Symbol]>,
1573            search_unbox: bool,
1574            serialized_index: &mut SerializedSearchIndex,
1575            used_in_function_signature: &mut BTreeSet<isize>,
1576        ) -> RenderTypeId {
1577            let pathid = serialized_index.names.len();
1578            let pathid = match serialized_index.crate_paths_index.entry((ty, path.to_vec())) {
1579                Entry::Occupied(entry) => {
1580                    let id = *entry.get();
1581                    if serialized_index.type_data[id].as_mut().is_none() {
1582                        serialized_index.type_data[id] = Some(TypeData {
1583                            search_unbox,
1584                            inverted_function_inputs_index: Vec::new(),
1585                            inverted_function_output_index: Vec::new(),
1586                        });
1587                    } else if search_unbox {
1588                        serialized_index.type_data[id].as_mut().unwrap().search_unbox = true;
1589                    }
1590                    id
1591                }
1592                Entry::Vacant(entry) => {
1593                    entry.insert(pathid);
1594                    let (name, path) = path.split_last().unwrap();
1595                    serialized_index.push_type(
1596                        name.to_string(),
1597                        PathData {
1598                            ty,
1599                            module_path: path.to_vec(),
1600                            exact_module_path: if let Some(exact_path) = exact_path
1601                                && let Some((name2, exact_path)) = exact_path.split_last()
1602                                && name == name2
1603                            {
1604                                Some(exact_path.to_vec())
1605                            } else {
1606                                None
1607                            },
1608                        },
1609                        TypeData {
1610                            inverted_function_inputs_index: Vec::new(),
1611                            inverted_function_output_index: Vec::new(),
1612                            search_unbox,
1613                        },
1614                    );
1615                    pathid
1616                }
1617            };
1618            used_in_function_signature.insert(isize::try_from(pathid).unwrap());
1619            RenderTypeId::Index(isize::try_from(pathid).unwrap())
1620        }
1621
1622        fn convert_render_type_id(
1623            id: RenderTypeId,
1624            cache: &mut Cache,
1625            serialized_index: &mut SerializedSearchIndex,
1626            used_in_function_signature: &mut BTreeSet<isize>,
1627            tcx: TyCtxt<'_>,
1628        ) -> Option<RenderTypeId> {
1629            use crate::clean::PrimitiveType;
1630            let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache;
1631            let search_unbox = match id {
1632                RenderTypeId::Mut => false,
1633                RenderTypeId::DefId(defid) => {
1634                    utils::has_doc_flag(tcx, defid, |d| d.search_unbox.is_some())
1635                }
1636                RenderTypeId::Primitive(
1637                    PrimitiveType::Reference | PrimitiveType::RawPointer | PrimitiveType::Tuple,
1638                ) => true,
1639                RenderTypeId::Primitive(..) => false,
1640                RenderTypeId::AssociatedType(..) => false,
1641                // this bool is only used by `insert_into_map`, so it doesn't matter what we set here
1642                // because Index means we've already inserted into the map
1643                RenderTypeId::Index(_) => false,
1644            };
1645            match id {
1646                RenderTypeId::Mut => Some(insert_into_map(
1647                    ItemType::Keyword,
1648                    &[kw::Mut],
1649                    None,
1650                    search_unbox,
1651                    serialized_index,
1652                    used_in_function_signature,
1653                )),
1654                RenderTypeId::DefId(defid) => {
1655                    if let Some(&(ref fqp, item_type)) =
1656                        paths.get(&defid).or_else(|| external_paths.get(&defid))
1657                    {
1658                        if tcx.lang_items().fn_mut_trait() == Some(defid)
1659                            || tcx.lang_items().fn_once_trait() == Some(defid)
1660                            || tcx.lang_items().fn_trait() == Some(defid)
1661                        {
1662                            let name = *fqp.last().unwrap();
1663                            // Make absolutely sure we use this single, correct path,
1664                            // because search.js needs to match. If we don't do this,
1665                            // there are three different paths that these traits may
1666                            // appear to come from.
1667                            Some(insert_into_map(
1668                                item_type,
1669                                &[sym::core, sym::ops, name],
1670                                Some(&[sym::core, sym::ops, name]),
1671                                search_unbox,
1672                                serialized_index,
1673                                used_in_function_signature,
1674                            ))
1675                        } else {
1676                            let exact_fqp = exact_paths
1677                                .get(&defid)
1678                                .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
1679                                .map(|v| &v[..])
1680                                // Re-exports only count if the name is exactly the same.
1681                                // This is a size optimization, since it means we only need
1682                                // to store the name once (and the path is re-used for everything
1683                                // exported from this same module). It's also likely to Do
1684                                // What I Mean, since if a re-export changes the name, it might
1685                                // also be a change in semantic meaning.
1686                                .filter(|this_fqp| this_fqp.last() == fqp.last());
1687                            Some(insert_into_map(
1688                                item_type,
1689                                fqp,
1690                                exact_fqp,
1691                                search_unbox,
1692                                serialized_index,
1693                                used_in_function_signature,
1694                            ))
1695                        }
1696                    } else {
1697                        None
1698                    }
1699                }
1700                RenderTypeId::Primitive(primitive) => {
1701                    let sym = primitive.as_sym();
1702                    Some(insert_into_map(
1703                        ItemType::Primitive,
1704                        &[sym],
1705                        None,
1706                        search_unbox,
1707                        serialized_index,
1708                        used_in_function_signature,
1709                    ))
1710                }
1711                RenderTypeId::Index(index) => {
1712                    used_in_function_signature.insert(index);
1713                    Some(id)
1714                }
1715                RenderTypeId::AssociatedType(sym) => Some(insert_into_map(
1716                    ItemType::AssocType,
1717                    &[sym],
1718                    None,
1719                    search_unbox,
1720                    serialized_index,
1721                    used_in_function_signature,
1722                )),
1723            }
1724        }
1725
1726        fn convert_render_type(
1727            ty: &mut RenderType,
1728            cache: &mut Cache,
1729            serialized_index: &mut SerializedSearchIndex,
1730            used_in_function_signature: &mut BTreeSet<isize>,
1731            tcx: TyCtxt<'_>,
1732        ) {
1733            if let Some(generics) = &mut ty.generics {
1734                for item in generics {
1735                    convert_render_type(
1736                        item,
1737                        cache,
1738                        serialized_index,
1739                        used_in_function_signature,
1740                        tcx,
1741                    );
1742                }
1743            }
1744            if let Some(bindings) = &mut ty.bindings {
1745                bindings.retain_mut(|(associated_type, constraints)| {
1746                    let converted_associated_type = convert_render_type_id(
1747                        *associated_type,
1748                        cache,
1749                        serialized_index,
1750                        used_in_function_signature,
1751                        tcx,
1752                    );
1753                    let Some(converted_associated_type) = converted_associated_type else {
1754                        return false;
1755                    };
1756                    *associated_type = converted_associated_type;
1757                    for constraint in constraints {
1758                        convert_render_type(
1759                            constraint,
1760                            cache,
1761                            serialized_index,
1762                            used_in_function_signature,
1763                            tcx,
1764                        );
1765                    }
1766                    true
1767                });
1768            }
1769            let Some(id) = ty.id else {
1770                assert!(ty.generics.is_some());
1771                return;
1772            };
1773            ty.id = convert_render_type_id(
1774                id,
1775                cache,
1776                serialized_index,
1777                used_in_function_signature,
1778                tcx,
1779            );
1780            use crate::clean::PrimitiveType;
1781            // These cases are added to the inverted index, but not actually included
1782            // in the signature. There's a matching set of cases in the
1783            // `unifyFunctionTypeIsMatchCandidate` function, for the slow path.
1784            match id {
1785                // typeNameIdOfArrayOrSlice
1786                RenderTypeId::Primitive(PrimitiveType::Array | PrimitiveType::Slice) => {
1787                    insert_into_map(
1788                        ItemType::Primitive,
1789                        &[Symbol::intern("[]")],
1790                        None,
1791                        false,
1792                        serialized_index,
1793                        used_in_function_signature,
1794                    );
1795                }
1796                RenderTypeId::Primitive(PrimitiveType::Tuple | PrimitiveType::Unit) => {
1797                    // typeNameIdOfArrayOrSlice
1798                    insert_into_map(
1799                        ItemType::Primitive,
1800                        &[Symbol::intern("()")],
1801                        None,
1802                        false,
1803                        serialized_index,
1804                        used_in_function_signature,
1805                    );
1806                }
1807                // typeNameIdOfHof
1808                RenderTypeId::Primitive(PrimitiveType::Fn) => {
1809                    insert_into_map(
1810                        ItemType::Primitive,
1811                        &[Symbol::intern("->")],
1812                        None,
1813                        false,
1814                        serialized_index,
1815                        used_in_function_signature,
1816                    );
1817                }
1818                RenderTypeId::DefId(did)
1819                    if tcx.lang_items().fn_mut_trait() == Some(did)
1820                        || tcx.lang_items().fn_once_trait() == Some(did)
1821                        || tcx.lang_items().fn_trait() == Some(did) =>
1822                {
1823                    insert_into_map(
1824                        ItemType::Primitive,
1825                        &[Symbol::intern("->")],
1826                        None,
1827                        false,
1828                        serialized_index,
1829                        used_in_function_signature,
1830                    );
1831                }
1832                // not special
1833                _ => {}
1834            }
1835        }
1836        if let Some(search_type) = &mut item.search_type {
1837            let mut used_in_function_inputs = BTreeSet::new();
1838            let mut used_in_function_output = BTreeSet::new();
1839            for item in &mut search_type.inputs {
1840                convert_render_type(
1841                    item,
1842                    cache,
1843                    &mut serialized_index,
1844                    &mut used_in_function_inputs,
1845                    tcx,
1846                );
1847            }
1848            for item in &mut search_type.output {
1849                convert_render_type(
1850                    item,
1851                    cache,
1852                    &mut serialized_index,
1853                    &mut used_in_function_output,
1854                    tcx,
1855                );
1856            }
1857            let used_in_constraints = search_type
1858                .where_clause
1859                .iter_mut()
1860                .map(|constraint| {
1861                    let mut used_in_constraint = BTreeSet::new();
1862                    for trait_ in constraint {
1863                        convert_render_type(
1864                            trait_,
1865                            cache,
1866                            &mut serialized_index,
1867                            &mut used_in_constraint,
1868                            tcx,
1869                        );
1870                    }
1871                    used_in_constraint
1872                })
1873                .collect::<Vec<_>>();
1874            loop {
1875                let mut inserted_any = false;
1876                for (i, used_in_constraint) in used_in_constraints.iter().enumerate() {
1877                    let id = !(i as isize);
1878                    if used_in_function_inputs.contains(&id)
1879                        && !used_in_function_inputs.is_superset(&used_in_constraint)
1880                    {
1881                        used_in_function_inputs.extend(used_in_constraint.iter().copied());
1882                        inserted_any = true;
1883                    }
1884                    if used_in_function_output.contains(&id)
1885                        && !used_in_function_output.is_superset(&used_in_constraint)
1886                    {
1887                        used_in_function_output.extend(used_in_constraint.iter().copied());
1888                        inserted_any = true;
1889                    }
1890                }
1891                if !inserted_any {
1892                    break;
1893                }
1894            }
1895            let search_type_size = search_type.size() +
1896                // Artificially give struct fields a size of 8 instead of their real
1897                // size of 2. This is because search.js sorts them to the end, so
1898                // by pushing them down, we prevent them from blocking real 2-arity functions.
1899                //
1900                // The number 8 is arbitrary. We want it big, but not enormous,
1901                // because the postings list has to fill in an empty array for each
1902                // unoccupied size.
1903                if item.ty.is_fn_like() { 0 } else { 16 };
1904            serialized_index.function_data[new_entry_id] = Some(search_type.clone());
1905
1906            #[derive(Clone, Copy)]
1907            enum InvertedIndexType {
1908                Inputs,
1909                Output,
1910            }
1911            impl InvertedIndexType {
1912                fn from_type_data(self, type_data: &mut TypeData) -> &mut Vec<Vec<u32>> {
1913                    match self {
1914                        Self::Inputs => &mut type_data.inverted_function_inputs_index,
1915                        Self::Output => &mut type_data.inverted_function_output_index,
1916                    }
1917                }
1918            }
1919
1920            let mut process_used_in_function =
1921                |used_in_function: BTreeSet<isize>, index_type: InvertedIndexType| {
1922                    for index in used_in_function {
1923                        let postings = if index >= 0 {
1924                            assert!(serialized_index.path_data[index as usize].is_some());
1925                            index_type.from_type_data(
1926                                serialized_index.type_data[index as usize].as_mut().unwrap(),
1927                            )
1928                        } else {
1929                            let generic_id = index.unsigned_abs() - 1;
1930                            if generic_id >= serialized_index.generic_inverted_index.len() {
1931                                serialized_index
1932                                    .generic_inverted_index
1933                                    .resize(generic_id + 1, Vec::new());
1934                            }
1935                            &mut serialized_index.generic_inverted_index[generic_id]
1936                        };
1937                        if search_type_size >= postings.len() {
1938                            postings.resize(search_type_size + 1, Vec::new());
1939                        }
1940                        let posting = &mut postings[search_type_size];
1941                        if posting.last() != Some(&(new_entry_id as u32)) {
1942                            posting.push(new_entry_id as u32);
1943                        }
1944                    }
1945                };
1946
1947            process_used_in_function(used_in_function_inputs, InvertedIndexType::Inputs);
1948            process_used_in_function(used_in_function_output, InvertedIndexType::Output);
1949        }
1950    }
1951
1952    Ok(serialized_index.sort())
1953}
1954
1955pub(crate) fn get_function_type_for_search(
1956    item: &clean::Item,
1957    tcx: TyCtxt<'_>,
1958    impl_generics: Option<&(clean::Type, clean::Generics)>,
1959    parent: Option<DefId>,
1960    cache: &Cache,
1961) -> Option<IndexItemFunctionType> {
1962    let mut trait_info = None;
1963    let impl_or_trait_generics = impl_generics.or_else(|| {
1964        if let Some(def_id) = parent
1965            && let Some(trait_) = cache.traits.get(&def_id)
1966            && let Some((path, _)) =
1967                cache.paths.get(&def_id).or_else(|| cache.external_paths.get(&def_id))
1968        {
1969            let path = clean::Path {
1970                res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, def_id),
1971                segments: path
1972                    .iter()
1973                    .map(|name| clean::PathSegment {
1974                        name: *name,
1975                        args: clean::GenericArgs::AngleBracketed {
1976                            args: ThinVec::new(),
1977                            constraints: ThinVec::new(),
1978                        },
1979                    })
1980                    .collect(),
1981            };
1982            trait_info = Some((clean::Type::Path { path }, trait_.generics.clone()));
1983            Some(trait_info.as_ref().unwrap())
1984        } else {
1985            None
1986        }
1987    });
1988    let (mut inputs, mut output, param_names, where_clause) = match item.kind {
1989        clean::ForeignFunctionItem(ref f, _)
1990        | clean::FunctionItem(ref f)
1991        | clean::MethodItem(ref f, _)
1992        | clean::RequiredMethodItem(ref f, _) => {
1993            get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
1994        }
1995        clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
1996        clean::StaticItem(ref s) => make_nullary_fn(&s.type_),
1997        clean::StructFieldItem(ref t) if let Some(parent) = parent => {
1998            let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> =
1999                Default::default();
2000            let output = get_index_type(t, vec![], &mut rgen);
2001            let input = RenderType {
2002                id: Some(RenderTypeId::DefId(parent)),
2003                generics: None,
2004                bindings: None,
2005            };
2006            (vec![input], vec![output], vec![], vec![])
2007        }
2008        _ => return None,
2009    };
2010
2011    inputs.retain(|a| a.id.is_some() || a.generics.is_some());
2012    output.retain(|a| a.id.is_some() || a.generics.is_some());
2013
2014    Some(IndexItemFunctionType { inputs, output, where_clause, param_names })
2015}
2016
2017fn get_index_type(
2018    clean_type: &clean::Type,
2019    generics: Vec<RenderType>,
2020    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2021) -> RenderType {
2022    RenderType {
2023        id: get_index_type_id(clean_type, rgen),
2024        generics: if generics.is_empty() { None } else { Some(generics) },
2025        bindings: None,
2026    }
2027}
2028
2029fn get_index_type_id(
2030    clean_type: &clean::Type,
2031    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2032) -> Option<RenderTypeId> {
2033    use rustc_hir::def::{DefKind, Res};
2034    match *clean_type {
2035        clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
2036        clean::DynTrait(ref bounds, _) => {
2037            bounds.first().map(|b| RenderTypeId::DefId(b.trait_.def_id()))
2038        }
2039        clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
2040        clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)),
2041        clean::RawPointer { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)),
2042        // The type parameters are converted to generics in `simplify_fn_type`
2043        clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
2044        clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
2045        clean::BareFunction(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Fn)),
2046        clean::Tuple(ref n) if n.is_empty() => {
2047            Some(RenderTypeId::Primitive(clean::PrimitiveType::Unit))
2048        }
2049        clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
2050        clean::QPath(ref data) => {
2051            if data.self_type.is_self_type()
2052                && let Some(clean::Path { res: Res::Def(DefKind::Trait, trait_), .. }) = data.trait_
2053            {
2054                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2055                let (idx, _) = rgen
2056                    .entry(SimplifiedParam::AssociatedType(trait_, data.assoc.name))
2057                    .or_insert_with(|| (idx, Vec::new()));
2058                Some(RenderTypeId::Index(*idx))
2059            } else {
2060                None
2061            }
2062        }
2063        // Not supported yet
2064        clean::Type::Pat(..)
2065        | clean::Type::FieldOf(..)
2066        | clean::Generic(_)
2067        | clean::SelfTy
2068        | clean::ImplTrait(_)
2069        | clean::Infer
2070        | clean::UnsafeBinder(_) => None,
2071    }
2072}
2073
2074#[derive(Clone, Copy, Eq, Hash, PartialEq)]
2075enum SimplifiedParam {
2076    // other kinds of type parameters are identified by their name
2077    Symbol(Symbol),
2078    // every argument-position impl trait is its own type parameter
2079    Anonymous(isize),
2080    // in a trait definition, the associated types are all bound to
2081    // their own type parameter
2082    AssociatedType(DefId, Symbol),
2083}
2084
2085/// The point of this function is to lower generics and types into the simplified form that the
2086/// frontend search engine can use.
2087///
2088/// For example, `[T, U, i32]]` where you have the bounds: `T: Display, U: Option<T>` will return
2089/// `[-1, -2, i32] where -1: Display, -2: Option<-1>`. If a type parameter has no trait bound, it
2090/// will still get a number. If a constraint is present but not used in the actual types, it will
2091/// not be added to the map.
2092///
2093/// This function also works recursively.
2094#[instrument(level = "trace", skip(tcx, rgen, cache))]
2095fn simplify_fn_type<'a, 'tcx>(
2096    self_: Option<&'a Type>,
2097    generics: &Generics,
2098    arg: &'a Type,
2099    tcx: TyCtxt<'tcx>,
2100    recurse: usize,
2101    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2102    is_return: bool,
2103    cache: &Cache,
2104) -> Option<RenderType> {
2105    if recurse >= 10 {
2106        // FIXME: remove this whole recurse thing when the recursion bug is fixed
2107        // See #59502 for the original issue.
2108        return None;
2109    }
2110
2111    // First, check if it's "Self".
2112    let (is_self, arg) = if let Some(self_) = self_
2113        && arg.is_self_type()
2114    {
2115        (true, self_)
2116    } else {
2117        (false, arg)
2118    };
2119
2120    // If this argument is a type parameter and not a trait bound or a type, we need to look
2121    // for its bounds.
2122    match *arg {
2123        Type::Generic(arg_s) => {
2124            // First we check if the bounds are in a `where` predicate...
2125            let where_bounds = generics
2126                .where_predicates
2127                .iter()
2128                .filter_map(|g| {
2129                    if let WherePredicate::BoundPredicate { ty, bounds, .. } = g
2130                        && *ty == *arg
2131                    {
2132                        Some(bounds)
2133                    } else {
2134                        None
2135                    }
2136                })
2137                .flatten();
2138            // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
2139            let inline_bounds = generics
2140                .params
2141                .iter()
2142                .find(|g| g.is_type() && g.name == arg_s)
2143                .and_then(|bound| bound.get_bounds())
2144                .into_iter()
2145                .flatten();
2146
2147            let type_bounds = where_bounds
2148                .chain(inline_bounds)
2149                .filter_map(
2150                    |bound| if let Some(path) = bound.get_trait_path() { Some(path) } else { None },
2151                )
2152                .filter_map(|path| {
2153                    let ty = Type::Path { path };
2154                    simplify_fn_type(self_, generics, &ty, tcx, recurse + 1, rgen, is_return, cache)
2155                })
2156                .collect();
2157
2158            Some(if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
2159                RenderType { id: Some(RenderTypeId::Index(*idx)), generics: None, bindings: None }
2160            } else {
2161                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2162                rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
2163                RenderType { id: Some(RenderTypeId::Index(idx)), generics: None, bindings: None }
2164            })
2165        }
2166        Type::ImplTrait(ref bounds) => {
2167            let type_bounds = bounds
2168                .iter()
2169                .filter_map(|bound| bound.get_trait_path())
2170                .filter_map(|path| {
2171                    let ty = Type::Path { path };
2172                    simplify_fn_type(self_, generics, &ty, tcx, recurse + 1, rgen, is_return, cache)
2173                })
2174                .collect::<Vec<_>>();
2175            Some(if is_return && !type_bounds.is_empty() {
2176                // In return position, `impl Trait` is a unique thing.
2177                RenderType { id: None, generics: Some(type_bounds), bindings: None }
2178            } else {
2179                // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
2180                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2181                rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
2182                RenderType { id: Some(RenderTypeId::Index(idx)), generics: None, bindings: None }
2183            })
2184        }
2185        Type::Slice(ref ty) => {
2186            let ty_generics =
2187                simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2188                    .into_iter()
2189                    .collect();
2190            Some(get_index_type(arg, ty_generics, rgen))
2191        }
2192        Type::Array(ref ty, _) => {
2193            let ty_generics =
2194                simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2195                    .into_iter()
2196                    .collect();
2197            Some(get_index_type(arg, ty_generics, rgen))
2198        }
2199        Type::Tuple(ref tys) => {
2200            let ty_generics = tys
2201                .iter()
2202                .filter_map(|ty| {
2203                    simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2204                })
2205                .collect();
2206            Some(get_index_type(arg, ty_generics, rgen))
2207        }
2208        Type::BareFunction(ref bf) => {
2209            let ty_generics = bf
2210                .decl
2211                .inputs
2212                .iter()
2213                .map(|arg| &arg.type_)
2214                .filter_map(|ty| {
2215                    simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2216                })
2217                .collect();
2218            // The search index, for simplicity's sake, represents fn pointers and closures
2219            // the same way: as a tuple for the parameters, and an associated type for the
2220            // return type.
2221            let ty_output = simplify_fn_type(
2222                self_,
2223                generics,
2224                &bf.decl.output,
2225                tcx,
2226                recurse + 1,
2227                rgen,
2228                is_return,
2229                cache,
2230            )
2231            .into_iter()
2232            .collect();
2233            let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
2234            Some(RenderType {
2235                id: get_index_type_id(arg, rgen),
2236                bindings: Some(ty_bindings),
2237                generics: Some(ty_generics),
2238            })
2239        }
2240        Type::BorrowedRef { lifetime: _, mutability, ref type_ }
2241        | Type::RawPointer(mutability, ref type_) => {
2242            let mut ty_generics = Vec::new();
2243            if mutability.is_mut() {
2244                ty_generics.push(RenderType {
2245                    id: Some(RenderTypeId::Mut),
2246                    generics: None,
2247                    bindings: None,
2248                });
2249            }
2250            if let Some(ty) =
2251                simplify_fn_type(self_, generics, type_, tcx, recurse + 1, rgen, is_return, cache)
2252            {
2253                ty_generics.push(ty);
2254            }
2255            Some(get_index_type(arg, ty_generics, rgen))
2256        }
2257        _ => {
2258            // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
2259            // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
2260            //
2261            // So in here, we can add it directly and look for its own type parameters (so for `Option`,
2262            // we will look for them but not for `T`).
2263            let mut ty_generics = Vec::new();
2264            let mut ty_constraints = Vec::new();
2265            if let Some(arg_generics) = arg.generic_args() {
2266                ty_generics = arg_generics
2267                    .into_iter()
2268                    .filter_map(|param| match param {
2269                        clean::GenericArg::Type(ty) => Some(ty),
2270                        _ => None,
2271                    })
2272                    .filter_map(|ty| {
2273                        simplify_fn_type(
2274                            self_,
2275                            generics,
2276                            &ty,
2277                            tcx,
2278                            recurse + 1,
2279                            rgen,
2280                            is_return,
2281                            cache,
2282                        )
2283                    })
2284                    .collect();
2285                for constraint in arg_generics.constraints() {
2286                    simplify_fn_constraint(
2287                        self_,
2288                        generics,
2289                        &constraint,
2290                        tcx,
2291                        recurse + 1,
2292                        &mut ty_constraints,
2293                        rgen,
2294                        is_return,
2295                        cache,
2296                    );
2297                }
2298            }
2299            // Every trait associated type on self gets assigned to a type parameter index
2300            // this same one is used later for any appearances of these types
2301            //
2302            // for example, Iterator::next is:
2303            //
2304            //     trait Iterator {
2305            //         fn next(&mut self) -> Option<Self::Item>
2306            //     }
2307            //
2308            // Self is technically just Iterator, but we want to pretend it's more like this:
2309            //
2310            //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
2311            if is_self
2312                && let Type::Path { path } = arg
2313                && let def_id = path.def_id()
2314                && let Some(trait_) = cache.traits.get(&def_id)
2315                && trait_.items.iter().any(|at| at.is_required_associated_type())
2316            {
2317                for assoc_ty in &trait_.items {
2318                    if let clean::ItemKind::RequiredAssocTypeItem(_generics, bounds) =
2319                        &assoc_ty.kind
2320                        && let Some(name) = assoc_ty.name
2321                    {
2322                        let idx = -isize::try_from(rgen.len() + 1).unwrap();
2323                        let (idx, stored_bounds) = rgen
2324                            .entry(SimplifiedParam::AssociatedType(def_id, name))
2325                            .or_insert_with(|| (idx, Vec::new()));
2326                        let idx = *idx;
2327                        if stored_bounds.is_empty() {
2328                            // Can't just pass stored_bounds to simplify_fn_type,
2329                            // because it also accepts rgen as a parameter.
2330                            // Instead, have it fill in this local, then copy it into the map afterward.
2331                            let type_bounds = bounds
2332                                .iter()
2333                                .filter_map(|bound| bound.get_trait_path())
2334                                .filter_map(|path| {
2335                                    let ty = Type::Path { path };
2336                                    simplify_fn_type(
2337                                        self_,
2338                                        generics,
2339                                        &ty,
2340                                        tcx,
2341                                        recurse + 1,
2342                                        rgen,
2343                                        is_return,
2344                                        cache,
2345                                    )
2346                                })
2347                                .collect();
2348                            let stored_bounds = &mut rgen
2349                                .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
2350                                .unwrap()
2351                                .1;
2352                            if stored_bounds.is_empty() {
2353                                *stored_bounds = type_bounds;
2354                            }
2355                        }
2356                        ty_constraints.push((
2357                            RenderTypeId::AssociatedType(name),
2358                            vec![RenderType {
2359                                id: Some(RenderTypeId::Index(idx)),
2360                                generics: None,
2361                                bindings: None,
2362                            }],
2363                        ))
2364                    }
2365                }
2366            }
2367            let id = get_index_type_id(arg, rgen);
2368            if id.is_some() || !ty_generics.is_empty() {
2369                Some(RenderType {
2370                    id,
2371                    bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
2372                    generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
2373                })
2374            } else {
2375                None
2376            }
2377        }
2378    }
2379}
2380
2381fn simplify_fn_constraint<'a>(
2382    self_: Option<&'a Type>,
2383    generics: &Generics,
2384    constraint: &'a clean::AssocItemConstraint,
2385    tcx: TyCtxt<'_>,
2386    recurse: usize,
2387    res: &mut Vec<(RenderTypeId, Vec<RenderType>)>,
2388    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2389    is_return: bool,
2390    cache: &Cache,
2391) {
2392    let mut ty_constraints = Vec::new();
2393    let ty_constrained_assoc = RenderTypeId::AssociatedType(constraint.assoc.name);
2394    for param in &constraint.assoc.args {
2395        match param {
2396            clean::GenericArg::Type(arg) => {
2397                ty_constraints.extend(simplify_fn_type(
2398                    self_,
2399                    generics,
2400                    &arg,
2401                    tcx,
2402                    recurse + 1,
2403                    rgen,
2404                    is_return,
2405                    cache,
2406                ));
2407            }
2408            clean::GenericArg::Lifetime(_)
2409            | clean::GenericArg::Const(_)
2410            | clean::GenericArg::Infer => {}
2411        }
2412    }
2413    for constraint in constraint.assoc.args.constraints() {
2414        simplify_fn_constraint(
2415            self_,
2416            generics,
2417            &constraint,
2418            tcx,
2419            recurse + 1,
2420            res,
2421            rgen,
2422            is_return,
2423            cache,
2424        );
2425    }
2426    match &constraint.kind {
2427        clean::AssocItemConstraintKind::Equality { term } => {
2428            if let clean::Term::Type(arg) = &term {
2429                ty_constraints.extend(simplify_fn_type(
2430                    self_,
2431                    generics,
2432                    arg,
2433                    tcx,
2434                    recurse + 1,
2435                    rgen,
2436                    is_return,
2437                    cache,
2438                ));
2439            }
2440        }
2441        clean::AssocItemConstraintKind::Bound { bounds } => {
2442            for bound in &bounds[..] {
2443                if let Some(path) = bound.get_trait_path() {
2444                    let ty = Type::Path { path };
2445                    ty_constraints.extend(simplify_fn_type(
2446                        self_,
2447                        generics,
2448                        &ty,
2449                        tcx,
2450                        recurse + 1,
2451                        rgen,
2452                        is_return,
2453                        cache,
2454                    ));
2455                }
2456            }
2457        }
2458    }
2459    res.push((ty_constrained_assoc, ty_constraints));
2460}
2461
2462/// Create a fake nullary function.
2463///
2464/// Used to allow type-based search on constants and statics.
2465fn make_nullary_fn(
2466    clean_type: &clean::Type,
2467) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
2468    let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
2469    let output = get_index_type(clean_type, vec![], &mut rgen);
2470    (vec![], vec![output], vec![], vec![])
2471}
2472
2473/// Return the full list of types when bounds have been resolved.
2474///
2475/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
2476/// `[u32, Display, Option]`.
2477fn get_fn_inputs_and_outputs(
2478    func: &Function,
2479    tcx: TyCtxt<'_>,
2480    impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
2481    cache: &Cache,
2482) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
2483    let decl = &func.decl;
2484
2485    let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
2486
2487    let combined_generics;
2488    let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics {
2489        match (impl_generics.is_empty(), func.generics.is_empty()) {
2490            (true, _) => (Some(impl_self), &func.generics),
2491            (_, true) => (Some(impl_self), impl_generics),
2492            (false, false) => {
2493                let params =
2494                    func.generics.params.iter().chain(&impl_generics.params).cloned().collect();
2495                let where_predicates = func
2496                    .generics
2497                    .where_predicates
2498                    .iter()
2499                    .chain(&impl_generics.where_predicates)
2500                    .cloned()
2501                    .collect();
2502                combined_generics = clean::Generics { params, where_predicates };
2503                (Some(impl_self), &combined_generics)
2504            }
2505        }
2506    } else {
2507        (None, &func.generics)
2508    };
2509
2510    let param_types = decl
2511        .inputs
2512        .iter()
2513        .filter_map(|param| {
2514            simplify_fn_type(self_, generics, &param.type_, tcx, 0, &mut rgen, false, cache)
2515        })
2516        .collect();
2517
2518    let ret_types = simplify_fn_type(self_, generics, &decl.output, tcx, 0, &mut rgen, true, cache)
2519        .into_iter()
2520        .collect();
2521
2522    let mut simplified_params = rgen.into_iter().collect::<Vec<_>>();
2523    simplified_params.sort_by_key(|(_, (idx, _))| -idx);
2524    (
2525        param_types,
2526        ret_types,
2527        simplified_params
2528            .iter()
2529            .map(|(name, (_idx, _traits))| match name {
2530                SimplifiedParam::Symbol(name) => Some(*name),
2531                SimplifiedParam::Anonymous(_) => None,
2532                SimplifiedParam::AssociatedType(def_id, name) => {
2533                    Some(Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name)))
2534                }
2535            })
2536            .collect(),
2537        simplified_params.into_iter().map(|(_name, (_idx, traits))| traits).collect(),
2538    )
2539}