11use std:: collections:: hash_map:: Entry ;
22use std:: collections:: BTreeMap ;
33
4- use rustc_data_structures:: fx:: FxHashMap ;
4+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexMap } ;
55use rustc_middle:: ty:: TyCtxt ;
66use rustc_span:: symbol:: Symbol ;
7- use serde:: ser:: { Serialize , SerializeStruct , Serializer } ;
7+ use serde:: ser:: { Serialize , SerializeSeq , SerializeStruct , Serializer } ;
88
99use crate :: clean;
1010use crate :: clean:: types:: { Function , Generics , ItemId , Type , WherePredicate } ;
@@ -78,17 +78,17 @@ pub(crate) fn build_index<'tcx>(
7878 map : & mut FxHashMap < F , usize > ,
7979 itemid : F ,
8080 lastpathid : & mut usize ,
81- crate_paths : & mut Vec < ( ItemType , Symbol ) > ,
81+ crate_paths : & mut Vec < ( ItemType , Vec < Symbol > ) > ,
8282 item_type : ItemType ,
83- path : Symbol ,
83+ path : & [ Symbol ] ,
8484 ) {
8585 match map. entry ( itemid) {
8686 Entry :: Occupied ( entry) => ty. id = Some ( RenderTypeId :: Index ( * entry. get ( ) ) ) ,
8787 Entry :: Vacant ( entry) => {
8888 let pathid = * lastpathid;
8989 entry. insert ( pathid) ;
9090 * lastpathid += 1 ;
91- crate_paths. push ( ( item_type, path) ) ;
91+ crate_paths. push ( ( item_type, path. to_vec ( ) ) ) ;
9292 ty. id = Some ( RenderTypeId :: Index ( pathid) ) ;
9393 }
9494 }
@@ -100,7 +100,7 @@ pub(crate) fn build_index<'tcx>(
100100 itemid_to_pathid : & mut FxHashMap < ItemId , usize > ,
101101 primitives : & mut FxHashMap < Symbol , usize > ,
102102 lastpathid : & mut usize ,
103- crate_paths : & mut Vec < ( ItemType , Symbol ) > ,
103+ crate_paths : & mut Vec < ( ItemType , Vec < Symbol > ) > ,
104104 ) {
105105 if let Some ( generics) = & mut ty. generics {
106106 for item in generics {
@@ -131,7 +131,7 @@ pub(crate) fn build_index<'tcx>(
131131 lastpathid,
132132 crate_paths,
133133 item_type,
134- * fqp. last ( ) . unwrap ( ) ,
134+ fqp,
135135 ) ;
136136 } else {
137137 ty. id = None ;
@@ -146,7 +146,7 @@ pub(crate) fn build_index<'tcx>(
146146 lastpathid,
147147 crate_paths,
148148 ItemType :: Primitive ,
149- sym,
149+ & [ sym] ,
150150 ) ;
151151 }
152152 RenderTypeId :: Index ( _) => { }
@@ -191,7 +191,7 @@ pub(crate) fn build_index<'tcx>(
191191 lastpathid += 1 ;
192192
193193 if let Some ( & ( ref fqp, short) ) = paths. get ( & defid) {
194- crate_paths. push ( ( short, * fqp. last ( ) . unwrap ( ) ) ) ;
194+ crate_paths. push ( ( short, fqp. clone ( ) ) ) ;
195195 Some ( pathid)
196196 } else {
197197 None
@@ -213,118 +213,163 @@ pub(crate) fn build_index<'tcx>(
213213 struct CrateData < ' a > {
214214 doc : String ,
215215 items : Vec < & ' a IndexItem > ,
216- paths : Vec < ( ItemType , Symbol ) > ,
216+ paths : Vec < ( ItemType , Vec < Symbol > ) > ,
217217 // The String is alias name and the vec is the list of the elements with this alias.
218218 //
219219 // To be noted: the `usize` elements are indexes to `items`.
220220 aliases : & ' a BTreeMap < String , Vec < usize > > ,
221221 }
222222
223+ struct Paths {
224+ ty : ItemType ,
225+ name : Symbol ,
226+ path : Option < usize > ,
227+ }
228+
229+ impl Serialize for Paths {
230+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
231+ where
232+ S : Serializer ,
233+ {
234+ let mut seq = serializer. serialize_seq ( None ) ?;
235+ seq. serialize_element ( & self . ty ) ?;
236+ seq. serialize_element ( self . name . as_str ( ) ) ?;
237+ if let Some ( ref path) = self . path {
238+ seq. serialize_element ( path) ?;
239+ }
240+ seq. end ( )
241+ }
242+ }
243+
223244 impl < ' a > Serialize for CrateData < ' a > {
224245 fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
225246 where
226247 S : Serializer ,
227248 {
249+ let mut extra_paths = FxHashMap :: default ( ) ;
250+ // We need to keep the order of insertion, hence why we use an `IndexMap`. Then we will
251+ // insert these "extra paths" (which are paths of items from external crates) into the
252+ // `full_paths` list at the end.
253+ let mut revert_extra_paths = FxIndexMap :: default ( ) ;
254+ let mut mod_paths = FxHashMap :: default ( ) ;
255+ for ( index, item) in self . items . iter ( ) . enumerate ( ) {
256+ if item. path . is_empty ( ) {
257+ continue ;
258+ }
259+ mod_paths. insert ( & item. path , index) ;
260+ }
261+ let mut paths = Vec :: with_capacity ( self . paths . len ( ) ) ;
262+ for ( ty, path) in & self . paths {
263+ if path. len ( ) < 2 {
264+ paths. push ( Paths { ty : * ty, name : path[ 0 ] , path : None } ) ;
265+ continue ;
266+ }
267+ let full_path = join_with_double_colon ( & path[ ..path. len ( ) - 1 ] ) ;
268+ if let Some ( index) = mod_paths. get ( & full_path) {
269+ paths. push ( Paths { ty : * ty, name : * path. last ( ) . unwrap ( ) , path : Some ( * index) } ) ;
270+ continue ;
271+ }
272+ // It means it comes from an external crate so the item and its path will be
273+ // stored into another array.
274+ //
275+ // `index` is put after the last `mod_paths`
276+ let index = extra_paths. len ( ) + self . items . len ( ) ;
277+ if !revert_extra_paths. contains_key ( & index) {
278+ revert_extra_paths. insert ( index, full_path. clone ( ) ) ;
279+ }
280+ match extra_paths. entry ( full_path) {
281+ Entry :: Occupied ( entry) => {
282+ paths. push ( Paths {
283+ ty : * ty,
284+ name : * path. last ( ) . unwrap ( ) ,
285+ path : Some ( * entry. get ( ) ) ,
286+ } ) ;
287+ }
288+ Entry :: Vacant ( entry) => {
289+ entry. insert ( index) ;
290+ paths. push ( Paths {
291+ ty : * ty,
292+ name : * path. last ( ) . unwrap ( ) ,
293+ path : Some ( index) ,
294+ } ) ;
295+ }
296+ }
297+ }
298+
299+ let mut names = Vec :: with_capacity ( self . items . len ( ) ) ;
300+ let mut types = String :: with_capacity ( self . items . len ( ) ) ;
301+ let mut full_paths = Vec :: with_capacity ( self . items . len ( ) ) ;
302+ let mut descriptions = Vec :: with_capacity ( self . items . len ( ) ) ;
303+ let mut parents = Vec :: with_capacity ( self . items . len ( ) ) ;
304+ let mut functions = Vec :: with_capacity ( self . items . len ( ) ) ;
305+ let mut deprecated = Vec :: with_capacity ( self . items . len ( ) ) ;
306+
307+ for ( index, item) in self . items . iter ( ) . enumerate ( ) {
308+ let n = item. ty as u8 ;
309+ let c = char:: try_from ( n + b'A' ) . expect ( "item types must fit in ASCII" ) ;
310+ assert ! ( c <= 'z' , "item types must fit within ASCII printables" ) ;
311+ types. push ( c) ;
312+
313+ assert_eq ! (
314+ item. parent. is_some( ) ,
315+ item. parent_idx. is_some( ) ,
316+ "`{}` is missing idx" ,
317+ item. name
318+ ) ;
319+ // 0 is a sentinel, everything else is one-indexed
320+ parents. push ( item. parent_idx . map ( |x| x + 1 ) . unwrap_or ( 0 ) ) ;
321+
322+ names. push ( item. name . as_str ( ) ) ;
323+ descriptions. push ( & item. desc ) ;
324+
325+ if !item. path . is_empty ( ) {
326+ full_paths. push ( ( index, & item. path ) ) ;
327+ }
328+
329+ // Fake option to get `0` out as a sentinel instead of `null`.
330+ // We want to use `0` because it's three less bytes.
331+ enum FunctionOption < ' a > {
332+ Function ( & ' a IndexItemFunctionType ) ,
333+ None ,
334+ }
335+ impl < ' a > Serialize for FunctionOption < ' a > {
336+ fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
337+ where
338+ S : Serializer ,
339+ {
340+ match self {
341+ FunctionOption :: None => 0 . serialize ( serializer) ,
342+ FunctionOption :: Function ( ty) => ty. serialize ( serializer) ,
343+ }
344+ }
345+ }
346+ functions. push ( match & item. search_type {
347+ Some ( ty) => FunctionOption :: Function ( ty) ,
348+ None => FunctionOption :: None ,
349+ } ) ;
350+
351+ if item. deprecation . is_some ( ) {
352+ deprecated. push ( index) ;
353+ }
354+ }
355+
356+ for ( index, path) in & revert_extra_paths {
357+ full_paths. push ( ( * index, path) ) ;
358+ }
359+
228360 let has_aliases = !self . aliases . is_empty ( ) ;
229361 let mut crate_data =
230362 serializer. serialize_struct ( "CrateData" , if has_aliases { 9 } else { 8 } ) ?;
231363 crate_data. serialize_field ( "doc" , & self . doc ) ?;
232- crate_data. serialize_field (
233- "t" ,
234- & self
235- . items
236- . iter ( )
237- . map ( |item| {
238- let n = item. ty as u8 ;
239- let c = char:: try_from ( n + b'A' ) . expect ( "item types must fit in ASCII" ) ;
240- assert ! ( c <= 'z' , "item types must fit within ASCII printables" ) ;
241- c
242- } )
243- . collect :: < String > ( ) ,
244- ) ?;
245- crate_data. serialize_field (
246- "n" ,
247- & self . items . iter ( ) . map ( |item| item. name . as_str ( ) ) . collect :: < Vec < _ > > ( ) ,
248- ) ?;
249- crate_data. serialize_field (
250- "q" ,
251- & self
252- . items
253- . iter ( )
254- . enumerate ( )
255- // Serialize as an array of item indices and full paths
256- . filter_map (
257- |( index, item) | {
258- if item. path . is_empty ( ) { None } else { Some ( ( index, & item. path ) ) }
259- } ,
260- )
261- . collect :: < Vec < _ > > ( ) ,
262- ) ?;
263- crate_data. serialize_field (
264- "d" ,
265- & self . items . iter ( ) . map ( |item| & item. desc ) . collect :: < Vec < _ > > ( ) ,
266- ) ?;
267- crate_data. serialize_field (
268- "i" ,
269- & self
270- . items
271- . iter ( )
272- . map ( |item| {
273- assert_eq ! (
274- item. parent. is_some( ) ,
275- item. parent_idx. is_some( ) ,
276- "`{}` is missing idx" ,
277- item. name
278- ) ;
279- // 0 is a sentinel, everything else is one-indexed
280- item. parent_idx . map ( |x| x + 1 ) . unwrap_or ( 0 )
281- } )
282- . collect :: < Vec < _ > > ( ) ,
283- ) ?;
284- crate_data. serialize_field (
285- "f" ,
286- & self
287- . items
288- . iter ( )
289- . map ( |item| {
290- // Fake option to get `0` out as a sentinel instead of `null`.
291- // We want to use `0` because it's three less bytes.
292- enum FunctionOption < ' a > {
293- Function ( & ' a IndexItemFunctionType ) ,
294- None ,
295- }
296- impl < ' a > Serialize for FunctionOption < ' a > {
297- fn serialize < S > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error >
298- where
299- S : Serializer ,
300- {
301- match self {
302- FunctionOption :: None => 0 . serialize ( serializer) ,
303- FunctionOption :: Function ( ty) => ty. serialize ( serializer) ,
304- }
305- }
306- }
307- match & item. search_type {
308- Some ( ty) => FunctionOption :: Function ( ty) ,
309- None => FunctionOption :: None ,
310- }
311- } )
312- . collect :: < Vec < _ > > ( ) ,
313- ) ?;
314- crate_data. serialize_field (
315- "c" ,
316- & self
317- . items
318- . iter ( )
319- . enumerate ( )
320- // Serialize as an array of deprecated item indices
321- . filter_map ( |( index, item) | item. deprecation . map ( |_| index) )
322- . collect :: < Vec < _ > > ( ) ,
323- ) ?;
324- crate_data. serialize_field (
325- "p" ,
326- & self . paths . iter ( ) . map ( |( it, s) | ( it, s. as_str ( ) ) ) . collect :: < Vec < _ > > ( ) ,
327- ) ?;
364+ crate_data. serialize_field ( "t" , & types) ?;
365+ crate_data. serialize_field ( "n" , & names) ?;
366+ // Serialize as an array of item indices and full paths
367+ crate_data. serialize_field ( "q" , & full_paths) ?;
368+ crate_data. serialize_field ( "d" , & descriptions) ?;
369+ crate_data. serialize_field ( "i" , & parents) ?;
370+ crate_data. serialize_field ( "f" , & functions) ?;
371+ crate_data. serialize_field ( "c" , & deprecated) ?;
372+ crate_data. serialize_field ( "p" , & paths) ?;
328373 if has_aliases {
329374 crate_data. serialize_field ( "a" , & self . aliases ) ?;
330375 }
0 commit comments