@@ -208,6 +208,46 @@ function initSearch(rawSearchIndex) {
208208 let typeNameIdMap ;
209209 const ALIASES = new Map ( ) ;
210210
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+
211251 function isWhitespace ( c ) {
212252 return " \t\n\r" . indexOf ( c ) !== - 1 ;
213253 }
@@ -217,7 +257,7 @@ function initSearch(rawSearchIndex) {
217257 }
218258
219259 function isEndCharacter ( c ) {
220- return ",>-" . indexOf ( c ) !== - 1 ;
260+ return ",>-] " . indexOf ( c ) !== - 1 ;
221261 }
222262
223263 function isStopCharacter ( c ) {
@@ -466,35 +506,64 @@ function initSearch(rawSearchIndex) {
466506
467507 let start = parserState . pos ;
468508 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+ } ) ;
474536 } 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 ) ;
482544 }
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+ ) ;
488566 }
489- elems . push (
490- createQueryElement (
491- query ,
492- parserState ,
493- parserState . userQuery . slice ( start , end ) ,
494- generics ,
495- isInGenerics
496- )
497- ) ;
498567 }
499568
500569 /**
@@ -518,6 +587,17 @@ function initSearch(rawSearchIndex) {
518587 const oldTypeFilter = parserState . typeFilter ;
519588 parserState . typeFilter = null ;
520589
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+
521601 while ( parserState . pos < parserState . length ) {
522602 const c = parserState . userQuery [ parserState . pos ] ;
523603 if ( c === endChar ) {
@@ -547,14 +627,6 @@ function initSearch(rawSearchIndex) {
547627 foundStopChar = true ;
548628 continue ;
549629 } else if ( isEndCharacter ( c ) ) {
550- let extra = "" ;
551- if ( endChar === ">" ) {
552- extra = "<" ;
553- } else if ( endChar === "" ) {
554- extra = "->" ;
555- } else {
556- extra = endChar ;
557- }
558630 throw [ "Unexpected " , c , " after " , extra ] ;
559631 }
560632 if ( ! foundStopChar ) {
@@ -581,9 +653,9 @@ function initSearch(rawSearchIndex) {
581653 }
582654 const posBefore = parserState . pos ;
583655 start = parserState . pos ;
584- getNextElem ( query , parserState , elems , endChar === "> ") ;
656+ getNextElem ( query , parserState , elems , endChar !== " ") ;
585657 if ( endChar !== "" && parserState . pos >= parserState . length ) {
586- throw [ "Unclosed " , "<" ] ;
658+ throw [ "Unclosed " , extra ] ;
587659 }
588660 // This case can be encountered if `getNextElem` encountered a "stop character" right
589661 // from the start. For example if you have `,,` or `<>`. In this case, we simply move up
@@ -594,7 +666,7 @@ function initSearch(rawSearchIndex) {
594666 foundStopChar = false ;
595667 }
596668 if ( parserState . pos >= parserState . length && endChar !== "" ) {
597- throw [ "Unclosed " , "<" ] ;
669+ throw [ "Unclosed " , extra ] ;
598670 }
599671 // We are either at the end of the string or on the `endChar` character, let's move forward
600672 // in any case.
@@ -779,7 +851,8 @@ function initSearch(rawSearchIndex) {
779851 *
780852 * ident = *(ALPHA / DIGIT / "_")
781853 * 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)
783856 * type-sep = COMMA/WS *(COMMA/WS)
784857 * nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
785858 * generics = OPEN-ANGLE-BRACKET [ nonempty-arg-list ] *(type-sep)
@@ -821,6 +894,8 @@ function initSearch(rawSearchIndex) {
821894 *
822895 * OPEN-ANGLE-BRACKET = "<"
823896 * CLOSE-ANGLE-BRACKET = ">"
897+ * OPEN-SQUARE-BRACKET = "["
898+ * CLOSE-SQUARE-BRACKET = "]"
824899 * COLON = ":"
825900 * DOUBLE-COLON = "::"
826901 * QUOTE = %x22
@@ -1170,7 +1245,22 @@ function initSearch(rawSearchIndex) {
11701245 // ones with no type filter, which can match any entry regardless of its
11711246 // own type.
11721247 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 ) ) {
11741264 return false ;
11751265 }
11761266 }
@@ -1217,7 +1307,12 @@ function initSearch(rawSearchIndex) {
12171307 return row . generics . length > 0 ? checkIfInGenerics ( row , elem ) : false ;
12181308 }
12191309
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 ) ) {
12211316 if ( elem . generics . length > 0 ) {
12221317 return checkGenerics ( row , elem ) ;
12231318 }
@@ -2082,34 +2177,6 @@ function initSearch(rawSearchIndex) {
20822177 filterCrates ) ;
20832178 }
20842179
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-
21132180 /**
21142181 * Convert a list of RawFunctionType / ID to object-based FunctionType.
21152182 *
@@ -2128,7 +2195,7 @@ function initSearch(rawSearchIndex) {
21282195 *
21292196 * @return {Array<FunctionSearchType> }
21302197 */
2131- function buildItemSearchTypeAll ( types , lowercasePaths , typeNameIdMap ) {
2198+ function buildItemSearchTypeAll ( types , lowercasePaths ) {
21322199 const PATH_INDEX_DATA = 0 ;
21332200 const GENERICS_DATA = 1 ;
21342201 return types . map ( type => {
@@ -2140,15 +2207,14 @@ function initSearch(rawSearchIndex) {
21402207 pathIndex = type [ PATH_INDEX_DATA ] ;
21412208 generics = buildItemSearchTypeAll (
21422209 type [ GENERICS_DATA ] ,
2143- lowercasePaths ,
2144- typeNameIdMap
2210+ lowercasePaths
21452211 ) ;
21462212 }
21472213 return {
21482214 // `0` is used as a sentinel because it's fewer bytes than `null`
21492215 id : pathIndex === 0
21502216 ? - 1
2151- : buildTypeMapIndex ( typeNameIdMap , lowercasePaths [ pathIndex - 1 ] . name ) ,
2217+ : buildTypeMapIndex ( lowercasePaths [ pathIndex - 1 ] . name ) ,
21522218 ty : pathIndex === 0 ? null : lowercasePaths [ pathIndex - 1 ] . ty ,
21532219 generics : generics ,
21542220 } ;
@@ -2171,7 +2237,7 @@ function initSearch(rawSearchIndex) {
21712237 *
21722238 * @return {null|FunctionSearchType }
21732239 */
2174- function buildFunctionSearchType ( functionSearchType , lowercasePaths , typeNameIdMap ) {
2240+ function buildFunctionSearchType ( functionSearchType , lowercasePaths ) {
21752241 const INPUTS_DATA = 0 ;
21762242 const OUTPUT_DATA = 1 ;
21772243 // `0` is used as a sentinel because it's fewer bytes than `null`
@@ -2184,15 +2250,14 @@ function initSearch(rawSearchIndex) {
21842250 inputs = [ {
21852251 id : pathIndex === 0
21862252 ? - 1
2187- : buildTypeMapIndex ( typeNameIdMap , lowercasePaths [ pathIndex - 1 ] . name ) ,
2253+ : buildTypeMapIndex ( lowercasePaths [ pathIndex - 1 ] . name ) ,
21882254 ty : pathIndex === 0 ? null : lowercasePaths [ pathIndex - 1 ] . ty ,
21892255 generics : [ ] ,
21902256 } ] ;
21912257 } else {
21922258 inputs = buildItemSearchTypeAll (
21932259 functionSearchType [ INPUTS_DATA ] ,
2194- lowercasePaths ,
2195- typeNameIdMap
2260+ lowercasePaths
21962261 ) ;
21972262 }
21982263 if ( functionSearchType . length > 1 ) {
@@ -2201,15 +2266,14 @@ function initSearch(rawSearchIndex) {
22012266 output = [ {
22022267 id : pathIndex === 0
22032268 ? - 1
2204- : buildTypeMapIndex ( typeNameIdMap , lowercasePaths [ pathIndex - 1 ] . name ) ,
2269+ : buildTypeMapIndex ( lowercasePaths [ pathIndex - 1 ] . name ) ,
22052270 ty : pathIndex === 0 ? null : lowercasePaths [ pathIndex - 1 ] . ty ,
22062271 generics : [ ] ,
22072272 } ] ;
22082273 } else {
22092274 output = buildItemSearchTypeAll (
22102275 functionSearchType [ OUTPUT_DATA ] ,
2211- lowercasePaths ,
2212- typeNameIdMap
2276+ lowercasePaths
22132277 ) ;
22142278 }
22152279 } else {
@@ -2233,6 +2297,12 @@ function initSearch(rawSearchIndex) {
22332297 let currentIndex = 0 ;
22342298 let id = 0 ;
22352299
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+
22362306 for ( const crate in rawSearchIndex ) {
22372307 if ( ! hasOwnPropertyRustdoc ( rawSearchIndex , crate ) ) {
22382308 continue ;
@@ -2363,8 +2433,7 @@ function initSearch(rawSearchIndex) {
23632433 parent : itemParentIdxs [ i ] > 0 ? paths [ itemParentIdxs [ i ] - 1 ] : undefined ,
23642434 type : buildFunctionSearchType (
23652435 itemFunctionSearchTypes [ i ] ,
2366- lowercasePaths ,
2367- typeNameIdMap
2436+ lowercasePaths
23682437 ) ,
23692438 id : id ,
23702439 normalizedName : word . indexOf ( "_" ) === - 1 ? word : word . replace ( / _ / g, "" ) ,
0 commit comments