@@ -208,6 +208,46 @@ function initSearch(rawSearchIndex) {
208
208
let typeNameIdMap ;
209
209
const ALIASES = new Map ( ) ;
210
210
211
+ /**
212
+ * Special type name IDs for searching by array.
213
+ */
214
+ let typeNameIdOfArray ;
215
+ /**
216
+ * Special type name IDs for searching by slice.
217
+ */
218
+ let typeNameIdOfSlice ;
219
+ /**
220
+ * Special type name IDs for searching by both array and slice (`[]` syntax).
221
+ */
222
+ let typeNameIdOfArrayOrSlice ;
223
+
224
+ /**
225
+ * Add an item to the type Name->ID map, or, if one already exists, use it.
226
+ * Returns the number. If name is "" or null, return -1 (pure generic).
227
+ *
228
+ * This is effectively string interning, so that function matching can be
229
+ * done more quickly. Two types with the same name but different item kinds
230
+ * get the same ID.
231
+ *
232
+ * @param {string } name
233
+ *
234
+ * @returns {integer }
235
+ */
236
+ function buildTypeMapIndex ( name ) {
237
+
238
+ if ( name === "" || name === null ) {
239
+ return - 1 ;
240
+ }
241
+
242
+ if ( typeNameIdMap . has ( name ) ) {
243
+ return typeNameIdMap . get ( name ) ;
244
+ } else {
245
+ const id = typeNameIdMap . size ;
246
+ typeNameIdMap . set ( name , id ) ;
247
+ return id ;
248
+ }
249
+ }
250
+
211
251
function isWhitespace ( c ) {
212
252
return " \t\n\r" . indexOf ( c ) !== - 1 ;
213
253
}
@@ -217,7 +257,7 @@ function initSearch(rawSearchIndex) {
217
257
}
218
258
219
259
function isEndCharacter ( c ) {
220
- return ",>-" . indexOf ( c ) !== - 1 ;
260
+ return ",>-] " . indexOf ( c ) !== - 1 ;
221
261
}
222
262
223
263
function isStopCharacter ( c ) {
@@ -466,35 +506,64 @@ function initSearch(rawSearchIndex) {
466
506
467
507
let start = parserState . pos ;
468
508
let end ;
469
- // We handle the strings on their own mostly to make code easier to follow.
470
- if ( parserState . userQuery [ parserState . pos ] === "\"" ) {
471
- start += 1 ;
472
- getStringElem ( query , parserState , isInGenerics ) ;
473
- end = parserState . pos - 1 ;
509
+ if ( parserState . userQuery [ parserState . pos ] === "[" ) {
510
+ parserState . pos += 1 ;
511
+ getItemsBefore ( query , parserState , generics , "]" ) ;
512
+ const typeFilter = parserState . typeFilter ;
513
+ if ( typeFilter !== null && typeFilter !== "primitive" ) {
514
+ throw [
515
+ "Invalid search type: primitive " ,
516
+ "[]" ,
517
+ " and " ,
518
+ typeFilter ,
519
+ " both specified" ,
520
+ ] ;
521
+ }
522
+ parserState . typeFilter = null ;
523
+ parserState . totalElems += 1 ;
524
+ if ( isInGenerics ) {
525
+ parserState . genericsElems += 1 ;
526
+ }
527
+ elems . push ( {
528
+ name : "[]" ,
529
+ id : - 1 ,
530
+ fullPath : [ "[]" ] ,
531
+ pathWithoutLast : [ ] ,
532
+ pathLast : "[]" ,
533
+ generics,
534
+ typeFilter : "primitive" ,
535
+ } ) ;
474
536
} else {
475
- end = getIdentEndPosition ( parserState ) ;
476
- }
477
- if ( parserState . pos < parserState . length &&
478
- parserState . userQuery [ parserState . pos ] === "<"
479
- ) {
480
- if ( start >= end ) {
481
- throw [ "Found generics without a path" ] ;
537
+ // We handle the strings on their own mostly to make code easier to follow.
538
+ if ( parserState . userQuery [ parserState . pos ] === "\"" ) {
539
+ start += 1 ;
540
+ getStringElem ( query , parserState , isInGenerics ) ;
541
+ end = parserState . pos - 1 ;
542
+ } else {
543
+ end = getIdentEndPosition ( parserState ) ;
482
544
}
483
- parserState . pos += 1 ;
484
- getItemsBefore ( query , parserState , generics , ">" ) ;
485
- }
486
- if ( start >= end && generics . length === 0 ) {
487
- return ;
545
+ if ( parserState . pos < parserState . length &&
546
+ parserState . userQuery [ parserState . pos ] === "<"
547
+ ) {
548
+ if ( start >= end ) {
549
+ throw [ "Found generics without a path" ] ;
550
+ }
551
+ parserState . pos += 1 ;
552
+ getItemsBefore ( query , parserState , generics , ">" ) ;
553
+ }
554
+ if ( start >= end && generics . length === 0 ) {
555
+ return ;
556
+ }
557
+ elems . push (
558
+ createQueryElement (
559
+ query ,
560
+ parserState ,
561
+ parserState . userQuery . slice ( start , end ) ,
562
+ generics ,
563
+ isInGenerics
564
+ )
565
+ ) ;
488
566
}
489
- elems . push (
490
- createQueryElement (
491
- query ,
492
- parserState ,
493
- parserState . userQuery . slice ( start , end ) ,
494
- generics ,
495
- isInGenerics
496
- )
497
- ) ;
498
567
}
499
568
500
569
/**
@@ -518,6 +587,17 @@ function initSearch(rawSearchIndex) {
518
587
const oldTypeFilter = parserState . typeFilter ;
519
588
parserState . typeFilter = null ;
520
589
590
+ let extra = "" ;
591
+ if ( endChar === ">" ) {
592
+ extra = "<" ;
593
+ } else if ( endChar === "]" ) {
594
+ extra = "[" ;
595
+ } else if ( endChar === "" ) {
596
+ extra = "->" ;
597
+ } else {
598
+ extra = endChar ;
599
+ }
600
+
521
601
while ( parserState . pos < parserState . length ) {
522
602
const c = parserState . userQuery [ parserState . pos ] ;
523
603
if ( c === endChar ) {
@@ -547,14 +627,6 @@ function initSearch(rawSearchIndex) {
547
627
foundStopChar = true ;
548
628
continue ;
549
629
} else if ( isEndCharacter ( c ) ) {
550
- let extra = "" ;
551
- if ( endChar === ">" ) {
552
- extra = "<" ;
553
- } else if ( endChar === "" ) {
554
- extra = "->" ;
555
- } else {
556
- extra = endChar ;
557
- }
558
630
throw [ "Unexpected " , c , " after " , extra ] ;
559
631
}
560
632
if ( ! foundStopChar ) {
@@ -581,9 +653,9 @@ function initSearch(rawSearchIndex) {
581
653
}
582
654
const posBefore = parserState . pos ;
583
655
start = parserState . pos ;
584
- getNextElem ( query , parserState , elems , endChar === "> ") ;
656
+ getNextElem ( query , parserState , elems , endChar !== " ") ;
585
657
if ( endChar !== "" && parserState . pos >= parserState . length ) {
586
- throw [ "Unclosed " , "<" ] ;
658
+ throw [ "Unclosed " , extra ] ;
587
659
}
588
660
// This case can be encountered if `getNextElem` encountered a "stop character" right
589
661
// from the start. For example if you have `,,` or `<>`. In this case, we simply move up
@@ -594,7 +666,7 @@ function initSearch(rawSearchIndex) {
594
666
foundStopChar = false ;
595
667
}
596
668
if ( parserState . pos >= parserState . length && endChar !== "" ) {
597
- throw [ "Unclosed " , "<" ] ;
669
+ throw [ "Unclosed " , extra ] ;
598
670
}
599
671
// We are either at the end of the string or on the `endChar` character, let's move forward
600
672
// in any case.
@@ -779,7 +851,8 @@ function initSearch(rawSearchIndex) {
779
851
*
780
852
* ident = *(ALPHA / DIGIT / "_")
781
853
* path = ident *(DOUBLE-COLON ident) [!]
782
- * arg = [type-filter *WS COLON *WS] path [generics]
854
+ * slice = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
855
+ * arg = [type-filter *WS COLON *WS] (path [generics] / slice)
783
856
* type-sep = COMMA/WS *(COMMA/WS)
784
857
* nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
785
858
* generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list ] *(type-sep)
@@ -821,6 +894,8 @@ function initSearch(rawSearchIndex) {
821
894
*
822
895
* OPEN-ANGLE-BRACKET = "<"
823
896
* CLOSE-ANGLE-BRACKET = ">"
897
+ * OPEN-SQUARE-BRACKET = "["
898
+ * CLOSE-SQUARE-BRACKET = "]"
824
899
* COLON = ":"
825
900
* DOUBLE-COLON = "::"
826
901
* QUOTE = %x22
@@ -1170,7 +1245,22 @@ function initSearch(rawSearchIndex) {
1170
1245
// ones with no type filter, which can match any entry regardless of its
1171
1246
// own type.
1172
1247
for ( const generic of elem . generics ) {
1173
- if ( generic . typeFilter !== - 1 && ! handleGeneric ( generic ) ) {
1248
+ if ( generic . typeFilter === TY_PRIMITIVE &&
1249
+ generic . id === typeNameIdOfArrayOrSlice ) {
1250
+ const genericArray = {
1251
+ id : typeNameIdOfArray ,
1252
+ typeFilter : TY_PRIMITIVE ,
1253
+ generics : generic . generics ,
1254
+ } ;
1255
+ const genericSlice = {
1256
+ id : typeNameIdOfSlice ,
1257
+ typeFilter : TY_PRIMITIVE ,
1258
+ generics : generic . generics ,
1259
+ } ;
1260
+ if ( ! handleGeneric ( genericArray ) && ! handleGeneric ( genericSlice ) ) {
1261
+ return false ;
1262
+ }
1263
+ } else if ( generic . typeFilter !== - 1 && ! handleGeneric ( generic ) ) {
1174
1264
return false ;
1175
1265
}
1176
1266
}
@@ -1217,7 +1307,12 @@ function initSearch(rawSearchIndex) {
1217
1307
return row . generics . length > 0 ? checkIfInGenerics ( row , elem ) : false ;
1218
1308
}
1219
1309
1220
- if ( row . id === elem . id && typePassesFilter ( elem . typeFilter , row . ty ) ) {
1310
+ const matchesExact = row . id === elem . id ;
1311
+ const matchesArrayOrSlice = elem . id === typeNameIdOfArrayOrSlice &&
1312
+ ( row . id === typeNameIdOfSlice || row . id === typeNameIdOfArray ) ;
1313
+
1314
+ if ( ( matchesExact || matchesArrayOrSlice ) &&
1315
+ typePassesFilter ( elem . typeFilter , row . ty ) ) {
1221
1316
if ( elem . generics . length > 0 ) {
1222
1317
return checkGenerics ( row , elem ) ;
1223
1318
}
@@ -2082,34 +2177,6 @@ function initSearch(rawSearchIndex) {
2082
2177
filterCrates ) ;
2083
2178
}
2084
2179
2085
- /**
2086
- * Add an item to the type Name->ID map, or, if one already exists, use it.
2087
- * Returns the number. If name is "" or null, return -1 (pure generic).
2088
- *
2089
- * This is effectively string interning, so that function matching can be
2090
- * done more quickly. Two types with the same name but different item kinds
2091
- * get the same ID.
2092
- *
2093
- * @param {Map<string, integer> } typeNameIdMap
2094
- * @param {string } name
2095
- *
2096
- * @returns {integer }
2097
- */
2098
- function buildTypeMapIndex ( typeNameIdMap , name ) {
2099
-
2100
- if ( name === "" || name === null ) {
2101
- return - 1 ;
2102
- }
2103
-
2104
- if ( typeNameIdMap . has ( name ) ) {
2105
- return typeNameIdMap . get ( name ) ;
2106
- } else {
2107
- const id = typeNameIdMap . size ;
2108
- typeNameIdMap . set ( name , id ) ;
2109
- return id ;
2110
- }
2111
- }
2112
-
2113
2180
/**
2114
2181
* Convert a list of RawFunctionType / ID to object-based FunctionType.
2115
2182
*
@@ -2128,7 +2195,7 @@ function initSearch(rawSearchIndex) {
2128
2195
*
2129
2196
* @return {Array<FunctionSearchType> }
2130
2197
*/
2131
- function buildItemSearchTypeAll ( types , lowercasePaths , typeNameIdMap ) {
2198
+ function buildItemSearchTypeAll ( types , lowercasePaths ) {
2132
2199
const PATH_INDEX_DATA = 0 ;
2133
2200
const GENERICS_DATA = 1 ;
2134
2201
return types . map ( type => {
@@ -2140,15 +2207,14 @@ function initSearch(rawSearchIndex) {
2140
2207
pathIndex = type [ PATH_INDEX_DATA ] ;
2141
2208
generics = buildItemSearchTypeAll (
2142
2209
type [ GENERICS_DATA ] ,
2143
- lowercasePaths ,
2144
- typeNameIdMap
2210
+ lowercasePaths
2145
2211
) ;
2146
2212
}
2147
2213
return {
2148
2214
// `0` is used as a sentinel because it's fewer bytes than `null`
2149
2215
id : pathIndex === 0
2150
2216
? - 1
2151
- : buildTypeMapIndex ( typeNameIdMap , lowercasePaths [ pathIndex - 1 ] . name ) ,
2217
+ : buildTypeMapIndex ( lowercasePaths [ pathIndex - 1 ] . name ) ,
2152
2218
ty : pathIndex === 0 ? null : lowercasePaths [ pathIndex - 1 ] . ty ,
2153
2219
generics : generics ,
2154
2220
} ;
@@ -2171,7 +2237,7 @@ function initSearch(rawSearchIndex) {
2171
2237
*
2172
2238
* @return {null|FunctionSearchType }
2173
2239
*/
2174
- function buildFunctionSearchType ( functionSearchType , lowercasePaths , typeNameIdMap ) {
2240
+ function buildFunctionSearchType ( functionSearchType , lowercasePaths ) {
2175
2241
const INPUTS_DATA = 0 ;
2176
2242
const OUTPUT_DATA = 1 ;
2177
2243
// `0` is used as a sentinel because it's fewer bytes than `null`
@@ -2184,15 +2250,14 @@ function initSearch(rawSearchIndex) {
2184
2250
inputs = [ {
2185
2251
id : pathIndex === 0
2186
2252
? - 1
2187
- : buildTypeMapIndex ( typeNameIdMap , lowercasePaths [ pathIndex - 1 ] . name ) ,
2253
+ : buildTypeMapIndex ( lowercasePaths [ pathIndex - 1 ] . name ) ,
2188
2254
ty : pathIndex === 0 ? null : lowercasePaths [ pathIndex - 1 ] . ty ,
2189
2255
generics : [ ] ,
2190
2256
} ] ;
2191
2257
} else {
2192
2258
inputs = buildItemSearchTypeAll (
2193
2259
functionSearchType [ INPUTS_DATA ] ,
2194
- lowercasePaths ,
2195
- typeNameIdMap
2260
+ lowercasePaths
2196
2261
) ;
2197
2262
}
2198
2263
if ( functionSearchType . length > 1 ) {
@@ -2201,15 +2266,14 @@ function initSearch(rawSearchIndex) {
2201
2266
output = [ {
2202
2267
id : pathIndex === 0
2203
2268
? - 1
2204
- : buildTypeMapIndex ( typeNameIdMap , lowercasePaths [ pathIndex - 1 ] . name ) ,
2269
+ : buildTypeMapIndex ( lowercasePaths [ pathIndex - 1 ] . name ) ,
2205
2270
ty : pathIndex === 0 ? null : lowercasePaths [ pathIndex - 1 ] . ty ,
2206
2271
generics : [ ] ,
2207
2272
} ] ;
2208
2273
} else {
2209
2274
output = buildItemSearchTypeAll (
2210
2275
functionSearchType [ OUTPUT_DATA ] ,
2211
- lowercasePaths ,
2212
- typeNameIdMap
2276
+ lowercasePaths
2213
2277
) ;
2214
2278
}
2215
2279
} else {
@@ -2233,6 +2297,12 @@ function initSearch(rawSearchIndex) {
2233
2297
let currentIndex = 0 ;
2234
2298
let id = 0 ;
2235
2299
2300
+ // Initialize type map indexes for primitive list types
2301
+ // that can be searched using `[]` syntax.
2302
+ typeNameIdOfArray = buildTypeMapIndex ( "array" ) ;
2303
+ typeNameIdOfSlice = buildTypeMapIndex ( "slice" ) ;
2304
+ typeNameIdOfArrayOrSlice = buildTypeMapIndex ( "[]" ) ;
2305
+
2236
2306
for ( const crate in rawSearchIndex ) {
2237
2307
if ( ! hasOwnPropertyRustdoc ( rawSearchIndex , crate ) ) {
2238
2308
continue ;
@@ -2363,8 +2433,7 @@ function initSearch(rawSearchIndex) {
2363
2433
parent : itemParentIdxs [ i ] > 0 ? paths [ itemParentIdxs [ i ] - 1 ] : undefined ,
2364
2434
type : buildFunctionSearchType (
2365
2435
itemFunctionSearchTypes [ i ] ,
2366
- lowercasePaths ,
2367
- typeNameIdMap
2436
+ lowercasePaths
2368
2437
) ,
2369
2438
id : id ,
2370
2439
normalizedName : word . indexOf ( "_" ) === - 1 ? word : word . replace ( / _ / g, "" ) ,
0 commit comments