rustdoc: search for tuples and unit by type with ()
This commit is contained in:
parent
a75fed74b6
commit
f6a045cc6b
9 changed files with 616 additions and 54 deletions
|
@ -150,12 +150,55 @@ will match these queries:
|
||||||
|
|
||||||
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
|
But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
|
||||||
|
|
||||||
Function signature searches also support arrays and slices. The explicit name
|
### Primitives with Special Syntax
|
||||||
`primitive:slice<u8>` and `primitive:array<u8>` can be used to match a slice
|
|
||||||
or array of bytes, while square brackets `[u8]` will match either one. Empty
|
<table>
|
||||||
square brackets, `[]`, will match any slice or array regardless of what
|
<thead>
|
||||||
it contains, while a slice with a type parameter, like `[T]`, will only match
|
<tr>
|
||||||
functions that actually operate on generic slices.
|
<th>Shorthand</th>
|
||||||
|
<th>Explicit names</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td><code>[]</code></td>
|
||||||
|
<td><code>primitive:slice</code> and/or <code>primitive:array</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>[T]</code></td>
|
||||||
|
<td><code>primitive:slice<T></code> and/or <code>primitive:array<T></code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>()</code></td>
|
||||||
|
<td><code>primitive:unit</code> and/or <code>primitive:tuple</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>(T)</code></td>
|
||||||
|
<td><code>T</code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>(T,)</code></td>
|
||||||
|
<td><code>primitive:tuple<T></code></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><code>!</code></td>
|
||||||
|
<td><code>primitive:never</code></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
When searching for `[]`, Rustdoc will return search results with either slices
|
||||||
|
or arrays. If you know which one you want, you can force it to return results
|
||||||
|
for `primitive:slice` or `primitive:array` using the explicit name syntax.
|
||||||
|
Empty square brackets, `[]`, will match any slice or array regardless of what
|
||||||
|
it contains, or an item type can be provided, such as `[u8]` or `[T]`, to
|
||||||
|
explicitly find functions that operate on byte slices or generic slices,
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
A single type expression wrapped in parens is the same as that type expression,
|
||||||
|
since parens act as the grouping operator. If they're empty, though, they will
|
||||||
|
match both `unit` and `tuple`, and if there's more than one type (or a trailing
|
||||||
|
or leading comma) it is the same as `primitive:tuple<...>`.
|
||||||
|
|
||||||
### Limitations and quirks of type-based search
|
### Limitations and quirks of type-based search
|
||||||
|
|
||||||
|
@ -188,11 +231,10 @@ Most of these limitations should be addressed in future version of Rustdoc.
|
||||||
that you don't want a type parameter, you can force it to match
|
that you don't want a type parameter, you can force it to match
|
||||||
something else by giving it a different prefix like `struct:T`.
|
something else by giving it a different prefix like `struct:T`.
|
||||||
|
|
||||||
* It's impossible to search for references, pointers, or tuples. The
|
* It's impossible to search for references or pointers. The
|
||||||
wrapped types can be searched for, so a function that takes `&File` can
|
wrapped types can be searched for, so a function that takes `&File` can
|
||||||
be found with `File`, but you'll get a parse error when typing an `&`
|
be found with `File`, but you'll get a parse error when typing an `&`
|
||||||
into the search field. Similarly, `Option<(T, U)>` can be matched with
|
into the search field.
|
||||||
`Option<T, U>`, but `(` will give a parse error.
|
|
||||||
|
|
||||||
* Searching for lifetimes is not supported.
|
* Searching for lifetimes is not supported.
|
||||||
|
|
||||||
|
@ -216,8 +258,9 @@ Item filters can be used in both name-based and type signature-based searches.
|
||||||
```text
|
```text
|
||||||
ident = *(ALPHA / DIGIT / "_")
|
ident = *(ALPHA / DIGIT / "_")
|
||||||
path = ident *(DOUBLE-COLON ident) [!]
|
path = ident *(DOUBLE-COLON ident) [!]
|
||||||
slice = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
|
slice-like = OPEN-SQUARE-BRACKET [ nonempty-arg-list ] CLOSE-SQUARE-BRACKET
|
||||||
arg = [type-filter *WS COLON *WS] (path [generics] / slice / [!])
|
tuple-like = OPEN-PAREN [ nonempty-arg-list ] CLOSE-PAREN
|
||||||
|
arg = [type-filter *WS COLON *WS] (path [generics] / slice-like / tuple-like / [!])
|
||||||
type-sep = COMMA/WS *(COMMA/WS)
|
type-sep = COMMA/WS *(COMMA/WS)
|
||||||
nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
|
nonempty-arg-list = *(type-sep) arg *(type-sep arg) *(type-sep)
|
||||||
generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep)
|
generic-arg-list = *(type-sep) arg [ EQUAL arg ] *(type-sep arg [ EQUAL arg ]) *(type-sep)
|
||||||
|
@ -263,6 +306,8 @@ OPEN-ANGLE-BRACKET = "<"
|
||||||
CLOSE-ANGLE-BRACKET = ">"
|
CLOSE-ANGLE-BRACKET = ">"
|
||||||
OPEN-SQUARE-BRACKET = "["
|
OPEN-SQUARE-BRACKET = "["
|
||||||
CLOSE-SQUARE-BRACKET = "]"
|
CLOSE-SQUARE-BRACKET = "]"
|
||||||
|
OPEN-PAREN = "("
|
||||||
|
CLOSE-PAREN = ")"
|
||||||
COLON = ":"
|
COLON = ":"
|
||||||
DOUBLE-COLON = "::"
|
DOUBLE-COLON = "::"
|
||||||
QUOTE = %x22
|
QUOTE = %x22
|
||||||
|
|
|
@ -581,6 +581,9 @@ fn get_index_type_id(
|
||||||
// The type parameters are converted to generics in `simplify_fn_type`
|
// The type parameters are converted to generics in `simplify_fn_type`
|
||||||
clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
|
clean::Slice(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Slice)),
|
||||||
clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
|
clean::Array(_, _) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Array)),
|
||||||
|
clean::Tuple(ref n) if n.is_empty() => {
|
||||||
|
Some(RenderTypeId::Primitive(clean::PrimitiveType::Unit))
|
||||||
|
}
|
||||||
clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
|
clean::Tuple(_) => Some(RenderTypeId::Primitive(clean::PrimitiveType::Tuple)),
|
||||||
clean::QPath(ref data) => {
|
clean::QPath(ref data) => {
|
||||||
if data.self_type.is_self_type()
|
if data.self_type.is_self_type()
|
||||||
|
|
|
@ -260,6 +260,18 @@ function initSearch(rawSearchIndex) {
|
||||||
* Special type name IDs for searching by both array and slice (`[]` syntax).
|
* Special type name IDs for searching by both array and slice (`[]` syntax).
|
||||||
*/
|
*/
|
||||||
let typeNameIdOfArrayOrSlice;
|
let typeNameIdOfArrayOrSlice;
|
||||||
|
/**
|
||||||
|
* Special type name IDs for searching by tuple.
|
||||||
|
*/
|
||||||
|
let typeNameIdOfTuple;
|
||||||
|
/**
|
||||||
|
* Special type name IDs for searching by unit.
|
||||||
|
*/
|
||||||
|
let typeNameIdOfUnit;
|
||||||
|
/**
|
||||||
|
* Special type name IDs for searching by both tuple and unit (`()` syntax).
|
||||||
|
*/
|
||||||
|
let typeNameIdOfTupleOrUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an item to the type Name->ID map, or, if one already exists, use it.
|
* Add an item to the type Name->ID map, or, if one already exists, use it.
|
||||||
|
@ -295,11 +307,7 @@ function initSearch(rawSearchIndex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEndCharacter(c) {
|
function isEndCharacter(c) {
|
||||||
return "=,>-]".indexOf(c) !== -1;
|
return "=,>-])".indexOf(c) !== -1;
|
||||||
}
|
|
||||||
|
|
||||||
function isErrorCharacter(c) {
|
|
||||||
return "()".indexOf(c) !== -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function itemTypeFromName(typename) {
|
function itemTypeFromName(typename) {
|
||||||
|
@ -585,8 +593,6 @@ function initSearch(rawSearchIndex) {
|
||||||
throw ["Unexpected ", "!", ": it can only be at the end of an ident"];
|
throw ["Unexpected ", "!", ": it can only be at the end of an ident"];
|
||||||
}
|
}
|
||||||
foundExclamation = parserState.pos;
|
foundExclamation = parserState.pos;
|
||||||
} else if (isErrorCharacter(c)) {
|
|
||||||
throw ["Unexpected ", c];
|
|
||||||
} else if (isPathSeparator(c)) {
|
} else if (isPathSeparator(c)) {
|
||||||
if (c === ":") {
|
if (c === ":") {
|
||||||
if (!isPathStart(parserState)) {
|
if (!isPathStart(parserState)) {
|
||||||
|
@ -616,11 +622,14 @@ function initSearch(rawSearchIndex) {
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
c === "[" ||
|
c === "[" ||
|
||||||
|
c === "(" ||
|
||||||
isEndCharacter(c) ||
|
isEndCharacter(c) ||
|
||||||
isSpecialStartCharacter(c) ||
|
isSpecialStartCharacter(c) ||
|
||||||
isSeparatorCharacter(c)
|
isSeparatorCharacter(c)
|
||||||
) {
|
) {
|
||||||
break;
|
break;
|
||||||
|
} else if (parserState.pos > 0) {
|
||||||
|
throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]];
|
||||||
} else {
|
} else {
|
||||||
throw ["Unexpected ", c];
|
throw ["Unexpected ", c];
|
||||||
}
|
}
|
||||||
|
@ -661,15 +670,24 @@ function initSearch(rawSearchIndex) {
|
||||||
skipWhitespace(parserState);
|
skipWhitespace(parserState);
|
||||||
let start = parserState.pos;
|
let start = parserState.pos;
|
||||||
let end;
|
let end;
|
||||||
if (parserState.userQuery[parserState.pos] === "[") {
|
if ("[(".indexOf(parserState.userQuery[parserState.pos]) !== -1) {
|
||||||
|
let endChar = ")";
|
||||||
|
let name = "()";
|
||||||
|
let friendlyName = "tuple";
|
||||||
|
|
||||||
|
if (parserState.userQuery[parserState.pos] === "[") {
|
||||||
|
endChar = "]";
|
||||||
|
name = "[]";
|
||||||
|
friendlyName = "slice";
|
||||||
|
}
|
||||||
parserState.pos += 1;
|
parserState.pos += 1;
|
||||||
getItemsBefore(query, parserState, generics, "]");
|
const { foundSeparator } = getItemsBefore(query, parserState, generics, endChar);
|
||||||
const typeFilter = parserState.typeFilter;
|
const typeFilter = parserState.typeFilter;
|
||||||
const isInBinding = parserState.isInBinding;
|
const isInBinding = parserState.isInBinding;
|
||||||
if (typeFilter !== null && typeFilter !== "primitive") {
|
if (typeFilter !== null && typeFilter !== "primitive") {
|
||||||
throw [
|
throw [
|
||||||
"Invalid search type: primitive ",
|
"Invalid search type: primitive ",
|
||||||
"[]",
|
name,
|
||||||
" and ",
|
" and ",
|
||||||
typeFilter,
|
typeFilter,
|
||||||
" both specified",
|
" both specified",
|
||||||
|
@ -677,27 +695,31 @@ function initSearch(rawSearchIndex) {
|
||||||
}
|
}
|
||||||
parserState.typeFilter = null;
|
parserState.typeFilter = null;
|
||||||
parserState.isInBinding = null;
|
parserState.isInBinding = null;
|
||||||
|
for (const gen of generics) {
|
||||||
|
if (gen.bindingName !== null) {
|
||||||
|
throw ["Type parameter ", "=", ` cannot be within ${friendlyName} `, name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name === "()" && !foundSeparator && generics.length === 1 && typeFilter === null) {
|
||||||
|
elems.push(generics[0]);
|
||||||
|
} else {
|
||||||
parserState.totalElems += 1;
|
parserState.totalElems += 1;
|
||||||
if (isInGenerics) {
|
if (isInGenerics) {
|
||||||
parserState.genericsElems += 1;
|
parserState.genericsElems += 1;
|
||||||
}
|
}
|
||||||
for (const gen of generics) {
|
|
||||||
if (gen.bindingName !== null) {
|
|
||||||
throw ["Type parameter ", "=", " cannot be within slice ", "[]"];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
elems.push({
|
elems.push({
|
||||||
name: "[]",
|
name: name,
|
||||||
id: null,
|
id: null,
|
||||||
fullPath: ["[]"],
|
fullPath: [name],
|
||||||
pathWithoutLast: [],
|
pathWithoutLast: [],
|
||||||
pathLast: "[]",
|
pathLast: name,
|
||||||
normalizedPathLast: "[]",
|
normalizedPathLast: name,
|
||||||
generics,
|
generics,
|
||||||
|
bindings: new Map(),
|
||||||
typeFilter: "primitive",
|
typeFilter: "primitive",
|
||||||
bindingName: isInBinding,
|
bindingName: isInBinding,
|
||||||
bindings: new Map(),
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const isStringElem = parserState.userQuery[start] === "\"";
|
const isStringElem = parserState.userQuery[start] === "\"";
|
||||||
// We handle the strings on their own mostly to make code easier to follow.
|
// We handle the strings on their own mostly to make code easier to follow.
|
||||||
|
@ -770,9 +792,11 @@ function initSearch(rawSearchIndex) {
|
||||||
* @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
|
* @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
|
||||||
* @param {string} endChar - This function will stop when it'll encounter this
|
* @param {string} endChar - This function will stop when it'll encounter this
|
||||||
* character.
|
* character.
|
||||||
|
* @returns {{foundSeparator: bool}}
|
||||||
*/
|
*/
|
||||||
function getItemsBefore(query, parserState, elems, endChar) {
|
function getItemsBefore(query, parserState, elems, endChar) {
|
||||||
let foundStopChar = true;
|
let foundStopChar = true;
|
||||||
|
let foundSeparator = false;
|
||||||
let start = parserState.pos;
|
let start = parserState.pos;
|
||||||
|
|
||||||
// If this is a generic, keep the outer item's type filter around.
|
// If this is a generic, keep the outer item's type filter around.
|
||||||
|
@ -786,6 +810,8 @@ function initSearch(rawSearchIndex) {
|
||||||
extra = "<";
|
extra = "<";
|
||||||
} else if (endChar === "]") {
|
} else if (endChar === "]") {
|
||||||
extra = "[";
|
extra = "[";
|
||||||
|
} else if (endChar === ")") {
|
||||||
|
extra = "(";
|
||||||
} else if (endChar === "") {
|
} else if (endChar === "") {
|
||||||
extra = "->";
|
extra = "->";
|
||||||
} else {
|
} else {
|
||||||
|
@ -802,6 +828,7 @@ function initSearch(rawSearchIndex) {
|
||||||
} else if (isSeparatorCharacter(c)) {
|
} else if (isSeparatorCharacter(c)) {
|
||||||
parserState.pos += 1;
|
parserState.pos += 1;
|
||||||
foundStopChar = true;
|
foundStopChar = true;
|
||||||
|
foundSeparator = true;
|
||||||
continue;
|
continue;
|
||||||
} else if (c === ":" && isPathStart(parserState)) {
|
} else if (c === ":" && isPathStart(parserState)) {
|
||||||
throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
|
throw ["Unexpected ", "::", ": paths cannot start with ", "::"];
|
||||||
|
@ -879,6 +906,8 @@ function initSearch(rawSearchIndex) {
|
||||||
|
|
||||||
parserState.typeFilter = oldTypeFilter;
|
parserState.typeFilter = oldTypeFilter;
|
||||||
parserState.isInBinding = oldIsInBinding;
|
parserState.isInBinding = oldIsInBinding;
|
||||||
|
|
||||||
|
return { foundSeparator };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -926,6 +955,8 @@ function initSearch(rawSearchIndex) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
throw ["Unexpected ", c, " (did you mean ", "->", "?)"];
|
throw ["Unexpected ", c, " (did you mean ", "->", "?)"];
|
||||||
|
} else if (parserState.pos > 0) {
|
||||||
|
throw ["Unexpected ", c, " after ", parserState.userQuery[parserState.pos - 1]];
|
||||||
}
|
}
|
||||||
throw ["Unexpected ", c];
|
throw ["Unexpected ", c];
|
||||||
} else if (c === ":" && !isPathStart(parserState)) {
|
} else if (c === ":" && !isPathStart(parserState)) {
|
||||||
|
@ -1599,6 +1630,11 @@ function initSearch(rawSearchIndex) {
|
||||||
) {
|
) {
|
||||||
// [] matches primitive:array or primitive:slice
|
// [] matches primitive:array or primitive:slice
|
||||||
// if it matches, then we're fine, and this is an appropriate match candidate
|
// if it matches, then we're fine, and this is an appropriate match candidate
|
||||||
|
} else if (queryElem.id === typeNameIdOfTupleOrUnit &&
|
||||||
|
(fnType.id === typeNameIdOfTuple || fnType.id === typeNameIdOfUnit)
|
||||||
|
) {
|
||||||
|
// () matches primitive:tuple or primitive:unit
|
||||||
|
// if it matches, then we're fine, and this is an appropriate match candidate
|
||||||
} else if (fnType.id !== queryElem.id || queryElem.id === null) {
|
} else if (fnType.id !== queryElem.id || queryElem.id === null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1792,7 +1828,7 @@ function initSearch(rawSearchIndex) {
|
||||||
if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
|
if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
|
||||||
typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 &&
|
typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 &&
|
||||||
// special case
|
// special case
|
||||||
elem.id !== typeNameIdOfArrayOrSlice
|
elem.id !== typeNameIdOfArrayOrSlice && elem.id !== typeNameIdOfTupleOrUnit
|
||||||
) {
|
) {
|
||||||
return row.id === elem.id || checkIfInList(
|
return row.id === elem.id || checkIfInList(
|
||||||
row.generics,
|
row.generics,
|
||||||
|
@ -2822,12 +2858,15 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||||
*/
|
*/
|
||||||
function buildFunctionTypeFingerprint(type, output, fps) {
|
function buildFunctionTypeFingerprint(type, output, fps) {
|
||||||
let input = type.id;
|
let input = type.id;
|
||||||
// All forms of `[]` get collapsed down to one thing in the bloom filter.
|
// All forms of `[]`/`()` get collapsed down to one thing in the bloom filter.
|
||||||
// Differentiating between arrays and slices, if the user asks for it, is
|
// Differentiating between arrays and slices, if the user asks for it, is
|
||||||
// still done in the matching algorithm.
|
// still done in the matching algorithm.
|
||||||
if (input === typeNameIdOfArray || input === typeNameIdOfSlice) {
|
if (input === typeNameIdOfArray || input === typeNameIdOfSlice) {
|
||||||
input = typeNameIdOfArrayOrSlice;
|
input = typeNameIdOfArrayOrSlice;
|
||||||
}
|
}
|
||||||
|
if (input === typeNameIdOfTuple || input === typeNameIdOfUnit) {
|
||||||
|
input = typeNameIdOfTupleOrUnit;
|
||||||
|
}
|
||||||
// http://burtleburtle.net/bob/hash/integer.html
|
// http://burtleburtle.net/bob/hash/integer.html
|
||||||
// ~~ is toInt32. It's used before adding, so
|
// ~~ is toInt32. It's used before adding, so
|
||||||
// the number stays in safe integer range.
|
// the number stays in safe integer range.
|
||||||
|
@ -2922,7 +2961,10 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||||
// that can be searched using `[]` syntax.
|
// that can be searched using `[]` syntax.
|
||||||
typeNameIdOfArray = buildTypeMapIndex("array");
|
typeNameIdOfArray = buildTypeMapIndex("array");
|
||||||
typeNameIdOfSlice = buildTypeMapIndex("slice");
|
typeNameIdOfSlice = buildTypeMapIndex("slice");
|
||||||
|
typeNameIdOfTuple = buildTypeMapIndex("tuple");
|
||||||
|
typeNameIdOfUnit = buildTypeMapIndex("unit");
|
||||||
typeNameIdOfArrayOrSlice = buildTypeMapIndex("[]");
|
typeNameIdOfArrayOrSlice = buildTypeMapIndex("[]");
|
||||||
|
typeNameIdOfTupleOrUnit = buildTypeMapIndex("()");
|
||||||
|
|
||||||
// Function type fingerprints are 128-bit bloom filters that are used to
|
// Function type fingerprints are 128-bit bloom filters that are used to
|
||||||
// estimate the distance between function and query.
|
// estimate the distance between function and query.
|
||||||
|
|
|
@ -24,7 +24,7 @@ const PARSED = [
|
||||||
original: "-> *",
|
original: "-> *",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "-> *",
|
userQuery: "-> *",
|
||||||
error: "Unexpected `*`",
|
error: "Unexpected `*` after ` `",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: 'a<"P">',
|
query: 'a<"P">',
|
||||||
|
@ -107,15 +107,6 @@ const PARSED = [
|
||||||
userQuery: "a<::a>",
|
userQuery: "a<::a>",
|
||||||
error: "Unexpected `::`: paths cannot start with `::`",
|
error: "Unexpected `::`: paths cannot start with `::`",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
query: "((a))",
|
|
||||||
elems: [],
|
|
||||||
foundElems: 0,
|
|
||||||
original: "((a))",
|
|
||||||
returned: [],
|
|
||||||
userQuery: "((a))",
|
|
||||||
error: "Unexpected `(`",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
query: "(p -> p",
|
query: "(p -> p",
|
||||||
elems: [],
|
elems: [],
|
||||||
|
@ -123,7 +114,7 @@ const PARSED = [
|
||||||
original: "(p -> p",
|
original: "(p -> p",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "(p -> p",
|
userQuery: "(p -> p",
|
||||||
error: "Unexpected `(`",
|
error: "Unexpected `-` after `(`",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: "::a::b",
|
query: "::a::b",
|
||||||
|
@ -204,7 +195,7 @@ const PARSED = [
|
||||||
original: "a (b:",
|
original: "a (b:",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "a (b:",
|
userQuery: "a (b:",
|
||||||
error: "Unexpected `(`",
|
error: "Expected `,`, `:` or `->`, found `(`",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: "_:",
|
query: "_:",
|
||||||
|
@ -249,7 +240,7 @@ const PARSED = [
|
||||||
original: "ab'",
|
original: "ab'",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "ab'",
|
userQuery: "ab'",
|
||||||
error: "Unexpected `'`",
|
error: "Unexpected `'` after `b`",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: "a->",
|
query: "a->",
|
||||||
|
|
|
@ -266,6 +266,24 @@ const PARSED = [
|
||||||
userQuery: "]",
|
userQuery: "]",
|
||||||
error: "Unexpected `]`",
|
error: "Unexpected `]`",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
query: '[a<b>',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "[a<b>",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "[a<b>",
|
||||||
|
error: "Unclosed `[`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: 'a<b>]',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "a<b>]",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "a<b>]",
|
||||||
|
error: "Unexpected `]` after `>`",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
query: 'primitive:[u8]',
|
query: 'primitive:[u8]',
|
||||||
elems: [
|
elems: [
|
||||||
|
|
365
tests/rustdoc-js-std/parser-tuple.js
Normal file
365
tests/rustdoc-js-std/parser-tuple.js
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
const PARSED = [
|
||||||
|
{
|
||||||
|
query: '(((D, ()))',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: '(((D, ()))',
|
||||||
|
returned: [],
|
||||||
|
userQuery: '(((d, ()))',
|
||||||
|
error: 'Unclosed `(`',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(((D, ())))',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "d",
|
||||||
|
fullPath: ["d"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "d",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: 1,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: '(((D, ())))',
|
||||||
|
returned: [],
|
||||||
|
userQuery: '(((d, ())))',
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(),u8',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 2,
|
||||||
|
original: "(),u8",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(),u8",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
// Parens act as grouping operators when:
|
||||||
|
// - there's no commas directly nested within
|
||||||
|
// - there's at least two child types (zero means unit)
|
||||||
|
// - it's not tagged with a type filter
|
||||||
|
// Otherwise, they represent unit and/or tuple. To search for
|
||||||
|
// unit or tuple specifically, use `primitive:unit` or `primitive:tuple<...>`.
|
||||||
|
{
|
||||||
|
query: '(u8)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "(u8)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(u8)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(u8,)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "(u8,)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(u8,)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(,u8)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "(,u8)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(,u8)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: 'primitive:(u8)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "primitive:(u8)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "primitive:(u8)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(primitive:u8)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "(primitive:u8)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(primitive:u8)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(u8,u8)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "(u8,u8)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(u8,u8)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(u8<u8>)',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [
|
||||||
|
{
|
||||||
|
name: "u8",
|
||||||
|
fullPath: ["u8"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "u8",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
typeFilter: -1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "(u8<u8>)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(u8<u8>)",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '()',
|
||||||
|
elems: [
|
||||||
|
{
|
||||||
|
name: "()",
|
||||||
|
fullPath: ["()"],
|
||||||
|
pathWithoutLast: [],
|
||||||
|
pathLast: "()",
|
||||||
|
generics: [],
|
||||||
|
typeFilter: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
foundElems: 1,
|
||||||
|
original: "()",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "()",
|
||||||
|
error: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(>',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "(>",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(>",
|
||||||
|
error: "Unexpected `>` after `(`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(<',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "(<",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(<",
|
||||||
|
error: "Found generics without a path",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(a>',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "(a>",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(a>",
|
||||||
|
error: "Unexpected `>` after `(`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(a<',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "(a<",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(a<",
|
||||||
|
error: "Unclosed `<`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(a',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "(a",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(a",
|
||||||
|
error: "Unclosed `(`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "(",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(",
|
||||||
|
error: "Unclosed `(`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: ')',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: ")",
|
||||||
|
returned: [],
|
||||||
|
userQuery: ")",
|
||||||
|
error: "Unexpected `)`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: '(a<b>',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "(a<b>",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "(a<b>",
|
||||||
|
error: "Unclosed `(`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: 'a<b>)',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "a<b>)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "a<b>)",
|
||||||
|
error: "Unexpected `)` after `>`",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query: 'macro:(u8)',
|
||||||
|
elems: [],
|
||||||
|
foundElems: 0,
|
||||||
|
original: "macro:(u8)",
|
||||||
|
returned: [],
|
||||||
|
userQuery: "macro:(u8)",
|
||||||
|
error: "Invalid search type: primitive `()` and `macro` both specified",
|
||||||
|
},
|
||||||
|
];
|
|
@ -44,7 +44,7 @@ const PARSED = [
|
||||||
original: "a,b(c)",
|
original: "a,b(c)",
|
||||||
returned: [],
|
returned: [],
|
||||||
userQuery: "a,b(c)",
|
userQuery: "a,b(c)",
|
||||||
error: "Unexpected `(`",
|
error: "Expected `,`, `:` or `->`, found `(`",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
query: 'aaa,a',
|
query: 'aaa,a',
|
||||||
|
|
80
tests/rustdoc-js/tuple-unit.js
Normal file
80
tests/rustdoc-js/tuple-unit.js
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// exact-check
|
||||||
|
|
||||||
|
const EXPECTED = [
|
||||||
|
{
|
||||||
|
'query': '()',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'side_effect' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'one' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'two' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'nest' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'primitive:unit',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'side_effect' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': 'primitive:tuple',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'one' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'two' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'nest' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '(P)',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'not_tuple' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'one' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'two' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '(P,)',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'one' },
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'two' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '(P, P)',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'two' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '(P, ())',
|
||||||
|
'returned': [],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '(Q, ())',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'nest' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '(R)',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'nest' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'query': '(u32)',
|
||||||
|
'returned': [
|
||||||
|
{ 'path': 'tuple_unit', 'name': 'nest' },
|
||||||
|
],
|
||||||
|
'in_args': [],
|
||||||
|
},
|
||||||
|
];
|
18
tests/rustdoc-js/tuple-unit.rs
Normal file
18
tests/rustdoc-js/tuple-unit.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
pub struct P;
|
||||||
|
pub struct Q;
|
||||||
|
pub struct R<T>(T);
|
||||||
|
|
||||||
|
// Checks that tuple and unit both work
|
||||||
|
pub fn side_effect() { }
|
||||||
|
|
||||||
|
// Check a non-tuple
|
||||||
|
pub fn not_tuple() -> P { loop {} }
|
||||||
|
|
||||||
|
// Check a 1-tuple
|
||||||
|
pub fn one() -> (P,) { loop {} }
|
||||||
|
|
||||||
|
// Check a 2-tuple
|
||||||
|
pub fn two() -> (P,P) { loop {} }
|
||||||
|
|
||||||
|
// Check a nested tuple
|
||||||
|
pub fn nest() -> (Q, R<(u32,)>) { loop {} }
|
Loading…
Add table
Add a link
Reference in a new issue