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