Skip to main content

rustdoc/html/render/
search_index.rs

1pub(crate) mod encode;
2mod serde;
3
4use std::collections::BTreeSet;
5use std::collections::hash_map::Entry;
6use std::path::Path;
7use std::string::FromUtf8Error;
8use std::{io, iter};
9
10use ::serde::de::{self, Deserializer, Error as _};
11use ::serde::ser::{SerializeSeq, Serializer};
12use ::serde::{Deserialize, Serialize};
13use rustc_ast::join_path_syms;
14use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
15use rustc_data_structures::thin_vec::ThinVec;
16use rustc_hir::find_attr;
17use rustc_middle::ty::TyCtxt;
18use rustc_span::def_id::DefId;
19use rustc_span::sym;
20use rustc_span::symbol::{Symbol, kw};
21use stringdex::internals as stringdex_internals;
22use tracing::instrument;
23
24use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
25use crate::clean::{self, utils};
26use crate::config::ShouldMerge;
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                         unstable,
619                         associated_item_disambiguator,
620                     }| EntryData {
621                        krate: *map.get(krate).unwrap(),
622                        ty: *ty,
623                        module_path: module_path.and_then(|path_id| map.get(&path_id).copied()),
624                        exact_module_path: exact_module_path
625                            .and_then(|path_id| map.get(&path_id).copied()),
626                        parent: parent.and_then(|path_id| map.get(&path_id).copied()),
627                        trait_parent: trait_parent.and_then(|path_id| map.get(&path_id).copied()),
628                        deprecated: *deprecated,
629                        unstable: *unstable,
630                        associated_item_disambiguator: associated_item_disambiguator.clone(),
631                    },
632                ),
633                self.descs[id].clone(),
634                self.function_data[id].clone().map(|mut func| {
635                    fn map_fn_sig_item(map: &FxHashMap<usize, usize>, ty: &mut RenderType) {
636                        match ty.id {
637                            None => {}
638                            Some(RenderTypeId::Index(generic)) if generic < 0 => {}
639                            Some(RenderTypeId::Index(id)) => {
640                                let id = usize::try_from(id).unwrap();
641                                let id = *map.get(&id).unwrap();
642                                assert!(id != !0);
643                                ty.id = Some(RenderTypeId::Index(isize::try_from(id).unwrap()));
644                            }
645                            _ => unreachable!(),
646                        }
647                        if let Some(generics) = &mut ty.generics {
648                            for generic in generics {
649                                map_fn_sig_item(map, generic);
650                            }
651                        }
652                        if let Some(bindings) = &mut ty.bindings {
653                            for (param, constraints) in bindings {
654                                *param = match *param {
655                                    param @ RenderTypeId::Index(generic) if generic < 0 => param,
656                                    RenderTypeId::Index(id) => {
657                                        let id = usize::try_from(id).unwrap();
658                                        let id = *map.get(&id).unwrap();
659                                        assert!(id != !0);
660                                        RenderTypeId::Index(isize::try_from(id).unwrap())
661                                    }
662                                    _ => unreachable!(),
663                                };
664                                for constraint in constraints {
665                                    map_fn_sig_item(map, constraint);
666                                }
667                            }
668                        }
669                    }
670                    for input in &mut func.inputs {
671                        map_fn_sig_item(&map, input);
672                    }
673                    for output in &mut func.output {
674                        map_fn_sig_item(&map, output);
675                    }
676                    for clause in &mut func.where_clause {
677                        for entry in clause {
678                            map_fn_sig_item(&map, entry);
679                        }
680                    }
681                    func
682                }),
683                self.type_data[id].as_ref().map(
684                    |TypeData {
685                         search_unbox,
686                         inverted_function_inputs_index,
687                         inverted_function_output_index,
688                     }| {
689                        let inverted_function_inputs_index: Vec<Vec<u32>> =
690                            inverted_function_inputs_index
691                                .iter()
692                                .cloned()
693                                .map(|mut list| {
694                                    for id in &mut list {
695                                        *id = u32::try_from(
696                                            *map.get(&usize::try_from(*id).unwrap()).unwrap(),
697                                        )
698                                        .unwrap();
699                                    }
700                                    list.sort();
701                                    list
702                                })
703                                .collect();
704                        let inverted_function_output_index: Vec<Vec<u32>> =
705                            inverted_function_output_index
706                                .iter()
707                                .cloned()
708                                .map(|mut list| {
709                                    for id in &mut list {
710                                        *id = u32::try_from(
711                                            *map.get(&usize::try_from(*id).unwrap()).unwrap(),
712                                        )
713                                        .unwrap();
714                                    }
715                                    list.sort();
716                                    list
717                                })
718                                .collect();
719                        TypeData {
720                            search_unbox: *search_unbox,
721                            inverted_function_inputs_index,
722                            inverted_function_output_index,
723                        }
724                    },
725                ),
726                self.alias_pointers[id].and_then(|alias| {
727                    if self.names[alias].is_empty() { None } else { map.get(&alias).copied() }
728                }),
729            );
730        }
731        new.generic_inverted_index = self
732            .generic_inverted_index
733            .into_iter()
734            .map(|mut postings| {
735                for list in postings.iter_mut() {
736                    let mut new_list: Vec<u32> = list
737                        .iter()
738                        .copied()
739                        .filter_map(|id| u32::try_from(*map.get(&usize::try_from(id).ok()?)?).ok())
740                        .collect();
741                    new_list.sort();
742                    *list = new_list;
743                }
744                postings
745            })
746            .collect();
747        new
748    }
749
750    pub(crate) fn write_to(self, doc_root: &Path, resource_suffix: &str) -> Result<(), Error> {
751        let SerializedSearchIndex {
752            names,
753            path_data,
754            entry_data,
755            descs,
756            function_data,
757            type_data,
758            alias_pointers,
759            generic_inverted_index,
760            crate_paths_index: _,
761        } = self;
762        let mut serialized_root = Vec::new();
763        serialized_root.extend_from_slice(br#"rr_('{"normalizedName":{"I":""#);
764        let normalized_names = names
765            .iter()
766            .map(|name| {
767                if name.contains("_") {
768                    name.replace("_", "").to_ascii_lowercase()
769                } else {
770                    name.to_ascii_lowercase()
771                }
772            })
773            .collect::<Vec<String>>();
774        let names_search_tree = stringdex_internals::tree::encode_search_tree_ukkonen(
775            normalized_names.iter().map(|name| name.as_bytes()),
776        );
777        let dir_path = doc_root.join(format!("search.index/"));
778        let _ = std::fs::remove_dir_all(&dir_path); // if already missing, no problem
779        stringdex_internals::write_tree_to_disk(
780            &names_search_tree,
781            &dir_path,
782            &mut serialized_root,
783        )
784        .map_err(|error| Error {
785            file: dir_path,
786            error: format!("failed to write name tree to disk: {error}"),
787        })?;
788        std::mem::drop(names_search_tree);
789        serialized_root.extend_from_slice(br#"","#);
790        serialized_root.extend_from_slice(&perform_write_strings(
791            doc_root,
792            "normalizedName",
793            normalized_names.into_iter(),
794        )?);
795        serialized_root.extend_from_slice(br#"},"crateNames":{"#);
796        let mut crates: Vec<&[u8]> = entry_data
797            .iter()
798            .filter_map(|entry_data| Some(names[entry_data.as_ref()?.krate].as_bytes()))
799            .collect();
800        crates.sort();
801        crates.dedup();
802        serialized_root.extend_from_slice(&perform_write_strings(
803            doc_root,
804            "crateNames",
805            crates.into_iter(),
806        )?);
807        serialized_root.extend_from_slice(br#"},"name":{"#);
808        serialized_root.extend_from_slice(&perform_write_strings(doc_root, "name", names.iter())?);
809        serialized_root.extend_from_slice(br#"},"path":{"#);
810        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "path", path_data)?);
811        serialized_root.extend_from_slice(br#"},"entry":{"#);
812        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "entry", entry_data)?);
813        serialized_root.extend_from_slice(br#"},"desc":{"#);
814        serialized_root.extend_from_slice(&perform_write_strings(
815            doc_root,
816            "desc",
817            descs.into_iter(),
818        )?);
819        serialized_root.extend_from_slice(br#"},"function":{"#);
820        serialized_root.extend_from_slice(&perform_write_serde(
821            doc_root,
822            "function",
823            function_data,
824        )?);
825        serialized_root.extend_from_slice(br#"},"type":{"#);
826        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "type", type_data)?);
827        serialized_root.extend_from_slice(br#"},"alias":{"#);
828        serialized_root.extend_from_slice(&perform_write_serde(doc_root, "alias", alias_pointers)?);
829        serialized_root.extend_from_slice(br#"},"generic_inverted_index":{"#);
830        serialized_root.extend_from_slice(&perform_write_postings(
831            doc_root,
832            "generic_inverted_index",
833            generic_inverted_index,
834        )?);
835        serialized_root.extend_from_slice(br#"}}')"#);
836        fn perform_write_strings(
837            doc_root: &Path,
838            dirname: &str,
839            mut column: impl Iterator<Item = impl AsRef<[u8]> + Clone> + ExactSizeIterator,
840        ) -> Result<Vec<u8>, Error> {
841            let dir_path = doc_root.join(format!("search.index/{dirname}"));
842            stringdex_internals::write_data_to_disk(&mut column, &dir_path).map_err(|error| Error {
843                file: dir_path,
844                error: format!("failed to write column to disk: {error}"),
845            })
846        }
847        fn perform_write_serde(
848            doc_root: &Path,
849            dirname: &str,
850            column: Vec<Option<impl Serialize>>,
851        ) -> Result<Vec<u8>, Error> {
852            perform_write_strings(
853                doc_root,
854                dirname,
855                column.into_iter().map(|value| {
856                    if let Some(value) = value {
857                        serde_json::to_vec(&value).unwrap()
858                    } else {
859                        Vec::new()
860                    }
861                }),
862            )
863        }
864        fn perform_write_postings(
865            doc_root: &Path,
866            dirname: &str,
867            column: Vec<Vec<Vec<u32>>>,
868        ) -> Result<Vec<u8>, Error> {
869            perform_write_strings(
870                doc_root,
871                dirname,
872                column.into_iter().map(|postings| {
873                    let mut buf = Vec::new();
874                    encode::write_postings_to_string(&postings, &mut buf);
875                    buf
876                }),
877            )
878        }
879        std::fs::write(
880            doc_root.join(format!("search.index/root{resource_suffix}.js")),
881            serialized_root,
882        )
883        .map_err(|error| Error {
884            file: doc_root.join(format!("search.index/root{resource_suffix}.js")),
885            error: format!("failed to write root to disk: {error}"),
886        })?;
887        Ok(())
888    }
889}
890
891#[derive(Clone, Debug)]
892struct EntryData {
893    krate: usize,
894    ty: ItemType,
895    module_path: Option<usize>,
896    exact_module_path: Option<usize>,
897    parent: Option<usize>,
898    trait_parent: Option<usize>,
899    deprecated: bool,
900    unstable: bool,
901    associated_item_disambiguator: Option<String>,
902}
903
904impl Serialize for EntryData {
905    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
906    where
907        S: Serializer,
908    {
909        let mut seq = serializer.serialize_seq(None)?;
910        seq.serialize_element(&self.krate)?;
911        seq.serialize_element(&self.ty)?;
912        seq.serialize_element(&self.module_path.map(|id| id + 1).unwrap_or(0))?;
913        seq.serialize_element(&self.exact_module_path.map(|id| id + 1).unwrap_or(0))?;
914        seq.serialize_element(&self.parent.map(|id| id + 1).unwrap_or(0))?;
915        seq.serialize_element(&self.trait_parent.map(|id| id + 1).unwrap_or(0))?;
916        seq.serialize_element(&if self.deprecated { 1 } else { 0 })?;
917        seq.serialize_element(&if self.unstable { 1 } else { 0 })?;
918        if let Some(disambig) = &self.associated_item_disambiguator {
919            seq.serialize_element(&disambig)?;
920        }
921        seq.end()
922    }
923}
924
925impl<'de> Deserialize<'de> for EntryData {
926    fn deserialize<D>(deserializer: D) -> Result<EntryData, D::Error>
927    where
928        D: Deserializer<'de>,
929    {
930        struct EntryDataVisitor;
931        impl<'de> de::Visitor<'de> for EntryDataVisitor {
932            type Value = EntryData;
933            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
934                write!(formatter, "path data")
935            }
936            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<EntryData, A::Error> {
937                let krate: usize =
938                    v.next_element()?.ok_or_else(|| A::Error::missing_field("krate"))?;
939                let ty: ItemType =
940                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
941                let module_path: SerializedOptional32 =
942                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
943                let exact_module_path: SerializedOptional32 = v
944                    .next_element()?
945                    .ok_or_else(|| A::Error::missing_field("exact_module_path"))?;
946                let parent: SerializedOptional32 =
947                    v.next_element()?.ok_or_else(|| A::Error::missing_field("parent"))?;
948                let trait_parent: SerializedOptional32 =
949                    v.next_element()?.ok_or_else(|| A::Error::missing_field("trait_parent"))?;
950
951                let deprecated: u32 = v.next_element()?.unwrap_or(0);
952                let unstable: u32 = v.next_element()?.unwrap_or(0);
953                let associated_item_disambiguator: Option<String> = v.next_element()?;
954                Ok(EntryData {
955                    krate,
956                    ty,
957                    module_path: Option::<i32>::from(module_path).map(|path| path as usize),
958                    exact_module_path: Option::<i32>::from(exact_module_path)
959                        .map(|path| path as usize),
960                    parent: Option::<i32>::from(parent).map(|path| path as usize),
961                    trait_parent: Option::<i32>::from(trait_parent).map(|path| path as usize),
962                    deprecated: deprecated != 0,
963                    unstable: unstable != 0,
964                    associated_item_disambiguator,
965                })
966            }
967        }
968        deserializer.deserialize_any(EntryDataVisitor)
969    }
970}
971
972#[derive(Clone, Debug)]
973struct PathData {
974    ty: ItemType,
975    module_path: Vec<Symbol>,
976    exact_module_path: Option<Vec<Symbol>>,
977}
978
979impl Serialize for PathData {
980    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
981    where
982        S: Serializer,
983    {
984        let mut seq = serializer.serialize_seq(None)?;
985        seq.serialize_element(&self.ty)?;
986        seq.serialize_element(&if self.module_path.is_empty() {
987            String::new()
988        } else {
989            join_path_syms(&self.module_path)
990        })?;
991        if let Some(ref path) = self.exact_module_path {
992            seq.serialize_element(&if path.is_empty() {
993                String::new()
994            } else {
995                join_path_syms(path)
996            })?;
997        }
998        seq.end()
999    }
1000}
1001
1002impl<'de> Deserialize<'de> for PathData {
1003    fn deserialize<D>(deserializer: D) -> Result<PathData, D::Error>
1004    where
1005        D: Deserializer<'de>,
1006    {
1007        struct PathDataVisitor;
1008        impl<'de> de::Visitor<'de> for PathDataVisitor {
1009            type Value = PathData;
1010            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1011                write!(formatter, "path data")
1012            }
1013            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<PathData, A::Error> {
1014                let ty: ItemType =
1015                    v.next_element()?.ok_or_else(|| A::Error::missing_field("ty"))?;
1016                let module_path: String =
1017                    v.next_element()?.ok_or_else(|| A::Error::missing_field("module_path"))?;
1018                let exact_module_path: Option<String> =
1019                    v.next_element()?.and_then(SerializedOptionalString::into);
1020                Ok(PathData {
1021                    ty,
1022                    module_path: if module_path.is_empty() {
1023                        vec![]
1024                    } else {
1025                        module_path.split("::").map(Symbol::intern).collect()
1026                    },
1027                    exact_module_path: exact_module_path.map(|path| {
1028                        if path.is_empty() {
1029                            vec![]
1030                        } else {
1031                            path.split("::").map(Symbol::intern).collect()
1032                        }
1033                    }),
1034                })
1035            }
1036        }
1037        deserializer.deserialize_any(PathDataVisitor)
1038    }
1039}
1040
1041#[derive(Clone, Debug)]
1042struct TypeData {
1043    /// If set to "true", the generics can be matched without having to
1044    /// mention the type itself. The truth table, assuming `Unboxable`
1045    /// has `search_unbox = true` and `Inner` has `search_unbox = false`
1046    ///
1047    /// | **query**          | `Unboxable<Inner>` | `Inner` | `Inner<Unboxable>` |
1048    /// |--------------------|--------------------|---------|--------------------|
1049    /// | `Inner`            | yes                | yes     | yes                |
1050    /// | `Unboxable`        | yes                | no      | no                 |
1051    /// | `Unboxable<Inner>` | yes                | no      | no                 |
1052    /// | `Inner<Unboxable>` | no                 | no      | yes                |
1053    search_unbox: bool,
1054    /// List of functions that mention this type in their type signature,
1055    /// on the left side of the `->` arrow.
1056    ///
1057    /// - The outer layer is sorted by number of types that appear in the
1058    ///   type signature. The search engine iterates over these in order from
1059    ///   smallest to largest. Functions with less stuff in their type
1060    ///   signature are more likely to be what the user wants, because we never
1061    ///   show functions that are *missing* parts of the query, so removing..
1062    ///
1063    /// - The inner layer is the list of functions.
1064    inverted_function_inputs_index: Vec<Vec<u32>>,
1065    /// List of functions that mention this type in their type signature,
1066    /// on the right side of the `->` arrow.
1067    inverted_function_output_index: Vec<Vec<u32>>,
1068}
1069
1070impl Serialize for TypeData {
1071    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1072    where
1073        S: Serializer,
1074    {
1075        let mut seq = serializer.serialize_seq(None)?;
1076        let mut buf = Vec::new();
1077        encode::write_postings_to_string(&self.inverted_function_inputs_index, &mut buf);
1078        let mut serialized_result = Vec::new();
1079        stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result).unwrap();
1080        seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?;
1081        buf.clear();
1082        serialized_result.clear();
1083        encode::write_postings_to_string(&self.inverted_function_output_index, &mut buf);
1084        stringdex_internals::encode::write_base64_to_bytes(&buf, &mut serialized_result).unwrap();
1085        seq.serialize_element(&str::from_utf8(&serialized_result).unwrap())?;
1086        if self.search_unbox {
1087            seq.serialize_element(&1)?;
1088        }
1089        seq.end()
1090    }
1091}
1092
1093impl<'de> Deserialize<'de> for TypeData {
1094    fn deserialize<D>(deserializer: D) -> Result<TypeData, D::Error>
1095    where
1096        D: Deserializer<'de>,
1097    {
1098        struct TypeDataVisitor;
1099        impl<'de> de::Visitor<'de> for TypeDataVisitor {
1100            type Value = TypeData;
1101            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1102                write!(formatter, "type data")
1103            }
1104            fn visit_none<E>(self) -> Result<TypeData, E> {
1105                Ok(TypeData {
1106                    inverted_function_inputs_index: vec![],
1107                    inverted_function_output_index: vec![],
1108                    search_unbox: false,
1109                })
1110            }
1111            fn visit_seq<A: de::SeqAccess<'de>>(self, mut v: A) -> Result<TypeData, A::Error> {
1112                let inverted_function_inputs_index: String =
1113                    v.next_element()?.unwrap_or(String::new());
1114                let inverted_function_output_index: String =
1115                    v.next_element()?.unwrap_or(String::new());
1116                let search_unbox: u32 = v.next_element()?.unwrap_or(0);
1117                let mut idx: Vec<u8> = Vec::new();
1118                stringdex_internals::decode::read_base64_from_bytes(
1119                    inverted_function_inputs_index.as_bytes(),
1120                    &mut idx,
1121                )
1122                .unwrap();
1123                let mut inverted_function_inputs_index = Vec::new();
1124                encode::read_postings_from_string(&mut inverted_function_inputs_index, &idx);
1125                idx.clear();
1126                stringdex_internals::decode::read_base64_from_bytes(
1127                    inverted_function_output_index.as_bytes(),
1128                    &mut idx,
1129                )
1130                .unwrap();
1131                let mut inverted_function_output_index = Vec::new();
1132                encode::read_postings_from_string(&mut inverted_function_output_index, &idx);
1133                Ok(TypeData {
1134                    inverted_function_inputs_index,
1135                    inverted_function_output_index,
1136                    search_unbox: search_unbox == 1,
1137                })
1138            }
1139        }
1140        deserializer.deserialize_any(TypeDataVisitor)
1141    }
1142}
1143
1144enum SerializedOptionalString {
1145    None,
1146    Some(String),
1147}
1148
1149impl From<SerializedOptionalString> for Option<String> {
1150    fn from(me: SerializedOptionalString) -> Option<String> {
1151        match me {
1152            SerializedOptionalString::Some(string) => Some(string),
1153            SerializedOptionalString::None => None,
1154        }
1155    }
1156}
1157
1158impl Serialize for SerializedOptionalString {
1159    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1160    where
1161        S: Serializer,
1162    {
1163        match self {
1164            SerializedOptionalString::Some(string) => string.serialize(serializer),
1165            SerializedOptionalString::None => 0.serialize(serializer),
1166        }
1167    }
1168}
1169impl<'de> Deserialize<'de> for SerializedOptionalString {
1170    fn deserialize<D>(deserializer: D) -> Result<SerializedOptionalString, D::Error>
1171    where
1172        D: Deserializer<'de>,
1173    {
1174        struct SerializedOptionalStringVisitor;
1175        impl<'de> de::Visitor<'de> for SerializedOptionalStringVisitor {
1176            type Value = SerializedOptionalString;
1177            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1178                write!(formatter, "0 or string")
1179            }
1180            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptionalString, E> {
1181                if v != 0 {
1182                    return Err(E::missing_field("not 0"));
1183                }
1184                Ok(SerializedOptionalString::None)
1185            }
1186            fn visit_string<E: de::Error>(self, v: String) -> Result<SerializedOptionalString, E> {
1187                Ok(SerializedOptionalString::Some(v))
1188            }
1189            fn visit_str<E: de::Error>(self, v: &str) -> Result<SerializedOptionalString, E> {
1190                Ok(SerializedOptionalString::Some(v.to_string()))
1191            }
1192        }
1193        deserializer.deserialize_any(SerializedOptionalStringVisitor)
1194    }
1195}
1196
1197enum SerializedOptional32 {
1198    None,
1199    Some(i32),
1200}
1201
1202impl From<SerializedOptional32> for Option<i32> {
1203    fn from(me: SerializedOptional32) -> Option<i32> {
1204        match me {
1205            SerializedOptional32::Some(number) => Some(number),
1206            SerializedOptional32::None => None,
1207        }
1208    }
1209}
1210
1211impl Serialize for SerializedOptional32 {
1212    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1213    where
1214        S: Serializer,
1215    {
1216        match self {
1217            &SerializedOptional32::Some(number) if number < 0 => number.serialize(serializer),
1218            &SerializedOptional32::Some(number) => (number + 1).serialize(serializer),
1219            &SerializedOptional32::None => 0.serialize(serializer),
1220        }
1221    }
1222}
1223impl<'de> Deserialize<'de> for SerializedOptional32 {
1224    fn deserialize<D>(deserializer: D) -> Result<SerializedOptional32, D::Error>
1225    where
1226        D: Deserializer<'de>,
1227    {
1228        struct SerializedOptional32Visitor;
1229        impl<'de> de::Visitor<'de> for SerializedOptional32Visitor {
1230            type Value = SerializedOptional32;
1231            fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1232                write!(formatter, "integer")
1233            }
1234            fn visit_i64<E: de::Error>(self, v: i64) -> Result<SerializedOptional32, E> {
1235                Ok(match v {
1236                    0 => SerializedOptional32::None,
1237                    v if v < 0 => SerializedOptional32::Some(v as i32),
1238                    v => SerializedOptional32::Some(v as i32 - 1),
1239                })
1240            }
1241            fn visit_u64<E: de::Error>(self, v: u64) -> Result<SerializedOptional32, E> {
1242                Ok(match v {
1243                    0 => SerializedOptional32::None,
1244                    v => SerializedOptional32::Some(v as i32 - 1),
1245                })
1246            }
1247        }
1248        deserializer.deserialize_any(SerializedOptional32Visitor)
1249    }
1250}
1251
1252/// Builds the search index from the collected metadata
1253pub(crate) fn build_index(
1254    krate: &clean::Crate,
1255    cache: &mut Cache,
1256    tcx: TyCtxt<'_>,
1257    doc_root: &Path,
1258    resource_suffix: &str,
1259    should_merge: &ShouldMerge,
1260) -> Result<SerializedSearchIndex, Error> {
1261    let mut search_index = std::mem::take(&mut cache.search_index);
1262
1263    // Attach all orphan items to the type's definition if the type
1264    // has since been learned.
1265    for &OrphanImplItem { impl_id, parent, trait_parent, ref item, ref impl_generics } in
1266        &cache.orphan_impl_items
1267    {
1268        if let Some((fqp, _)) = cache.paths.get(&parent) {
1269            let desc = short_markdown_summary(&item.doc_value(), &item.link_names(cache));
1270            search_index.push(IndexItem {
1271                ty: item.type_(),
1272                defid: item.item_id.as_def_id(),
1273                name: item.name.unwrap(),
1274                module_path: fqp[..fqp.len() - 1].to_vec(),
1275                desc,
1276                parent: Some(parent),
1277                parent_idx: None,
1278                trait_parent,
1279                trait_parent_idx: None,
1280                exact_module_path: None,
1281                impl_id,
1282                search_type: get_function_type_for_search(
1283                    item,
1284                    tcx,
1285                    impl_generics.as_ref(),
1286                    Some(parent),
1287                    cache,
1288                ),
1289                aliases: item.attrs.get_doc_aliases(),
1290                is_deprecated: item.is_deprecated(tcx),
1291                is_unstable: item.is_unstable(),
1292            });
1293        }
1294    }
1295
1296    // Sort search index items. This improves the compressibility of the search index.
1297    search_index.sort_unstable_by(|k1, k2| {
1298        // `sort_unstable_by_key` produces lifetime errors
1299        // HACK(rustdoc): should not be sorting `CrateNum` or `DefIndex`, this will soon go away, too
1300        let k1 =
1301            (&k1.module_path, k1.name.as_str(), &k1.ty, k1.parent.map(|id| (id.index, id.krate)));
1302        let k2 =
1303            (&k2.module_path, k2.name.as_str(), &k2.ty, k2.parent.map(|id| (id.index, id.krate)));
1304        Ord::cmp(&k1, &k2)
1305    });
1306
1307    // Now, convert to an on-disk search index format
1308    //
1309    // if there's already a search index, load it into memory and add the new entries to it
1310    // otherwise, do nothing
1311    let mut serialized_index = if should_merge.read_rendered_cci {
1312        SerializedSearchIndex::load(doc_root, resource_suffix)?
1313    } else {
1314        SerializedSearchIndex::default()
1315    };
1316
1317    // The crate always goes first in this list
1318    let crate_name = krate.name(tcx);
1319    let crate_doc =
1320        short_markdown_summary(&krate.module.doc_value(), &krate.module.link_names(cache));
1321    let crate_idx = {
1322        let crate_path = (ItemType::ExternCrate, vec![crate_name]);
1323        match serialized_index.crate_paths_index.entry(crate_path) {
1324            Entry::Occupied(index) => {
1325                let index = *index.get();
1326                serialized_index.descs[index] = crate_doc;
1327                for type_data in serialized_index.type_data.iter_mut() {
1328                    if let Some(TypeData {
1329                        inverted_function_inputs_index,
1330                        inverted_function_output_index,
1331                        ..
1332                    }) = type_data
1333                    {
1334                        for list in inverted_function_inputs_index
1335                            .iter_mut()
1336                            .chain(inverted_function_output_index.iter_mut())
1337                        {
1338                            list.retain(|fnid| {
1339                                serialized_index.entry_data[usize::try_from(*fnid).unwrap()]
1340                                    .as_ref()
1341                                    .unwrap()
1342                                    .krate
1343                                    != index
1344                            });
1345                        }
1346                    }
1347                }
1348                for i in (index + 1)..serialized_index.entry_data.len() {
1349                    // if this crate has been built before, replace its stuff with new
1350                    if let Some(EntryData { krate, .. }) = serialized_index.entry_data[i]
1351                        && krate == index
1352                    {
1353                        serialized_index.entry_data[i] = None;
1354                        serialized_index.descs[i] = String::new();
1355                        serialized_index.function_data[i] = None;
1356                        if serialized_index.path_data[i].is_none() {
1357                            serialized_index.names[i] = String::new();
1358                        }
1359                    }
1360                    if let Some(alias_pointer) = serialized_index.alias_pointers[i]
1361                        && serialized_index.entry_data[alias_pointer].is_none()
1362                    {
1363                        serialized_index.alias_pointers[i] = None;
1364                        if serialized_index.path_data[i].is_none()
1365                            && serialized_index.entry_data[i].is_none()
1366                        {
1367                            serialized_index.names[i] = String::new();
1368                        }
1369                    }
1370                }
1371                index
1372            }
1373            Entry::Vacant(slot) => {
1374                let krate = serialized_index.names.len();
1375                slot.insert(krate);
1376                serialized_index.push(
1377                    crate_name.as_str().to_string(),
1378                    Some(PathData {
1379                        ty: ItemType::ExternCrate,
1380                        module_path: vec![],
1381                        exact_module_path: None,
1382                    }),
1383                    Some(EntryData {
1384                        krate,
1385                        ty: ItemType::ExternCrate,
1386                        module_path: None,
1387                        exact_module_path: None,
1388                        parent: None,
1389                        trait_parent: None,
1390                        deprecated: false,
1391                        unstable: false,
1392                        associated_item_disambiguator: None,
1393                    }),
1394                    crate_doc,
1395                    None,
1396                    None,
1397                    None,
1398                );
1399                krate
1400            }
1401        }
1402    };
1403
1404    // First, populate associated item parents and trait parents
1405    let crate_items: Vec<&mut IndexItem> = search_index
1406        .iter_mut()
1407        .map(|item| {
1408            let mut defid_to_rowid = |defid, check_external: bool| {
1409                cache
1410                    .paths
1411                    .get(&defid)
1412                    .or_else(|| check_external.then(|| cache.external_paths.get(&defid)).flatten())
1413                    .map(|&(ref fqp, ty)| {
1414                        let pathid = serialized_index.names.len();
1415                        match serialized_index.crate_paths_index.entry((ty, fqp.clone())) {
1416                            Entry::Occupied(entry) => *entry.get(),
1417                            Entry::Vacant(entry) => {
1418                                entry.insert(pathid);
1419                                let (name, path) = fqp.split_last().unwrap();
1420                                serialized_index.push_path(
1421                                    name.as_str().to_string(),
1422                                    PathData {
1423                                        ty,
1424                                        module_path: path.to_vec(),
1425                                        exact_module_path: if let Some(exact_path) =
1426                                            cache.exact_paths.get(&defid)
1427                                            && let Some((name2, exact_path)) =
1428                                                exact_path.split_last()
1429                                            && name == name2
1430                                        {
1431                                            Some(exact_path.to_vec())
1432                                        } else {
1433                                            None
1434                                        },
1435                                    },
1436                                );
1437                                usize::try_from(pathid).unwrap()
1438                            }
1439                        }
1440                    })
1441            };
1442            item.parent_idx = item.parent.and_then(|p| defid_to_rowid(p, false));
1443            item.trait_parent_idx = item.trait_parent.and_then(|p| defid_to_rowid(p, true));
1444
1445            if let Some(defid) = item.defid
1446                && item.parent_idx.is_none()
1447            {
1448                // If this is a re-export, retain the original path.
1449                // Associated items don't use this.
1450                // Their parent carries the exact fqp instead.
1451                let exact_fqp = cache
1452                    .exact_paths
1453                    .get(&defid)
1454                    .or_else(|| cache.external_paths.get(&defid).map(|(fqp, _)| fqp));
1455                item.exact_module_path = exact_fqp.and_then(|fqp| {
1456                    // Re-exports only count if the name is exactly the same.
1457                    // This is a size optimization, since it means we only need
1458                    // to store the name once (and the path is re-used for everything
1459                    // exported from this same module). It's also likely to Do
1460                    // What I Mean, since if a re-export changes the name, it might
1461                    // also be a change in semantic meaning.
1462                    if fqp.last() != Some(&item.name) {
1463                        return None;
1464                    }
1465                    let path = if item.ty == ItemType::Macro
1466                        && find_attr!(tcx, defid, MacroExport { .. })
1467                    {
1468                        // `#[macro_export]` always exports to the crate root.
1469                        vec![tcx.crate_name(defid.krate)]
1470                    } else {
1471                        if fqp.len() < 2 {
1472                            return None;
1473                        }
1474                        fqp[..fqp.len() - 1].to_vec()
1475                    };
1476                    if path == item.module_path {
1477                        return None;
1478                    }
1479                    Some(path)
1480                });
1481            } else if let Some(parent_idx) = item.parent_idx {
1482                let i = usize::try_from(parent_idx).unwrap();
1483                item.module_path =
1484                    serialized_index.path_data[i].as_ref().unwrap().module_path.clone();
1485                item.exact_module_path =
1486                    serialized_index.path_data[i].as_ref().unwrap().exact_module_path.clone();
1487            }
1488
1489            &mut *item
1490        })
1491        .collect();
1492
1493    // Now, find anywhere that the same name is used for two different items
1494    // these need a disambiguator hash for lints
1495    let mut associated_item_duplicates = FxHashMap::<(usize, ItemType, Symbol), usize>::default();
1496    for item in crate_items.iter().map(|x| &*x) {
1497        if item.impl_id.is_some()
1498            && let Some(parent_idx) = item.parent_idx
1499        {
1500            let count =
1501                associated_item_duplicates.entry((parent_idx, item.ty, item.name)).or_insert(0);
1502            *count += 1;
1503        }
1504    }
1505
1506    // now populate the actual entries, type data, and function data
1507    for item in crate_items {
1508        assert_eq!(
1509            item.parent.is_some(),
1510            item.parent_idx.is_some(),
1511            "`{}` is missing idx",
1512            item.name
1513        );
1514
1515        let module_path = Some(serialized_index.get_id_by_module_path(&item.module_path));
1516        let exact_module_path = item
1517            .exact_module_path
1518            .as_ref()
1519            .map(|path| serialized_index.get_id_by_module_path(path));
1520
1521        let new_entry_id = serialized_index.add_entry(
1522            item.name,
1523            EntryData {
1524                ty: item.ty,
1525                parent: item.parent_idx,
1526                trait_parent: item.trait_parent_idx,
1527                module_path,
1528                exact_module_path,
1529                deprecated: item.is_deprecated,
1530                unstable: item.is_unstable,
1531                associated_item_disambiguator: if let Some(impl_id) = item.impl_id
1532                    && let Some(parent_idx) = item.parent_idx
1533                    && associated_item_duplicates
1534                        .get(&(parent_idx, item.ty, item.name))
1535                        .copied()
1536                        .unwrap_or(0)
1537                        > 1
1538                {
1539                    Some(render::get_id_for_impl(tcx, ItemId::DefId(impl_id)))
1540                } else {
1541                    None
1542                },
1543                krate: crate_idx,
1544            },
1545            item.desc.to_string(),
1546        );
1547
1548        // Aliases
1549        // -------
1550        for alias in &item.aliases[..] {
1551            serialized_index.push_alias(alias.as_str().to_string(), new_entry_id);
1552        }
1553
1554        // Function signature reverse index
1555        // --------------------------------
1556        fn insert_into_map(
1557            ty: ItemType,
1558            path: &[Symbol],
1559            exact_path: Option<&[Symbol]>,
1560            search_unbox: bool,
1561            serialized_index: &mut SerializedSearchIndex,
1562            used_in_function_signature: &mut BTreeSet<isize>,
1563        ) -> RenderTypeId {
1564            let pathid = serialized_index.names.len();
1565            let pathid = match serialized_index.crate_paths_index.entry((ty, path.to_vec())) {
1566                Entry::Occupied(entry) => {
1567                    let id = *entry.get();
1568                    if serialized_index.type_data[id].as_mut().is_none() {
1569                        serialized_index.type_data[id] = Some(TypeData {
1570                            search_unbox,
1571                            inverted_function_inputs_index: Vec::new(),
1572                            inverted_function_output_index: Vec::new(),
1573                        });
1574                    } else if search_unbox {
1575                        serialized_index.type_data[id].as_mut().unwrap().search_unbox = true;
1576                    }
1577                    id
1578                }
1579                Entry::Vacant(entry) => {
1580                    entry.insert(pathid);
1581                    let (name, path) = path.split_last().unwrap();
1582                    serialized_index.push_type(
1583                        name.to_string(),
1584                        PathData {
1585                            ty,
1586                            module_path: path.to_vec(),
1587                            exact_module_path: if let Some(exact_path) = exact_path
1588                                && let Some((name2, exact_path)) = exact_path.split_last()
1589                                && name == name2
1590                            {
1591                                Some(exact_path.to_vec())
1592                            } else {
1593                                None
1594                            },
1595                        },
1596                        TypeData {
1597                            inverted_function_inputs_index: Vec::new(),
1598                            inverted_function_output_index: Vec::new(),
1599                            search_unbox,
1600                        },
1601                    );
1602                    pathid
1603                }
1604            };
1605            used_in_function_signature.insert(isize::try_from(pathid).unwrap());
1606            RenderTypeId::Index(isize::try_from(pathid).unwrap())
1607        }
1608
1609        fn convert_render_type_id(
1610            id: RenderTypeId,
1611            cache: &mut Cache,
1612            serialized_index: &mut SerializedSearchIndex,
1613            used_in_function_signature: &mut BTreeSet<isize>,
1614            tcx: TyCtxt<'_>,
1615        ) -> Option<RenderTypeId> {
1616            use crate::clean::PrimitiveType;
1617            let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache;
1618            let search_unbox = match id {
1619                RenderTypeId::Mut => false,
1620                RenderTypeId::DefId(defid) => {
1621                    utils::has_doc_flag(tcx, defid, |d| d.search_unbox.is_some())
1622                }
1623                RenderTypeId::Primitive(
1624                    PrimitiveType::Reference | PrimitiveType::RawPointer | PrimitiveType::Tuple,
1625                ) => true,
1626                RenderTypeId::Primitive(..) => false,
1627                RenderTypeId::AssociatedType(..) => false,
1628                // this bool is only used by `insert_into_map`, so it doesn't matter what we set here
1629                // because Index means we've already inserted into the map
1630                RenderTypeId::Index(_) => false,
1631            };
1632            match id {
1633                RenderTypeId::Mut => Some(insert_into_map(
1634                    ItemType::Keyword,
1635                    &[kw::Mut],
1636                    None,
1637                    search_unbox,
1638                    serialized_index,
1639                    used_in_function_signature,
1640                )),
1641                RenderTypeId::DefId(defid) => {
1642                    if let Some(&(ref fqp, item_type)) =
1643                        paths.get(&defid).or_else(|| external_paths.get(&defid))
1644                    {
1645                        if tcx.lang_items().fn_mut_trait() == Some(defid)
1646                            || tcx.lang_items().fn_once_trait() == Some(defid)
1647                            || tcx.lang_items().fn_trait() == Some(defid)
1648                        {
1649                            let name = *fqp.last().unwrap();
1650                            // Make absolutely sure we use this single, correct path,
1651                            // because search.js needs to match. If we don't do this,
1652                            // there are three different paths that these traits may
1653                            // appear to come from.
1654                            Some(insert_into_map(
1655                                item_type,
1656                                &[sym::core, sym::ops, name],
1657                                Some(&[sym::core, sym::ops, name]),
1658                                search_unbox,
1659                                serialized_index,
1660                                used_in_function_signature,
1661                            ))
1662                        } else {
1663                            let exact_fqp = exact_paths
1664                                .get(&defid)
1665                                .or_else(|| external_paths.get(&defid).map(|(fqp, _)| fqp))
1666                                .map(|v| &v[..])
1667                                // Re-exports only count if the name is exactly the same.
1668                                // This is a size optimization, since it means we only need
1669                                // to store the name once (and the path is re-used for everything
1670                                // exported from this same module). It's also likely to Do
1671                                // What I Mean, since if a re-export changes the name, it might
1672                                // also be a change in semantic meaning.
1673                                .filter(|this_fqp| this_fqp.last() == fqp.last());
1674                            Some(insert_into_map(
1675                                item_type,
1676                                fqp,
1677                                exact_fqp,
1678                                search_unbox,
1679                                serialized_index,
1680                                used_in_function_signature,
1681                            ))
1682                        }
1683                    } else {
1684                        None
1685                    }
1686                }
1687                RenderTypeId::Primitive(primitive) => {
1688                    let sym = primitive.as_sym();
1689                    Some(insert_into_map(
1690                        ItemType::Primitive,
1691                        &[sym],
1692                        None,
1693                        search_unbox,
1694                        serialized_index,
1695                        used_in_function_signature,
1696                    ))
1697                }
1698                RenderTypeId::Index(index) => {
1699                    used_in_function_signature.insert(index);
1700                    Some(id)
1701                }
1702                RenderTypeId::AssociatedType(sym) => Some(insert_into_map(
1703                    ItemType::AssocType,
1704                    &[sym],
1705                    None,
1706                    search_unbox,
1707                    serialized_index,
1708                    used_in_function_signature,
1709                )),
1710            }
1711        }
1712
1713        fn convert_render_type(
1714            ty: &mut RenderType,
1715            cache: &mut Cache,
1716            serialized_index: &mut SerializedSearchIndex,
1717            used_in_function_signature: &mut BTreeSet<isize>,
1718            tcx: TyCtxt<'_>,
1719        ) {
1720            if let Some(generics) = &mut ty.generics {
1721                for item in generics {
1722                    convert_render_type(
1723                        item,
1724                        cache,
1725                        serialized_index,
1726                        used_in_function_signature,
1727                        tcx,
1728                    );
1729                }
1730            }
1731            if let Some(bindings) = &mut ty.bindings {
1732                bindings.retain_mut(|(associated_type, constraints)| {
1733                    let converted_associated_type = convert_render_type_id(
1734                        *associated_type,
1735                        cache,
1736                        serialized_index,
1737                        used_in_function_signature,
1738                        tcx,
1739                    );
1740                    let Some(converted_associated_type) = converted_associated_type else {
1741                        return false;
1742                    };
1743                    *associated_type = converted_associated_type;
1744                    for constraint in constraints {
1745                        convert_render_type(
1746                            constraint,
1747                            cache,
1748                            serialized_index,
1749                            used_in_function_signature,
1750                            tcx,
1751                        );
1752                    }
1753                    true
1754                });
1755            }
1756            let Some(id) = ty.id else {
1757                assert!(ty.generics.is_some());
1758                return;
1759            };
1760            ty.id = convert_render_type_id(
1761                id,
1762                cache,
1763                serialized_index,
1764                used_in_function_signature,
1765                tcx,
1766            );
1767            use crate::clean::PrimitiveType;
1768            // These cases are added to the inverted index, but not actually included
1769            // in the signature. There's a matching set of cases in the
1770            // `unifyFunctionTypeIsMatchCandidate` function, for the slow path.
1771            match id {
1772                // typeNameIdOfArrayOrSlice
1773                RenderTypeId::Primitive(PrimitiveType::Array | PrimitiveType::Slice) => {
1774                    insert_into_map(
1775                        ItemType::Primitive,
1776                        &[Symbol::intern("[]")],
1777                        None,
1778                        false,
1779                        serialized_index,
1780                        used_in_function_signature,
1781                    );
1782                }
1783                RenderTypeId::Primitive(PrimitiveType::Tuple | PrimitiveType::Unit) => {
1784                    // typeNameIdOfArrayOrSlice
1785                    insert_into_map(
1786                        ItemType::Primitive,
1787                        &[Symbol::intern("()")],
1788                        None,
1789                        false,
1790                        serialized_index,
1791                        used_in_function_signature,
1792                    );
1793                }
1794                // typeNameIdOfHof
1795                RenderTypeId::Primitive(PrimitiveType::Fn) => {
1796                    insert_into_map(
1797                        ItemType::Primitive,
1798                        &[Symbol::intern("->")],
1799                        None,
1800                        false,
1801                        serialized_index,
1802                        used_in_function_signature,
1803                    );
1804                }
1805                RenderTypeId::DefId(did)
1806                    if tcx.lang_items().fn_mut_trait() == Some(did)
1807                        || tcx.lang_items().fn_once_trait() == Some(did)
1808                        || tcx.lang_items().fn_trait() == Some(did) =>
1809                {
1810                    insert_into_map(
1811                        ItemType::Primitive,
1812                        &[Symbol::intern("->")],
1813                        None,
1814                        false,
1815                        serialized_index,
1816                        used_in_function_signature,
1817                    );
1818                }
1819                // not special
1820                _ => {}
1821            }
1822        }
1823        if let Some(search_type) = &mut item.search_type {
1824            let mut used_in_function_inputs = BTreeSet::new();
1825            let mut used_in_function_output = BTreeSet::new();
1826            for item in &mut search_type.inputs {
1827                convert_render_type(
1828                    item,
1829                    cache,
1830                    &mut serialized_index,
1831                    &mut used_in_function_inputs,
1832                    tcx,
1833                );
1834            }
1835            for item in &mut search_type.output {
1836                convert_render_type(
1837                    item,
1838                    cache,
1839                    &mut serialized_index,
1840                    &mut used_in_function_output,
1841                    tcx,
1842                );
1843            }
1844            let used_in_constraints = search_type
1845                .where_clause
1846                .iter_mut()
1847                .map(|constraint| {
1848                    let mut used_in_constraint = BTreeSet::new();
1849                    for trait_ in constraint {
1850                        convert_render_type(
1851                            trait_,
1852                            cache,
1853                            &mut serialized_index,
1854                            &mut used_in_constraint,
1855                            tcx,
1856                        );
1857                    }
1858                    used_in_constraint
1859                })
1860                .collect::<Vec<_>>();
1861            loop {
1862                let mut inserted_any = false;
1863                for (i, used_in_constraint) in used_in_constraints.iter().enumerate() {
1864                    let id = !(i as isize);
1865                    if used_in_function_inputs.contains(&id)
1866                        && !used_in_function_inputs.is_superset(&used_in_constraint)
1867                    {
1868                        used_in_function_inputs.extend(used_in_constraint.iter().copied());
1869                        inserted_any = true;
1870                    }
1871                    if used_in_function_output.contains(&id)
1872                        && !used_in_function_output.is_superset(&used_in_constraint)
1873                    {
1874                        used_in_function_output.extend(used_in_constraint.iter().copied());
1875                        inserted_any = true;
1876                    }
1877                }
1878                if !inserted_any {
1879                    break;
1880                }
1881            }
1882            let search_type_size = search_type.size() +
1883                // Artificially give struct fields a size of 8 instead of their real
1884                // size of 2. This is because search.js sorts them to the end, so
1885                // by pushing them down, we prevent them from blocking real 2-arity functions.
1886                //
1887                // The number 8 is arbitrary. We want it big, but not enormous,
1888                // because the postings list has to fill in an empty array for each
1889                // unoccupied size.
1890                if item.ty.is_fn_like() { 0 } else { 16 };
1891            serialized_index.function_data[new_entry_id] = Some(search_type.clone());
1892
1893            #[derive(Clone, Copy)]
1894            enum InvertedIndexType {
1895                Inputs,
1896                Output,
1897            }
1898            impl InvertedIndexType {
1899                fn from_type_data(self, type_data: &mut TypeData) -> &mut Vec<Vec<u32>> {
1900                    match self {
1901                        Self::Inputs => &mut type_data.inverted_function_inputs_index,
1902                        Self::Output => &mut type_data.inverted_function_output_index,
1903                    }
1904                }
1905            }
1906
1907            let mut process_used_in_function =
1908                |used_in_function: BTreeSet<isize>, index_type: InvertedIndexType| {
1909                    for index in used_in_function {
1910                        let postings = if index >= 0 {
1911                            assert!(serialized_index.path_data[index as usize].is_some());
1912                            index_type.from_type_data(
1913                                serialized_index.type_data[index as usize].as_mut().unwrap(),
1914                            )
1915                        } else {
1916                            let generic_id = index.unsigned_abs() - 1;
1917                            if generic_id >= serialized_index.generic_inverted_index.len() {
1918                                serialized_index
1919                                    .generic_inverted_index
1920                                    .resize(generic_id + 1, Vec::new());
1921                            }
1922                            &mut serialized_index.generic_inverted_index[generic_id]
1923                        };
1924                        if search_type_size >= postings.len() {
1925                            postings.resize(search_type_size + 1, Vec::new());
1926                        }
1927                        let posting = &mut postings[search_type_size];
1928                        if posting.last() != Some(&(new_entry_id as u32)) {
1929                            posting.push(new_entry_id as u32);
1930                        }
1931                    }
1932                };
1933
1934            process_used_in_function(used_in_function_inputs, InvertedIndexType::Inputs);
1935            process_used_in_function(used_in_function_output, InvertedIndexType::Output);
1936        }
1937    }
1938
1939    Ok(serialized_index.sort())
1940}
1941
1942pub(crate) fn get_function_type_for_search(
1943    item: &clean::Item,
1944    tcx: TyCtxt<'_>,
1945    impl_generics: Option<&(clean::Type, clean::Generics)>,
1946    parent: Option<DefId>,
1947    cache: &Cache,
1948) -> Option<IndexItemFunctionType> {
1949    let mut trait_info = None;
1950    let impl_or_trait_generics = impl_generics.or_else(|| {
1951        if let Some(def_id) = parent
1952            && let Some(trait_) = cache.traits.get(&def_id)
1953            && let Some((path, _)) =
1954                cache.paths.get(&def_id).or_else(|| cache.external_paths.get(&def_id))
1955        {
1956            let path = clean::Path {
1957                res: rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Trait, def_id),
1958                segments: path
1959                    .iter()
1960                    .map(|name| clean::PathSegment {
1961                        name: *name,
1962                        args: clean::GenericArgs::AngleBracketed {
1963                            args: ThinVec::new(),
1964                            constraints: ThinVec::new(),
1965                        },
1966                    })
1967                    .collect(),
1968            };
1969            trait_info = Some((clean::Type::Path { path }, trait_.generics.clone()));
1970            Some(trait_info.as_ref().unwrap())
1971        } else {
1972            None
1973        }
1974    });
1975    let (mut inputs, mut output, param_names, where_clause) = match item.kind {
1976        clean::ForeignFunctionItem(ref f, _)
1977        | clean::FunctionItem(ref f)
1978        | clean::MethodItem(ref f, _)
1979        | clean::RequiredMethodItem(ref f, _) => {
1980            get_fn_inputs_and_outputs(f, tcx, impl_or_trait_generics, cache)
1981        }
1982        clean::ConstantItem(ref c) => make_nullary_fn(&c.type_),
1983        clean::StaticItem(ref s) => make_nullary_fn(&s.type_),
1984        clean::StructFieldItem(ref t) if let Some(parent) = parent => {
1985            let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> =
1986                Default::default();
1987            let output = get_index_type(t, vec![], &mut rgen);
1988            let input = RenderType {
1989                id: Some(RenderTypeId::DefId(parent)),
1990                generics: None,
1991                bindings: None,
1992            };
1993            (vec![input], vec![output], vec![], vec![])
1994        }
1995        _ => return None,
1996    };
1997
1998    inputs.retain(|a| a.id.is_some() || a.generics.is_some());
1999    output.retain(|a| a.id.is_some() || a.generics.is_some());
2000
2001    Some(IndexItemFunctionType { inputs, output, where_clause, param_names })
2002}
2003
2004fn get_index_type(
2005    clean_type: &clean::Type,
2006    generics: Vec<RenderType>,
2007    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2008) -> RenderType {
2009    RenderType {
2010        id: get_index_type_id(clean_type, rgen),
2011        generics: if generics.is_empty() { None } else { Some(generics) },
2012        bindings: None,
2013    }
2014}
2015
2016fn get_index_type_id(
2017    clean_type: &clean::Type,
2018    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2019) -> Option<RenderTypeId> {
2020    use rustc_hir::def::{DefKind, Res};
2021    match *clean_type {
2022        clean::Type::Path { ref path, .. } => Some(RenderTypeId::DefId(path.def_id())),
2023        clean::DynTrait(ref bounds, _) => {
2024            bounds.first().map(|b| RenderTypeId::DefId(b.trait_.def_id()))
2025        }
2026        clean::Primitive(p) => Some(RenderTypeId::Primitive(p)),
2027        clean::BorrowedRef { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::Reference)),
2028        clean::RawPointer { .. } => Some(RenderTypeId::Primitive(clean::PrimitiveType::RawPointer)),
2029        // The type parameters are converted to generics in `simplify_fn_type`
2030        clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
2031        clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
2032        clean::BareFunction(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Fn)),
2033        clean::Tuple(ref n) if n.is_empty() => {
2034            Some(RenderTypeId::Primitive(clean::PrimitiveType::Unit))
2035        }
2036        clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
2037        clean::QPath(ref data) => {
2038            if data.self_type.is_self_type()
2039                && let Some(clean::Path { res: Res::Def(DefKind::Trait, trait_), .. }) = data.trait_
2040            {
2041                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2042                let (idx, _) = rgen
2043                    .entry(SimplifiedParam::AssociatedType(trait_, data.assoc.name))
2044                    .or_insert_with(|| (idx, Vec::new()));
2045                Some(RenderTypeId::Index(*idx))
2046            } else {
2047                None
2048            }
2049        }
2050        // Not supported yet
2051        clean::Type::Pat(..)
2052        | clean::Generic(_)
2053        | clean::SelfTy
2054        | clean::ImplTrait(_)
2055        | clean::Infer
2056        | clean::UnsafeBinder(_) => None,
2057    }
2058}
2059
2060#[derive(Clone, Copy, Eq, Hash, PartialEq)]
2061enum SimplifiedParam {
2062    // other kinds of type parameters are identified by their name
2063    Symbol(Symbol),
2064    // every argument-position impl trait is its own type parameter
2065    Anonymous(isize),
2066    // in a trait definition, the associated types are all bound to
2067    // their own type parameter
2068    AssociatedType(DefId, Symbol),
2069}
2070
2071/// The point of this function is to lower generics and types into the simplified form that the
2072/// frontend search engine can use.
2073///
2074/// For example, `[T, U, i32]]` where you have the bounds: `T: Display, U: Option<T>` will return
2075/// `[-1, -2, i32] where -1: Display, -2: Option<-1>`. If a type parameter has no trait bound, it
2076/// will still get a number. If a constraint is present but not used in the actual types, it will
2077/// not be added to the map.
2078///
2079/// This function also works recursively.
2080#[instrument(level = "trace", skip(tcx, rgen, cache))]
2081fn simplify_fn_type<'a, 'tcx>(
2082    self_: Option<&'a Type>,
2083    generics: &Generics,
2084    arg: &'a Type,
2085    tcx: TyCtxt<'tcx>,
2086    recurse: usize,
2087    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2088    is_return: bool,
2089    cache: &Cache,
2090) -> Option<RenderType> {
2091    if recurse >= 10 {
2092        // FIXME: remove this whole recurse thing when the recursion bug is fixed
2093        // See #59502 for the original issue.
2094        return None;
2095    }
2096
2097    // First, check if it's "Self".
2098    let (is_self, arg) = if let Some(self_) = self_
2099        && arg.is_self_type()
2100    {
2101        (true, self_)
2102    } else {
2103        (false, arg)
2104    };
2105
2106    // If this argument is a type parameter and not a trait bound or a type, we need to look
2107    // for its bounds.
2108    match *arg {
2109        Type::Generic(arg_s) => {
2110            // First we check if the bounds are in a `where` predicate...
2111            let where_bounds = generics
2112                .where_predicates
2113                .iter()
2114                .filter_map(|g| {
2115                    if let WherePredicate::BoundPredicate { ty, bounds, .. } = g
2116                        && *ty == *arg
2117                    {
2118                        Some(bounds)
2119                    } else {
2120                        None
2121                    }
2122                })
2123                .flatten();
2124            // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
2125            let inline_bounds = generics
2126                .params
2127                .iter()
2128                .find(|g| g.is_type() && g.name == arg_s)
2129                .and_then(|bound| bound.get_bounds())
2130                .into_iter()
2131                .flatten();
2132
2133            let type_bounds = where_bounds
2134                .chain(inline_bounds)
2135                .filter_map(
2136                    |bound| if let Some(path) = bound.get_trait_path() { Some(path) } else { None },
2137                )
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();
2143
2144            Some(if let Some((idx, _)) = rgen.get(&SimplifiedParam::Symbol(arg_s)) {
2145                RenderType { id: Some(RenderTypeId::Index(*idx)), generics: None, bindings: None }
2146            } else {
2147                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2148                rgen.insert(SimplifiedParam::Symbol(arg_s), (idx, type_bounds));
2149                RenderType { id: Some(RenderTypeId::Index(idx)), generics: None, bindings: None }
2150            })
2151        }
2152        Type::ImplTrait(ref bounds) => {
2153            let type_bounds = bounds
2154                .iter()
2155                .filter_map(|bound| bound.get_trait_path())
2156                .filter_map(|path| {
2157                    let ty = Type::Path { path };
2158                    simplify_fn_type(self_, generics, &ty, tcx, recurse + 1, rgen, is_return, cache)
2159                })
2160                .collect::<Vec<_>>();
2161            Some(if is_return && !type_bounds.is_empty() {
2162                // In return position, `impl Trait` is a unique thing.
2163                RenderType { id: None, generics: Some(type_bounds), bindings: None }
2164            } else {
2165                // In parameter position, `impl Trait` is the same as an unnamed generic parameter.
2166                let idx = -isize::try_from(rgen.len() + 1).unwrap();
2167                rgen.insert(SimplifiedParam::Anonymous(idx), (idx, type_bounds));
2168                RenderType { id: Some(RenderTypeId::Index(idx)), generics: None, bindings: None }
2169            })
2170        }
2171        Type::Slice(ref ty) => {
2172            let ty_generics =
2173                simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2174                    .into_iter()
2175                    .collect();
2176            Some(get_index_type(arg, ty_generics, rgen))
2177        }
2178        Type::Array(ref ty, _) => {
2179            let ty_generics =
2180                simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2181                    .into_iter()
2182                    .collect();
2183            Some(get_index_type(arg, ty_generics, rgen))
2184        }
2185        Type::Tuple(ref tys) => {
2186            let ty_generics = tys
2187                .iter()
2188                .filter_map(|ty| {
2189                    simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2190                })
2191                .collect();
2192            Some(get_index_type(arg, ty_generics, rgen))
2193        }
2194        Type::BareFunction(ref bf) => {
2195            let ty_generics = bf
2196                .decl
2197                .inputs
2198                .iter()
2199                .map(|arg| &arg.type_)
2200                .filter_map(|ty| {
2201                    simplify_fn_type(self_, generics, ty, tcx, recurse + 1, rgen, is_return, cache)
2202                })
2203                .collect();
2204            // The search index, for simplicity's sake, represents fn pointers and closures
2205            // the same way: as a tuple for the parameters, and an associated type for the
2206            // return type.
2207            let ty_output = simplify_fn_type(
2208                self_,
2209                generics,
2210                &bf.decl.output,
2211                tcx,
2212                recurse + 1,
2213                rgen,
2214                is_return,
2215                cache,
2216            )
2217            .into_iter()
2218            .collect();
2219            let ty_bindings = vec![(RenderTypeId::AssociatedType(sym::Output), ty_output)];
2220            Some(RenderType {
2221                id: get_index_type_id(arg, rgen),
2222                bindings: Some(ty_bindings),
2223                generics: Some(ty_generics),
2224            })
2225        }
2226        Type::BorrowedRef { lifetime: _, mutability, ref type_ }
2227        | Type::RawPointer(mutability, ref type_) => {
2228            let mut ty_generics = Vec::new();
2229            if mutability.is_mut() {
2230                ty_generics.push(RenderType {
2231                    id: Some(RenderTypeId::Mut),
2232                    generics: None,
2233                    bindings: None,
2234                });
2235            }
2236            if let Some(ty) =
2237                simplify_fn_type(self_, generics, type_, tcx, recurse + 1, rgen, is_return, cache)
2238            {
2239                ty_generics.push(ty);
2240            }
2241            Some(get_index_type(arg, ty_generics, rgen))
2242        }
2243        _ => {
2244            // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
2245            // looking at `Option`, we enter this "else" condition, otherwise if it's `T`, we don't.
2246            //
2247            // So in here, we can add it directly and look for its own type parameters (so for `Option`,
2248            // we will look for them but not for `T`).
2249            let mut ty_generics = Vec::new();
2250            let mut ty_constraints = Vec::new();
2251            if let Some(arg_generics) = arg.generic_args() {
2252                ty_generics = arg_generics
2253                    .into_iter()
2254                    .filter_map(|param| match param {
2255                        clean::GenericArg::Type(ty) => Some(ty),
2256                        _ => None,
2257                    })
2258                    .filter_map(|ty| {
2259                        simplify_fn_type(
2260                            self_,
2261                            generics,
2262                            &ty,
2263                            tcx,
2264                            recurse + 1,
2265                            rgen,
2266                            is_return,
2267                            cache,
2268                        )
2269                    })
2270                    .collect();
2271                for constraint in arg_generics.constraints() {
2272                    simplify_fn_constraint(
2273                        self_,
2274                        generics,
2275                        &constraint,
2276                        tcx,
2277                        recurse + 1,
2278                        &mut ty_constraints,
2279                        rgen,
2280                        is_return,
2281                        cache,
2282                    );
2283                }
2284            }
2285            // Every trait associated type on self gets assigned to a type parameter index
2286            // this same one is used later for any appearances of these types
2287            //
2288            // for example, Iterator::next is:
2289            //
2290            //     trait Iterator {
2291            //         fn next(&mut self) -> Option<Self::Item>
2292            //     }
2293            //
2294            // Self is technically just Iterator, but we want to pretend it's more like this:
2295            //
2296            //     fn next<T>(self: Iterator<Item=T>) -> Option<T>
2297            if is_self
2298                && let Type::Path { path } = arg
2299                && let def_id = path.def_id()
2300                && let Some(trait_) = cache.traits.get(&def_id)
2301                && trait_.items.iter().any(|at| at.is_required_associated_type())
2302            {
2303                for assoc_ty in &trait_.items {
2304                    if let clean::ItemKind::RequiredAssocTypeItem(_generics, bounds) =
2305                        &assoc_ty.kind
2306                        && let Some(name) = assoc_ty.name
2307                    {
2308                        let idx = -isize::try_from(rgen.len() + 1).unwrap();
2309                        let (idx, stored_bounds) = rgen
2310                            .entry(SimplifiedParam::AssociatedType(def_id, name))
2311                            .or_insert_with(|| (idx, Vec::new()));
2312                        let idx = *idx;
2313                        if stored_bounds.is_empty() {
2314                            // Can't just pass stored_bounds to simplify_fn_type,
2315                            // because it also accepts rgen as a parameter.
2316                            // Instead, have it fill in this local, then copy it into the map afterward.
2317                            let type_bounds = bounds
2318                                .iter()
2319                                .filter_map(|bound| bound.get_trait_path())
2320                                .filter_map(|path| {
2321                                    let ty = Type::Path { path };
2322                                    simplify_fn_type(
2323                                        self_,
2324                                        generics,
2325                                        &ty,
2326                                        tcx,
2327                                        recurse + 1,
2328                                        rgen,
2329                                        is_return,
2330                                        cache,
2331                                    )
2332                                })
2333                                .collect();
2334                            let stored_bounds = &mut rgen
2335                                .get_mut(&SimplifiedParam::AssociatedType(def_id, name))
2336                                .unwrap()
2337                                .1;
2338                            if stored_bounds.is_empty() {
2339                                *stored_bounds = type_bounds;
2340                            }
2341                        }
2342                        ty_constraints.push((
2343                            RenderTypeId::AssociatedType(name),
2344                            vec![RenderType {
2345                                id: Some(RenderTypeId::Index(idx)),
2346                                generics: None,
2347                                bindings: None,
2348                            }],
2349                        ))
2350                    }
2351                }
2352            }
2353            let id = get_index_type_id(arg, rgen);
2354            if id.is_some() || !ty_generics.is_empty() {
2355                Some(RenderType {
2356                    id,
2357                    bindings: if ty_constraints.is_empty() { None } else { Some(ty_constraints) },
2358                    generics: if ty_generics.is_empty() { None } else { Some(ty_generics) },
2359                })
2360            } else {
2361                None
2362            }
2363        }
2364    }
2365}
2366
2367fn simplify_fn_constraint<'a>(
2368    self_: Option<&'a Type>,
2369    generics: &Generics,
2370    constraint: &'a clean::AssocItemConstraint,
2371    tcx: TyCtxt<'_>,
2372    recurse: usize,
2373    res: &mut Vec<(RenderTypeId, Vec<RenderType>)>,
2374    rgen: &mut FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)>,
2375    is_return: bool,
2376    cache: &Cache,
2377) {
2378    let mut ty_constraints = Vec::new();
2379    let ty_constrained_assoc = RenderTypeId::AssociatedType(constraint.assoc.name);
2380    for param in &constraint.assoc.args {
2381        match param {
2382            clean::GenericArg::Type(arg) => {
2383                ty_constraints.extend(simplify_fn_type(
2384                    self_,
2385                    generics,
2386                    &arg,
2387                    tcx,
2388                    recurse + 1,
2389                    rgen,
2390                    is_return,
2391                    cache,
2392                ));
2393            }
2394            clean::GenericArg::Lifetime(_)
2395            | clean::GenericArg::Const(_)
2396            | clean::GenericArg::Infer => {}
2397        }
2398    }
2399    for constraint in constraint.assoc.args.constraints() {
2400        simplify_fn_constraint(
2401            self_,
2402            generics,
2403            &constraint,
2404            tcx,
2405            recurse + 1,
2406            res,
2407            rgen,
2408            is_return,
2409            cache,
2410        );
2411    }
2412    match &constraint.kind {
2413        clean::AssocItemConstraintKind::Equality { term } => {
2414            if let clean::Term::Type(arg) = &term {
2415                ty_constraints.extend(simplify_fn_type(
2416                    self_,
2417                    generics,
2418                    arg,
2419                    tcx,
2420                    recurse + 1,
2421                    rgen,
2422                    is_return,
2423                    cache,
2424                ));
2425            }
2426        }
2427        clean::AssocItemConstraintKind::Bound { bounds } => {
2428            for bound in &bounds[..] {
2429                if let Some(path) = bound.get_trait_path() {
2430                    let ty = Type::Path { path };
2431                    ty_constraints.extend(simplify_fn_type(
2432                        self_,
2433                        generics,
2434                        &ty,
2435                        tcx,
2436                        recurse + 1,
2437                        rgen,
2438                        is_return,
2439                        cache,
2440                    ));
2441                }
2442            }
2443        }
2444    }
2445    res.push((ty_constrained_assoc, ty_constraints));
2446}
2447
2448/// Create a fake nullary function.
2449///
2450/// Used to allow type-based search on constants and statics.
2451fn make_nullary_fn(
2452    clean_type: &clean::Type,
2453) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
2454    let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
2455    let output = get_index_type(clean_type, vec![], &mut rgen);
2456    (vec![], vec![output], vec![], vec![])
2457}
2458
2459/// Return the full list of types when bounds have been resolved.
2460///
2461/// i.e. `fn foo<A: Display, B: Option<A>>(x: u32, y: B)` will return
2462/// `[u32, Display, Option]`.
2463fn get_fn_inputs_and_outputs(
2464    func: &Function,
2465    tcx: TyCtxt<'_>,
2466    impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
2467    cache: &Cache,
2468) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
2469    let decl = &func.decl;
2470
2471    let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
2472
2473    let combined_generics;
2474    let (self_, generics) = if let Some((impl_self, impl_generics)) = impl_or_trait_generics {
2475        match (impl_generics.is_empty(), func.generics.is_empty()) {
2476            (true, _) => (Some(impl_self), &func.generics),
2477            (_, true) => (Some(impl_self), impl_generics),
2478            (false, false) => {
2479                let params =
2480                    func.generics.params.iter().chain(&impl_generics.params).cloned().collect();
2481                let where_predicates = func
2482                    .generics
2483                    .where_predicates
2484                    .iter()
2485                    .chain(&impl_generics.where_predicates)
2486                    .cloned()
2487                    .collect();
2488                combined_generics = clean::Generics { params, where_predicates };
2489                (Some(impl_self), &combined_generics)
2490            }
2491        }
2492    } else {
2493        (None, &func.generics)
2494    };
2495
2496    let param_types = decl
2497        .inputs
2498        .iter()
2499        .filter_map(|param| {
2500            simplify_fn_type(self_, generics, &param.type_, tcx, 0, &mut rgen, false, cache)
2501        })
2502        .collect();
2503
2504    let ret_types = simplify_fn_type(self_, generics, &decl.output, tcx, 0, &mut rgen, true, cache)
2505        .into_iter()
2506        .collect();
2507
2508    let mut simplified_params = rgen.into_iter().collect::<Vec<_>>();
2509    simplified_params.sort_by_key(|(_, (idx, _))| -idx);
2510    (
2511        param_types,
2512        ret_types,
2513        simplified_params
2514            .iter()
2515            .map(|(name, (_idx, _traits))| match name {
2516                SimplifiedParam::Symbol(name) => Some(*name),
2517                SimplifiedParam::Anonymous(_) => None,
2518                SimplifiedParam::AssociatedType(def_id, name) => {
2519                    Some(Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name)))
2520                }
2521            })
2522            .collect(),
2523        simplified_params.into_iter().map(|(_name, (_idx, traits))| traits).collect(),
2524    )
2525}