mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-26 13:01:27 +03:00
rustdoc-search: show types signatures in results
This commit is contained in:
@@ -264,6 +264,7 @@ a.anchor,
|
||||
.mobile-topbar h2 a,
|
||||
h1 a,
|
||||
.search-results a,
|
||||
.search-results li,
|
||||
.stab,
|
||||
.result-name i {
|
||||
color: var(--main-color);
|
||||
@@ -379,7 +380,7 @@ details:not(.toggle) summary {
|
||||
margin-bottom: .6em;
|
||||
}
|
||||
|
||||
code, pre, .code-header {
|
||||
code, pre, .code-header, .type-signature {
|
||||
font-family: "Source Code Pro", monospace;
|
||||
}
|
||||
.docblock code, .docblock-short code {
|
||||
@@ -1205,22 +1206,28 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
||||
|
||||
.search-results.active {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.search-results > a {
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-areas:
|
||||
"search-result-name search-result-desc"
|
||||
"search-result-type-signature search-result-type-signature";
|
||||
grid-template-columns: .6fr .4fr;
|
||||
/* A little margin ensures the browser's outlining of focused links has room to display. */
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
border-bottom: 1px solid var(--search-result-border-color);
|
||||
gap: 1em;
|
||||
column-gap: 1em;
|
||||
}
|
||||
|
||||
.search-results > a > div.desc {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
flex: 2;
|
||||
grid-area: search-result-desc;
|
||||
}
|
||||
|
||||
.search-results a:hover,
|
||||
@@ -1232,7 +1239,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: start;
|
||||
flex: 3;
|
||||
grid-area: search-result-name;
|
||||
}
|
||||
.search-results .result-name .alias {
|
||||
color: var(--search-results-alias-color);
|
||||
@@ -1253,6 +1260,10 @@ so that we can apply CSS-filters to change the arrow color in themes */
|
||||
.search-results .result-name .path > * {
|
||||
display: inline;
|
||||
}
|
||||
.search-results .type-signature {
|
||||
grid-area: search-result-type-signature;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.popover {
|
||||
position: absolute;
|
||||
|
||||
@@ -92,6 +92,9 @@ let Results;
|
||||
* parent: (Object|undefined),
|
||||
* path: string,
|
||||
* ty: number,
|
||||
* type: FunctionSearchType?,
|
||||
* displayType: Promise<Array<Array<string>>>|null,
|
||||
* displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
|
||||
* }}
|
||||
*/
|
||||
let ResultObject;
|
||||
|
||||
@@ -15,7 +15,16 @@ if (!Array.prototype.toSpliced) {
|
||||
};
|
||||
}
|
||||
|
||||
(function() {
|
||||
function onEachBtwn(arr, func, funcBtwn) {
|
||||
let skipped = true;
|
||||
for (const value of arr) {
|
||||
if (!skipped) {
|
||||
funcBtwn(value);
|
||||
}
|
||||
skipped = func(value);
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== Core search logic begin ====================
|
||||
// This mapping table should match the discriminants of
|
||||
// `rustdoc::formats::item_type::ItemType` type in Rust.
|
||||
@@ -50,8 +59,10 @@ const itemTypes = [
|
||||
];
|
||||
|
||||
// used for special search precedence
|
||||
const TY_PRIMITIVE = itemTypes.indexOf("primitive");
|
||||
const TY_GENERIC = itemTypes.indexOf("generic");
|
||||
const TY_IMPORT = itemTypes.indexOf("import");
|
||||
const TY_TRAIT = itemTypes.indexOf("trait");
|
||||
const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
|
||||
|
||||
// Hard limit on how deep to recurse into generics when doing type-driven search.
|
||||
@@ -1117,6 +1128,13 @@ class DocSearch {
|
||||
* @type {Map<string, {id: integer, assocOnly: boolean}>}
|
||||
*/
|
||||
this.typeNameIdMap = new Map();
|
||||
/**
|
||||
* Map from type ID to associated type name. Used for display,
|
||||
* not for search.
|
||||
*
|
||||
* @type {Map<integer, string>}
|
||||
*/
|
||||
this.assocTypeIdNameMap = new Map();
|
||||
this.ALIASES = new Map();
|
||||
this.rootPath = rootPath;
|
||||
this.searchState = searchState;
|
||||
@@ -1161,6 +1179,14 @@ class DocSearch {
|
||||
* Special type name IDs for searching higher order functions (`->` syntax).
|
||||
*/
|
||||
this.typeNameIdOfHof = this.buildTypeMapIndex("->");
|
||||
/**
|
||||
* Special type name IDs the output assoc type.
|
||||
*/
|
||||
this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true);
|
||||
/**
|
||||
* Special type name IDs for searching by reference.
|
||||
*/
|
||||
this.typeNameIdOfReference = this.buildTypeMapIndex("reference");
|
||||
|
||||
/**
|
||||
* Empty, immutable map used in item search types with no bindings.
|
||||
@@ -1237,9 +1263,9 @@ class DocSearch {
|
||||
*
|
||||
* @return {Array<FunctionSearchType>}
|
||||
*/
|
||||
buildItemSearchTypeAll(types, lowercasePaths) {
|
||||
buildItemSearchTypeAll(types, paths, lowercasePaths) {
|
||||
return types.length > 0 ?
|
||||
types.map(type => this.buildItemSearchType(type, lowercasePaths)) :
|
||||
types.map(type => this.buildItemSearchType(type, paths, lowercasePaths)) :
|
||||
this.EMPTY_GENERICS_ARRAY;
|
||||
}
|
||||
|
||||
@@ -1248,7 +1274,7 @@ class DocSearch {
|
||||
*
|
||||
* @param {RawFunctionType} type
|
||||
*/
|
||||
buildItemSearchType(type, lowercasePaths, isAssocType) {
|
||||
buildItemSearchType(type, paths, lowercasePaths, isAssocType) {
|
||||
const PATH_INDEX_DATA = 0;
|
||||
const GENERICS_DATA = 1;
|
||||
const BINDINGS_DATA = 2;
|
||||
@@ -1261,6 +1287,7 @@ class DocSearch {
|
||||
pathIndex = type[PATH_INDEX_DATA];
|
||||
generics = this.buildItemSearchTypeAll(
|
||||
type[GENERICS_DATA],
|
||||
paths,
|
||||
lowercasePaths,
|
||||
);
|
||||
if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
|
||||
@@ -1277,8 +1304,8 @@ class DocSearch {
|
||||
//
|
||||
// As a result, the key should never have generics on it.
|
||||
return [
|
||||
this.buildItemSearchType(assocType, lowercasePaths, true).id,
|
||||
this.buildItemSearchTypeAll(constraints, lowercasePaths),
|
||||
this.buildItemSearchType(assocType, paths, lowercasePaths, true).id,
|
||||
this.buildItemSearchTypeAll(constraints, paths, lowercasePaths),
|
||||
];
|
||||
}));
|
||||
} else {
|
||||
@@ -1294,6 +1321,7 @@ class DocSearch {
|
||||
// the actual names of generic parameters aren't stored, since they aren't API
|
||||
result = {
|
||||
id: pathIndex,
|
||||
name: "",
|
||||
ty: TY_GENERIC,
|
||||
path: null,
|
||||
exactPath: null,
|
||||
@@ -1304,6 +1332,7 @@ class DocSearch {
|
||||
// `0` is used as a sentinel because it's fewer bytes than `null`
|
||||
result = {
|
||||
id: null,
|
||||
name: "",
|
||||
ty: null,
|
||||
path: null,
|
||||
exactPath: null,
|
||||
@@ -1312,8 +1341,13 @@ class DocSearch {
|
||||
};
|
||||
} else {
|
||||
const item = lowercasePaths[pathIndex - 1];
|
||||
const id = this.buildTypeMapIndex(item.name, isAssocType);
|
||||
if (isAssocType) {
|
||||
this.assocTypeIdNameMap.set(id, paths[pathIndex - 1].name);
|
||||
}
|
||||
result = {
|
||||
id: this.buildTypeMapIndex(item.name, isAssocType),
|
||||
id,
|
||||
name: paths[pathIndex - 1].name,
|
||||
ty: item.ty,
|
||||
path: item.path,
|
||||
exactPath: item.exactPath,
|
||||
@@ -1355,7 +1389,7 @@ class DocSearch {
|
||||
}
|
||||
if (cr.ty === result.ty && cr.path === result.path
|
||||
&& cr.bindings === result.bindings && cr.generics === result.generics
|
||||
&& cr.ty === result.ty
|
||||
&& cr.ty === result.ty && cr.name === result.name
|
||||
) {
|
||||
return cr;
|
||||
}
|
||||
@@ -1466,11 +1500,12 @@ class DocSearch {
|
||||
* The raw function search type format is generated using serde in
|
||||
* librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
|
||||
*
|
||||
* @param {Array<{name: string, ty: number}>} paths
|
||||
* @param {Array<{name: string, ty: number}>} lowercasePaths
|
||||
*
|
||||
* @return {null|FunctionSearchType}
|
||||
*/
|
||||
const buildFunctionSearchTypeCallback = lowercasePaths => {
|
||||
const buildFunctionSearchTypeCallback = (paths, lowercasePaths) => {
|
||||
return functionSearchType => {
|
||||
if (functionSearchType === 0) {
|
||||
return null;
|
||||
@@ -1480,11 +1515,16 @@ class DocSearch {
|
||||
let inputs, output;
|
||||
if (typeof functionSearchType[INPUTS_DATA] === "number") {
|
||||
inputs = [
|
||||
this.buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths),
|
||||
this.buildItemSearchType(
|
||||
functionSearchType[INPUTS_DATA],
|
||||
paths,
|
||||
lowercasePaths,
|
||||
),
|
||||
];
|
||||
} else {
|
||||
inputs = this.buildItemSearchTypeAll(
|
||||
functionSearchType[INPUTS_DATA],
|
||||
paths,
|
||||
lowercasePaths,
|
||||
);
|
||||
}
|
||||
@@ -1493,12 +1533,14 @@ class DocSearch {
|
||||
output = [
|
||||
this.buildItemSearchType(
|
||||
functionSearchType[OUTPUT_DATA],
|
||||
paths,
|
||||
lowercasePaths,
|
||||
),
|
||||
];
|
||||
} else {
|
||||
output = this.buildItemSearchTypeAll(
|
||||
functionSearchType[OUTPUT_DATA],
|
||||
paths,
|
||||
lowercasePaths,
|
||||
);
|
||||
}
|
||||
@@ -1509,8 +1551,12 @@ class DocSearch {
|
||||
const l = functionSearchType.length;
|
||||
for (let i = 2; i < l; ++i) {
|
||||
where_clause.push(typeof functionSearchType[i] === "number"
|
||||
? [this.buildItemSearchType(functionSearchType[i], lowercasePaths)]
|
||||
: this.buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
|
||||
? [this.buildItemSearchType(functionSearchType[i], paths, lowercasePaths)]
|
||||
: this.buildItemSearchTypeAll(
|
||||
functionSearchType[i],
|
||||
paths,
|
||||
lowercasePaths,
|
||||
));
|
||||
}
|
||||
return {
|
||||
inputs, output, where_clause,
|
||||
@@ -1554,6 +1600,13 @@ class DocSearch {
|
||||
this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e));
|
||||
let descIndex = 0;
|
||||
|
||||
/**
|
||||
* List of generic function type parameter names.
|
||||
* Used for display, not for searching.
|
||||
* @type {[string]}
|
||||
*/
|
||||
let lastParamNames = [];
|
||||
|
||||
// This object should have exactly the same set of fields as the "row"
|
||||
// object defined below. Your JavaScript runtime will thank you.
|
||||
// https://mathiasbynens.be/notes/shapes-ics
|
||||
@@ -1568,6 +1621,7 @@ class DocSearch {
|
||||
desc: crateCorpus.doc,
|
||||
parent: undefined,
|
||||
type: null,
|
||||
paramNames: lastParamNames,
|
||||
id,
|
||||
word: crate,
|
||||
normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""),
|
||||
@@ -1604,6 +1658,10 @@ class DocSearch {
|
||||
// an array of [(String) alias name
|
||||
// [Number] index to items]
|
||||
const aliases = crateCorpus.a;
|
||||
// an array of [(Number) item index,
|
||||
// (String) comma-separated list of function generic param names]
|
||||
// an item whose index is not present will fall back to the previous present path
|
||||
const itemParamNames = new Map(crateCorpus.P);
|
||||
|
||||
// an array of [{name: String, ty: Number}]
|
||||
const lowercasePaths = [];
|
||||
@@ -1611,7 +1669,7 @@ class DocSearch {
|
||||
// a string representing the list of function types
|
||||
const itemFunctionDecoder = new VlqHexDecoder(
|
||||
crateCorpus.f,
|
||||
buildFunctionSearchTypeCallback(lowercasePaths),
|
||||
buildFunctionSearchTypeCallback(paths, lowercasePaths),
|
||||
);
|
||||
|
||||
// convert `rawPaths` entries into object form
|
||||
@@ -1662,6 +1720,9 @@ class DocSearch {
|
||||
const name = itemNames[i] === "" ? lastName : itemNames[i];
|
||||
const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase();
|
||||
const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
|
||||
const paramNames = itemParamNames.has(i) ?
|
||||
itemParamNames.get(i).split(",") :
|
||||
lastParamNames;
|
||||
const type = itemFunctionDecoder.next();
|
||||
if (type !== null) {
|
||||
if (type) {
|
||||
@@ -1694,6 +1755,7 @@ class DocSearch {
|
||||
itemPaths.get(itemReexports.get(i)) : path,
|
||||
parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined,
|
||||
type,
|
||||
paramNames,
|
||||
id,
|
||||
word,
|
||||
normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""),
|
||||
@@ -1704,6 +1766,7 @@ class DocSearch {
|
||||
id += 1;
|
||||
searchIndex.push(row);
|
||||
lastPath = row.path;
|
||||
lastParamNames = row.paramNames;
|
||||
if (!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
|
||||
descIndex += 1;
|
||||
}
|
||||
@@ -2048,18 +2111,21 @@ class DocSearch {
|
||||
* marked for removal.
|
||||
*
|
||||
* @param {[ResultObject]} results
|
||||
* @param {"sig"|"elems"|"returned"|null} typeInfo
|
||||
* @param {ParsedQuery} query
|
||||
* @returns {[ResultObject]}
|
||||
*/
|
||||
const transformResults = results => {
|
||||
const transformResults = (results, typeInfo) => {
|
||||
const duplicates = new Set();
|
||||
const out = [];
|
||||
|
||||
for (const result of results) {
|
||||
if (result.id !== -1) {
|
||||
const obj = this.searchIndex[result.id];
|
||||
obj.dist = result.dist;
|
||||
const res = buildHrefAndPath(obj);
|
||||
obj.displayPath = pathSplitter(res[0]);
|
||||
const res = buildHrefAndPath(this.searchIndex[result.id]);
|
||||
const obj = Object.assign({
|
||||
dist: result.dist,
|
||||
displayPath: pathSplitter(res[0]),
|
||||
}, this.searchIndex[result.id]);
|
||||
|
||||
// To be sure than it some items aren't considered as duplicate.
|
||||
obj.fullPath = res[2] + "|" + obj.ty;
|
||||
@@ -2078,6 +2144,11 @@ class DocSearch {
|
||||
duplicates.add(obj.fullPath);
|
||||
duplicates.add(res[2]);
|
||||
|
||||
if (typeInfo !== null) {
|
||||
obj.displayTypeSignature =
|
||||
this.formatDisplayTypeSignature(obj, typeInfo);
|
||||
}
|
||||
|
||||
obj.href = res[1];
|
||||
out.push(obj);
|
||||
if (out.length >= MAX_RESULTS) {
|
||||
@@ -2088,6 +2159,327 @@ class DocSearch {
|
||||
return out;
|
||||
};
|
||||
|
||||
/**
|
||||
* Add extra data to result objects, and filter items that have been
|
||||
* marked for removal.
|
||||
*
|
||||
* The output is formatted as an array of hunks, where odd numbered
|
||||
* hunks are highlighted and even numbered ones are not.
|
||||
*
|
||||
* @param {ResultObject} obj
|
||||
* @param {"sig"|"elems"|"returned"|null} typeInfo
|
||||
* @param {ParsedQuery} query
|
||||
* @returns Promise<
|
||||
* "type": Array<string>,
|
||||
* "mappedNames": Map<string, string>,
|
||||
* "whereClause": Map<string, Array<string>>,
|
||||
* >
|
||||
*/
|
||||
this.formatDisplayTypeSignature = async(obj, typeInfo) => {
|
||||
let fnInputs = null;
|
||||
let fnOutput = null;
|
||||
let mgens = null;
|
||||
if (typeInfo !== "elems" && typeInfo !== "returned") {
|
||||
fnInputs = unifyFunctionTypes(
|
||||
obj.type.inputs,
|
||||
parsedQuery.elems,
|
||||
obj.type.where_clause,
|
||||
null,
|
||||
mgensScratch => {
|
||||
fnOutput = unifyFunctionTypes(
|
||||
obj.type.output,
|
||||
parsedQuery.returned,
|
||||
obj.type.where_clause,
|
||||
mgensScratch,
|
||||
mgensOut => {
|
||||
mgens = mgensOut;
|
||||
return true;
|
||||
},
|
||||
0,
|
||||
);
|
||||
return !!fnOutput;
|
||||
},
|
||||
0,
|
||||
);
|
||||
} else {
|
||||
const arr = typeInfo === "elems" ? obj.type.inputs : obj.type.output;
|
||||
const highlighted = unifyFunctionTypes(
|
||||
arr,
|
||||
parsedQuery.elems,
|
||||
obj.type.where_clause,
|
||||
null,
|
||||
mgensOut => {
|
||||
mgens = mgensOut;
|
||||
return true;
|
||||
},
|
||||
0,
|
||||
);
|
||||
if (typeInfo === "elems") {
|
||||
fnInputs = highlighted;
|
||||
} else {
|
||||
fnOutput = highlighted;
|
||||
}
|
||||
}
|
||||
if (!fnInputs) {
|
||||
fnInputs = obj.type.inputs;
|
||||
}
|
||||
if (!fnOutput) {
|
||||
fnOutput = obj.type.output;
|
||||
}
|
||||
const mappedNames = new Map();
|
||||
const whereClause = new Map();
|
||||
|
||||
const fnParamNames = obj.paramNames;
|
||||
const queryParamNames = [];
|
||||
/**
|
||||
* Recursively writes a map of IDs to query generic names,
|
||||
* which are later used to map query generic names to function generic names.
|
||||
* For example, when the user writes `X -> Option<X>` and the function
|
||||
* is actually written as `T -> Option<T>`, this function stores the
|
||||
* mapping `(-1, "X")`, and the writeFn function looks up the entry
|
||||
* for -1 to form the final, user-visible mapping of "X is T".
|
||||
*
|
||||
* @param {QueryElement} queryElem
|
||||
*/
|
||||
const remapQuery = queryElem => {
|
||||
if (queryElem.id < 0) {
|
||||
queryParamNames[-1 - queryElem.id] = queryElem.name;
|
||||
}
|
||||
if (queryElem.generics.length > 0) {
|
||||
queryElem.generics.forEach(remapQuery);
|
||||
}
|
||||
if (queryElem.bindings.size > 0) {
|
||||
[...queryElem.bindings.values()].flat().forEach(remapQuery);
|
||||
}
|
||||
};
|
||||
|
||||
parsedQuery.elems.forEach(remapQuery);
|
||||
parsedQuery.returned.forEach(remapQuery);
|
||||
|
||||
/**
|
||||
* Write text to a highlighting array.
|
||||
* Index 0 is not highlighted, index 1 is highlighted,
|
||||
* index 2 is not highlighted, etc.
|
||||
*
|
||||
* @param {{name: string, highlighted: bool|undefined}} fnType - input
|
||||
* @param {[string]} result
|
||||
*/
|
||||
const pushText = (fnType, result) => {
|
||||
// If !!(result.length % 2) == false, then pushing a new slot starts an even
|
||||
// numbered slot. Even numbered slots are not highlighted.
|
||||
//
|
||||
// `highlighted` will not be defined if an entire subtree is not highlighted,
|
||||
// so `!!` is used to coerce it to boolean. `result.length % 2` is used to
|
||||
// check if the number is even, but it evaluates to a number, so it also
|
||||
// needs coerced to a boolean.
|
||||
if (!!(result.length % 2) === !!fnType.highlighted) {
|
||||
result.push("");
|
||||
} else if (result.length === 0 && !!fnType.highlighted) {
|
||||
result.push("");
|
||||
result.push("");
|
||||
}
|
||||
|
||||
result[result.length - 1] += fnType.name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write a higher order function type: either a function pointer
|
||||
* or a trait bound on Fn, FnMut, or FnOnce.
|
||||
*
|
||||
* @param {FunctionType} fnType - input
|
||||
* @param {[string]} result
|
||||
*/
|
||||
const writeHof = (fnType, result) => {
|
||||
const hofOutput = fnType.bindings.get(this.typeNameIdOfOutput) || [];
|
||||
const hofInputs = fnType.generics;
|
||||
pushText(fnType, result);
|
||||
pushText({name: " (", highlighted: false}, result);
|
||||
let needsComma = false;
|
||||
for (const fnType of hofInputs) {
|
||||
if (needsComma) {
|
||||
pushText({ name: ", ", highlighted: false }, result);
|
||||
}
|
||||
needsComma = true;
|
||||
writeFn(fnType, result);
|
||||
}
|
||||
pushText({
|
||||
name: hofOutput.length === 0 ? ")" : ") -> ",
|
||||
highlighted: false,
|
||||
}, result);
|
||||
if (hofOutput.length > 1) {
|
||||
pushText({name: "(", highlighted: false}, result);
|
||||
}
|
||||
needsComma = false;
|
||||
for (const fnType of hofOutput) {
|
||||
if (needsComma) {
|
||||
pushText({ name: ", ", highlighted: false }, result);
|
||||
}
|
||||
needsComma = true;
|
||||
writeFn(fnType, result);
|
||||
}
|
||||
if (hofOutput.length > 1) {
|
||||
pushText({name: ")", highlighted: false}, result);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Write a primitive type with special syntax, like `!` or `[T]`.
|
||||
* Returns `false` if the supplied type isn't special.
|
||||
*
|
||||
* @param {FunctionType} fnType
|
||||
* @param {[string]} result
|
||||
*/
|
||||
const writeSpecialPrimitive = (fnType, result) => {
|
||||
if (fnType.id === this.typeNameIdOfArray || fnType.id === this.typeNameIdOfSlice ||
|
||||
fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit) {
|
||||
const [ob, sb] =
|
||||
fnType.id === this.typeNameIdOfArray ||
|
||||
fnType.id === this.typeNameIdOfSlice ?
|
||||
["[", "]"] :
|
||||
["(", ")"];
|
||||
pushText({ name: ob, highlighted: fnType.highlighted }, result);
|
||||
onEachBtwn(
|
||||
fnType.generics,
|
||||
nested => writeFn(nested, result),
|
||||
() => pushText({ name: ", ", highlighted: false }, result),
|
||||
);
|
||||
pushText({ name: sb, highlighted: fnType.highlighted }, result);
|
||||
return true;
|
||||
} else if (fnType.id === this.typeNameIdOfReference) {
|
||||
pushText({ name: "&", highlighted: fnType.highlighted }, result);
|
||||
let prevHighlighted = false;
|
||||
onEachBtwn(
|
||||
fnType.generics,
|
||||
value => {
|
||||
prevHighlighted = value.highlighted;
|
||||
writeFn(value, result);
|
||||
},
|
||||
value => pushText({
|
||||
name: " ",
|
||||
highlighted: prevHighlighted && value.highlighted,
|
||||
}, result),
|
||||
);
|
||||
return true;
|
||||
} else if (fnType.id === this.typeNameIdOfFn) {
|
||||
writeHof(fnType, result);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
/**
|
||||
* Write a type. This function checks for special types,
|
||||
* like slices, with their own formatting. It also handles
|
||||
* updating the where clause and generic type param map.
|
||||
*
|
||||
* @param {FunctionType} fnType
|
||||
* @param {[string]} result
|
||||
*/
|
||||
const writeFn = (fnType, result) => {
|
||||
if (fnType.id < 0) {
|
||||
const queryId = mgens && mgens.has(fnType.id) ? mgens.get(fnType.id) : null;
|
||||
if (fnParamNames[-1 - fnType.id] === "") {
|
||||
for (const nested of fnType.generics) {
|
||||
writeFn(nested, result);
|
||||
}
|
||||
return;
|
||||
} else if (queryId < 0) {
|
||||
mappedNames.set(
|
||||
fnParamNames[-1 - fnType.id],
|
||||
queryParamNames[-1 - queryId],
|
||||
);
|
||||
}
|
||||
pushText({
|
||||
name: fnParamNames[-1 - fnType.id],
|
||||
highlighted: !!fnType.highlighted,
|
||||
}, result);
|
||||
const where = [];
|
||||
onEachBtwn(
|
||||
fnType.generics,
|
||||
nested => writeFn(nested, where),
|
||||
() => pushText({ name: " + ", highlighted: false }, where),
|
||||
);
|
||||
if (where.length > 0) {
|
||||
whereClause.set(fnParamNames[-1 - fnType.id], where);
|
||||
}
|
||||
} else {
|
||||
if (fnType.ty === TY_PRIMITIVE) {
|
||||
if (writeSpecialPrimitive(fnType, result)) {
|
||||
return;
|
||||
}
|
||||
} else if (fnType.ty === TY_TRAIT && (
|
||||
fnType.id === this.typeNameIdOfFn ||
|
||||
fnType.id === this.typeNameIdOfFnMut ||
|
||||
fnType.id === this.typeNameIdOfFnOnce)) {
|
||||
writeHof(fnType, result);
|
||||
return;
|
||||
}
|
||||
pushText(fnType, result);
|
||||
let hasBindings = false;
|
||||
if (fnType.bindings.size > 0) {
|
||||
onEachBtwn(
|
||||
fnType.bindings,
|
||||
([key, values]) => {
|
||||
const name = this.assocTypeIdNameMap.get(key);
|
||||
if (values.length === 1 && values[0].id < 0 &&
|
||||
`${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]) {
|
||||
// the internal `Item=Iterator::Item` type variable should be
|
||||
// shown in the where clause and name mapping output, but is
|
||||
// redundant in this spot
|
||||
for (const value of values) {
|
||||
writeFn(value, []);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!hasBindings) {
|
||||
hasBindings = true;
|
||||
pushText({ name: "<", highlighted: false }, result);
|
||||
}
|
||||
pushText({ name, highlighted: false }, result);
|
||||
pushText({
|
||||
name: values.length > 1 ? "=(" : "=",
|
||||
highlighted: false,
|
||||
}, result);
|
||||
onEachBtwn(
|
||||
values,
|
||||
value => writeFn(value, result),
|
||||
() => pushText({ name: " + ", highlighted: false }, result),
|
||||
);
|
||||
if (values.length > 1) {
|
||||
pushText({ name: ")", highlighted: false }, result);
|
||||
}
|
||||
},
|
||||
() => pushText({ name: ", ", highlighted: false }, result),
|
||||
);
|
||||
}
|
||||
if (fnType.generics.length > 0) {
|
||||
pushText({ name: hasBindings ? ", " : "<", highlighted: false }, result);
|
||||
}
|
||||
onEachBtwn(
|
||||
fnType.generics,
|
||||
value => writeFn(value, result),
|
||||
() => pushText({ name: ", ", highlighted: false }, result),
|
||||
);
|
||||
if (hasBindings || fnType.generics.length > 0) {
|
||||
pushText({ name: ">", highlighted: false }, result);
|
||||
}
|
||||
}
|
||||
};
|
||||
const type = [];
|
||||
onEachBtwn(
|
||||
fnInputs,
|
||||
fnType => writeFn(fnType, type),
|
||||
() => pushText({ name: ", ", highlighted: false }, type),
|
||||
);
|
||||
pushText({ name: " -> ", highlighted: false }, type);
|
||||
onEachBtwn(
|
||||
fnOutput,
|
||||
fnType => writeFn(fnType, type),
|
||||
() => pushText({ name: ", ", highlighted: false }, type),
|
||||
);
|
||||
|
||||
return {type, mappedNames, whereClause};
|
||||
};
|
||||
|
||||
/**
|
||||
* This function takes a result map, and sorts it by various criteria, including edit
|
||||
* distance, substring match, and the crate it comes from.
|
||||
@@ -2097,7 +2489,7 @@ class DocSearch {
|
||||
* @param {string} preferredCrate
|
||||
* @returns {Promise<[ResultObject]>}
|
||||
*/
|
||||
const sortResults = async(results, isType, preferredCrate) => {
|
||||
const sortResults = async(results, typeInfo, preferredCrate) => {
|
||||
const userQuery = parsedQuery.userQuery;
|
||||
const normalizedUserQuery = parsedQuery.userQuery.toLowerCase();
|
||||
const result_list = [];
|
||||
@@ -2207,17 +2599,17 @@ class DocSearch {
|
||||
return 0;
|
||||
});
|
||||
|
||||
return transformResults(result_list);
|
||||
return transformResults(result_list, typeInfo);
|
||||
};
|
||||
|
||||
/**
|
||||
* This function checks if a list of search query `queryElems` can all be found in the
|
||||
* search index (`fnTypes`).
|
||||
*
|
||||
* This function returns `true` on a match, or `false` if none. If `solutionCb` is
|
||||
* This function returns highlighted results on a match, or `null`. If `solutionCb` is
|
||||
* supplied, it will call that function with mgens, and that callback can accept or
|
||||
* reject the result bu returning `true` or `false`. If the callback returns false,
|
||||
* then this function will try with a different solution, or bail with false if it
|
||||
* reject the result by returning `true` or `false`. If the callback returns false,
|
||||
* then this function will try with a different solution, or bail with null if it
|
||||
* runs out of candidates.
|
||||
*
|
||||
* @param {Array<FunctionType>} fnTypesIn - The objects to check.
|
||||
@@ -2230,7 +2622,7 @@ class DocSearch {
|
||||
* - Limit checks that Ty matches Vec<Ty>,
|
||||
* but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
|
||||
*
|
||||
* @return {boolean} - Returns true if a match, false otherwise.
|
||||
* @return {[FunctionType]|null} - Returns highlighed results if a match, null otherwise.
|
||||
*/
|
||||
function unifyFunctionTypes(
|
||||
fnTypesIn,
|
||||
@@ -2241,17 +2633,17 @@ class DocSearch {
|
||||
unboxingDepth,
|
||||
) {
|
||||
if (unboxingDepth >= UNBOXING_LIMIT) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @type Map<integer, integer>|null
|
||||
*/
|
||||
const mgens = mgensIn === null ? null : new Map(mgensIn);
|
||||
if (queryElems.length === 0) {
|
||||
return !solutionCb || solutionCb(mgens);
|
||||
return (!solutionCb || solutionCb(mgens)) ? fnTypesIn : null;
|
||||
}
|
||||
if (!fnTypesIn || fnTypesIn.length === 0) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
const ql = queryElems.length;
|
||||
const fl = fnTypesIn.length;
|
||||
@@ -2260,7 +2652,7 @@ class DocSearch {
|
||||
if (ql === 1 && queryElems[0].generics.length === 0
|
||||
&& queryElems[0].bindings.size === 0) {
|
||||
const queryElem = queryElems[0];
|
||||
for (const fnType of fnTypesIn) {
|
||||
for (const [i, fnType] of fnTypesIn.entries()) {
|
||||
if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
|
||||
continue;
|
||||
}
|
||||
@@ -2272,14 +2664,33 @@ class DocSearch {
|
||||
const mgensScratch = new Map(mgens);
|
||||
mgensScratch.set(fnType.id, queryElem.id);
|
||||
if (!solutionCb || solutionCb(mgensScratch)) {
|
||||
return true;
|
||||
const highlighted = [...fnTypesIn];
|
||||
highlighted[i] = Object.assign({
|
||||
highlighted: true,
|
||||
}, fnType, {
|
||||
generics: whereClause[-1 - fnType.id],
|
||||
});
|
||||
return highlighted;
|
||||
}
|
||||
} else if (!solutionCb || solutionCb(mgens ? new Map(mgens) : null)) {
|
||||
// unifyFunctionTypeIsMatchCandidate already checks that ids match
|
||||
return true;
|
||||
const highlighted = [...fnTypesIn];
|
||||
highlighted[i] = Object.assign({
|
||||
highlighted: true,
|
||||
}, fnType, {
|
||||
generics: unifyFunctionTypes(
|
||||
fnType.generics,
|
||||
queryElem.generics,
|
||||
whereClause,
|
||||
mgens ? new Map(mgens) : null,
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
) || fnType.generics,
|
||||
});
|
||||
return highlighted;
|
||||
}
|
||||
}
|
||||
for (const fnType of fnTypesIn) {
|
||||
for (const [i, fnType] of fnTypesIn.entries()) {
|
||||
if (!unifyFunctionTypeIsUnboxCandidate(
|
||||
fnType,
|
||||
queryElem,
|
||||
@@ -2296,25 +2707,42 @@ class DocSearch {
|
||||
}
|
||||
const mgensScratch = new Map(mgens);
|
||||
mgensScratch.set(fnType.id, 0);
|
||||
if (unifyFunctionTypes(
|
||||
const highlightedGenerics = unifyFunctionTypes(
|
||||
whereClause[(-fnType.id) - 1],
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
solutionCb,
|
||||
unboxingDepth + 1,
|
||||
)) {
|
||||
return true;
|
||||
);
|
||||
if (highlightedGenerics) {
|
||||
const highlighted = [...fnTypesIn];
|
||||
highlighted[i] = Object.assign({
|
||||
highlighted: true,
|
||||
}, fnType, {
|
||||
generics: highlightedGenerics,
|
||||
});
|
||||
return highlighted;
|
||||
}
|
||||
} else {
|
||||
const highlightedGenerics = unifyFunctionTypes(
|
||||
[...Array.from(fnType.bindings.values()).flat(), ...fnType.generics],
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgens ? new Map(mgens) : null,
|
||||
solutionCb,
|
||||
unboxingDepth + 1,
|
||||
);
|
||||
if (highlightedGenerics) {
|
||||
const highlighted = [...fnTypesIn];
|
||||
highlighted[i] = Object.assign({}, fnType, {
|
||||
generics: highlightedGenerics,
|
||||
bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
|
||||
return [k, highlightedGenerics.splice(0, v.length)];
|
||||
})),
|
||||
});
|
||||
return highlighted;
|
||||
}
|
||||
} else if (unifyFunctionTypes(
|
||||
[...fnType.generics, ...Array.from(fnType.bindings.values()).flat()],
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgens ? new Map(mgens) : null,
|
||||
solutionCb,
|
||||
unboxingDepth + 1,
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -2371,6 +2799,8 @@ class DocSearch {
|
||||
if (!queryElemsTmp) {
|
||||
queryElemsTmp = queryElems.slice(0, qlast);
|
||||
}
|
||||
let unifiedGenerics = [];
|
||||
let unifiedGenericsMgens = null;
|
||||
const passesUnification = unifyFunctionTypes(
|
||||
fnTypes,
|
||||
queryElemsTmp,
|
||||
@@ -2393,7 +2823,7 @@ class DocSearch {
|
||||
}
|
||||
const simplifiedGenerics = solution.simplifiedGenerics;
|
||||
for (const simplifiedMgens of solution.mgens) {
|
||||
const passesUnification = unifyFunctionTypes(
|
||||
unifiedGenerics = unifyFunctionTypes(
|
||||
simplifiedGenerics,
|
||||
queryElem.generics,
|
||||
whereClause,
|
||||
@@ -2401,7 +2831,8 @@ class DocSearch {
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
);
|
||||
if (passesUnification) {
|
||||
if (unifiedGenerics) {
|
||||
unifiedGenericsMgens = simplifiedMgens;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2410,7 +2841,23 @@ class DocSearch {
|
||||
unboxingDepth,
|
||||
);
|
||||
if (passesUnification) {
|
||||
return true;
|
||||
passesUnification.length = fl;
|
||||
passesUnification[flast] = passesUnification[i];
|
||||
passesUnification[i] = Object.assign({}, fnType, {
|
||||
highlighted: true,
|
||||
generics: unifiedGenerics,
|
||||
bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
|
||||
return [k, queryElem.bindings.has(k) ? unifyFunctionTypes(
|
||||
v,
|
||||
queryElem.bindings.get(k),
|
||||
whereClause,
|
||||
unifiedGenericsMgens,
|
||||
solutionCb,
|
||||
unboxingDepth,
|
||||
) : unifiedGenerics.splice(0, v.length)];
|
||||
})),
|
||||
});
|
||||
return passesUnification;
|
||||
}
|
||||
// backtrack
|
||||
fnTypes[flast] = fnTypes[i];
|
||||
@@ -2445,7 +2892,7 @@ class DocSearch {
|
||||
Array.from(fnType.bindings.values()).flat() :
|
||||
[];
|
||||
const passesUnification = unifyFunctionTypes(
|
||||
fnTypes.toSpliced(i, 1, ...generics, ...bindings),
|
||||
fnTypes.toSpliced(i, 1, ...bindings, ...generics),
|
||||
queryElems,
|
||||
whereClause,
|
||||
mgensScratch,
|
||||
@@ -2453,10 +2900,24 @@ class DocSearch {
|
||||
unboxingDepth + 1,
|
||||
);
|
||||
if (passesUnification) {
|
||||
return true;
|
||||
const highlightedGenerics = passesUnification.slice(
|
||||
i,
|
||||
i + generics.length + bindings.length,
|
||||
);
|
||||
const highlightedFnType = Object.assign({}, fnType, {
|
||||
generics: highlightedGenerics,
|
||||
bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
|
||||
return [k, highlightedGenerics.splice(0, v.length)];
|
||||
})),
|
||||
});
|
||||
return passesUnification.toSpliced(
|
||||
i,
|
||||
generics.length + bindings.length,
|
||||
highlightedFnType,
|
||||
);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Check if this function is a match candidate.
|
||||
@@ -2627,7 +3088,7 @@ class DocSearch {
|
||||
}
|
||||
});
|
||||
if (simplifiedGenerics.length > 0) {
|
||||
simplifiedGenerics = [...simplifiedGenerics, ...binds];
|
||||
simplifiedGenerics = [...binds, ...simplifiedGenerics];
|
||||
} else {
|
||||
simplifiedGenerics = binds;
|
||||
}
|
||||
@@ -3285,10 +3746,11 @@ class DocSearch {
|
||||
innerRunQuery();
|
||||
}
|
||||
|
||||
const isType = parsedQuery.foundElems !== 1 || parsedQuery.hasReturnArrow;
|
||||
const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
|
||||
sortResults(results_in_args, true, currentCrate),
|
||||
sortResults(results_returned, true, currentCrate),
|
||||
sortResults(results_others, false, currentCrate),
|
||||
sortResults(results_in_args, "elems", currentCrate),
|
||||
sortResults(results_returned, "returned", currentCrate),
|
||||
sortResults(results_others, (isType ? "query" : null), currentCrate),
|
||||
]);
|
||||
const ret = createQueryResults(
|
||||
sorted_in_args,
|
||||
@@ -3315,6 +3777,7 @@ class DocSearch {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ==================== Core search logic end ====================
|
||||
|
||||
let rawSearchIndex;
|
||||
@@ -3446,15 +3909,18 @@ function focusSearchResult() {
|
||||
* @param {Array<?>} array - The search results for this tab
|
||||
* @param {ParsedQuery} query
|
||||
* @param {boolean} display - True if this is the active tab
|
||||
* @param {"sig"|"elems"|"returned"|null} typeInfo
|
||||
*/
|
||||
async function addTab(array, query, display) {
|
||||
const extraClass = display ? " active" : "";
|
||||
|
||||
const output = document.createElement("div");
|
||||
const output = document.createElement(
|
||||
array.length === 0 && query.error === null ? "div" : "ul",
|
||||
);
|
||||
if (array.length > 0) {
|
||||
output.className = "search-results " + extraClass;
|
||||
|
||||
for (const item of array) {
|
||||
const lis = Promise.all(array.map(async item => {
|
||||
const name = item.name;
|
||||
const type = itemTypes[item.ty];
|
||||
const longType = longItemTypes[item.ty];
|
||||
@@ -3464,7 +3930,7 @@ async function addTab(array, query, display) {
|
||||
link.className = "result-" + type;
|
||||
link.href = item.href;
|
||||
|
||||
const resultName = document.createElement("div");
|
||||
const resultName = document.createElement("span");
|
||||
resultName.className = "result-name";
|
||||
|
||||
resultName.insertAdjacentHTML(
|
||||
@@ -3487,10 +3953,73 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||
const description = document.createElement("div");
|
||||
description.className = "desc";
|
||||
description.insertAdjacentHTML("beforeend", item.desc);
|
||||
if (item.displayTypeSignature) {
|
||||
const {type, mappedNames, whereClause} = await item.displayTypeSignature;
|
||||
const displayType = document.createElement("div");
|
||||
type.forEach((value, index) => {
|
||||
if (index % 2 !== 0) {
|
||||
const highlight = document.createElement("strong");
|
||||
highlight.appendChild(document.createTextNode(value));
|
||||
displayType.appendChild(highlight);
|
||||
} else {
|
||||
displayType.appendChild(document.createTextNode(value));
|
||||
}
|
||||
});
|
||||
if (mappedNames.size > 0 || whereClause.size > 0) {
|
||||
let addWhereLineFn = () => {
|
||||
const line = document.createElement("div");
|
||||
line.className = "where";
|
||||
line.appendChild(document.createTextNode("where"));
|
||||
displayType.appendChild(line);
|
||||
addWhereLineFn = () => {};
|
||||
};
|
||||
for (const [name, qname] of mappedNames) {
|
||||
// don't care unless the generic name is different
|
||||
if (name === qname) {
|
||||
continue;
|
||||
}
|
||||
addWhereLineFn();
|
||||
const line = document.createElement("div");
|
||||
line.className = "where";
|
||||
line.appendChild(document.createTextNode(` ${qname} matches `));
|
||||
const lineStrong = document.createElement("strong");
|
||||
lineStrong.appendChild(document.createTextNode(name));
|
||||
line.appendChild(lineStrong);
|
||||
displayType.appendChild(line);
|
||||
}
|
||||
for (const [name, innerType] of whereClause) {
|
||||
// don't care unless there's at least one highlighted entry
|
||||
if (innerType.length <= 1) {
|
||||
continue;
|
||||
}
|
||||
addWhereLineFn();
|
||||
const line = document.createElement("div");
|
||||
line.className = "where";
|
||||
line.appendChild(document.createTextNode(` ${name}: `));
|
||||
innerType.forEach((value, index) => {
|
||||
if (index % 2 !== 0) {
|
||||
const highlight = document.createElement("strong");
|
||||
highlight.appendChild(document.createTextNode(value));
|
||||
line.appendChild(highlight);
|
||||
} else {
|
||||
line.appendChild(document.createTextNode(value));
|
||||
}
|
||||
});
|
||||
displayType.appendChild(line);
|
||||
}
|
||||
}
|
||||
displayType.className = "type-signature";
|
||||
link.appendChild(displayType);
|
||||
}
|
||||
|
||||
link.appendChild(description);
|
||||
output.appendChild(link);
|
||||
}
|
||||
return link;
|
||||
}));
|
||||
lis.then(lis => {
|
||||
for (const li of lis) {
|
||||
output.appendChild(li);
|
||||
}
|
||||
});
|
||||
} else if (query.error === null) {
|
||||
output.className = "search-failed" + extraClass;
|
||||
output.innerHTML = "No results :(<br/>" +
|
||||
@@ -3507,7 +4036,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
|
||||
"href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
|
||||
" <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
|
||||
}
|
||||
return [output, array.length];
|
||||
return output;
|
||||
}
|
||||
|
||||
function makeTabHeader(tabNb, text, nbElems) {
|
||||
@@ -3564,24 +4093,18 @@ async function showResults(results, go_to_first, filterCrates) {
|
||||
|
||||
currentResults = results.query.userQuery;
|
||||
|
||||
const [ret_others, ret_in_args, ret_returned] = await Promise.all([
|
||||
addTab(results.others, results.query, true),
|
||||
addTab(results.in_args, results.query, false),
|
||||
addTab(results.returned, results.query, false),
|
||||
]);
|
||||
|
||||
// Navigate to the relevant tab if the current tab is empty, like in case users search
|
||||
// for "-> String". If they had selected another tab previously, they have to click on
|
||||
// it again.
|
||||
let currentTab = searchState.currentTab;
|
||||
if ((currentTab === 0 && ret_others[1] === 0) ||
|
||||
(currentTab === 1 && ret_in_args[1] === 0) ||
|
||||
(currentTab === 2 && ret_returned[1] === 0)) {
|
||||
if (ret_others[1] !== 0) {
|
||||
if ((currentTab === 0 && results.others.length === 0) ||
|
||||
(currentTab === 1 && results.in_args.length === 0) ||
|
||||
(currentTab === 2 && results.returned.length === 0)) {
|
||||
if (results.others.length !== 0) {
|
||||
currentTab = 0;
|
||||
} else if (ret_in_args[1] !== 0) {
|
||||
} else if (results.in_args.length) {
|
||||
currentTab = 1;
|
||||
} else if (ret_returned[1] !== 0) {
|
||||
} else if (results.returned.length) {
|
||||
currentTab = 2;
|
||||
}
|
||||
}
|
||||
@@ -3610,14 +4133,14 @@ async function showResults(results, go_to_first, filterCrates) {
|
||||
});
|
||||
output += `<h3 class="error">Query parser error: "${error.join("")}".</h3>`;
|
||||
output += "<div id=\"search-tabs\">" +
|
||||
makeTabHeader(0, "In Names", ret_others[1]) +
|
||||
makeTabHeader(0, "In Names", results.others.length) +
|
||||
"</div>";
|
||||
currentTab = 0;
|
||||
} else if (results.query.foundElems <= 1 && results.query.returned.length === 0) {
|
||||
output += "<div id=\"search-tabs\">" +
|
||||
makeTabHeader(0, "In Names", ret_others[1]) +
|
||||
makeTabHeader(1, "In Parameters", ret_in_args[1]) +
|
||||
makeTabHeader(2, "In Return Types", ret_returned[1]) +
|
||||
makeTabHeader(0, "In Names", results.others.length) +
|
||||
makeTabHeader(1, "In Parameters", results.in_args.length) +
|
||||
makeTabHeader(2, "In Return Types", results.returned.length) +
|
||||
"</div>";
|
||||
} else {
|
||||
const signatureTabTitle =
|
||||
@@ -3625,7 +4148,7 @@ async function showResults(results, go_to_first, filterCrates) {
|
||||
results.query.returned.length === 0 ? "In Function Parameters" :
|
||||
"In Function Signatures";
|
||||
output += "<div id=\"search-tabs\">" +
|
||||
makeTabHeader(0, signatureTabTitle, ret_others[1]) +
|
||||
makeTabHeader(0, signatureTabTitle, results.others.length) +
|
||||
"</div>";
|
||||
currentTab = 0;
|
||||
}
|
||||
@@ -3647,11 +4170,17 @@ async function showResults(results, go_to_first, filterCrates) {
|
||||
`Consider searching for "${targ}" instead.</h3>`;
|
||||
}
|
||||
|
||||
const [ret_others, ret_in_args, ret_returned] = await Promise.all([
|
||||
addTab(results.others, results.query, currentTab === 0),
|
||||
addTab(results.in_args, results.query, currentTab === 1),
|
||||
addTab(results.returned, results.query, currentTab === 2),
|
||||
]);
|
||||
|
||||
const resultsElem = document.createElement("div");
|
||||
resultsElem.id = "results";
|
||||
resultsElem.appendChild(ret_others[0]);
|
||||
resultsElem.appendChild(ret_in_args[0]);
|
||||
resultsElem.appendChild(ret_returned[0]);
|
||||
resultsElem.appendChild(ret_others);
|
||||
resultsElem.appendChild(ret_in_args);
|
||||
resultsElem.appendChild(ret_returned);
|
||||
|
||||
search.innerHTML = output;
|
||||
if (searchState.rustdocToolbar) {
|
||||
@@ -3933,4 +4462,3 @@ if (typeof window !== "undefined") {
|
||||
// exports.
|
||||
initSearch(new Map());
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
|
||||
function arrayToCode(array) {
|
||||
return array.map((value, index) => {
|
||||
value = value.split(" ").join(" ");
|
||||
return (index % 2 === 1) ? ("`" + value + "`") : value;
|
||||
}).join("");
|
||||
}
|
||||
|
||||
function loadContent(content) {
|
||||
const Module = module.constructor;
|
||||
const m = new Module();
|
||||
@@ -180,15 +188,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
|
||||
if (!result_v.forEach) {
|
||||
throw result_v;
|
||||
}
|
||||
result_v.forEach((value, index) => {
|
||||
value = value.split(" ").join(" ");
|
||||
if (index % 2 === 1) {
|
||||
result_v[index] = "`" + value + "`";
|
||||
} else {
|
||||
result_v[index] = value;
|
||||
}
|
||||
});
|
||||
result_v = result_v.join("");
|
||||
result_v = arrayToCode(result_v);
|
||||
}
|
||||
const obj_path = fullPath + (fullPath.length > 0 ? "." : "") + key;
|
||||
valueCheck(obj_path, expected[key], result_v, error_text, queryName);
|
||||
@@ -436,9 +436,41 @@ function loadSearchJS(doc_folder, resource_suffix) {
|
||||
searchModule.initSearch(searchIndex.searchIndex);
|
||||
const docSearch = searchModule.docSearch;
|
||||
return {
|
||||
doSearch: function(queryStr, filterCrate, currentCrate) {
|
||||
return docSearch.execQuery(searchModule.parseQuery(queryStr),
|
||||
doSearch: async function(queryStr, filterCrate, currentCrate) {
|
||||
const result = await docSearch.execQuery(searchModule.parseQuery(queryStr),
|
||||
filterCrate, currentCrate);
|
||||
for (const tab in result) {
|
||||
if (!Object.prototype.hasOwnProperty.call(result, tab)) {
|
||||
continue;
|
||||
}
|
||||
if (!(result[tab] instanceof Array)) {
|
||||
continue;
|
||||
}
|
||||
for (const entry of result[tab]) {
|
||||
for (const key in entry) {
|
||||
if (!Object.prototype.hasOwnProperty.call(entry, key)) {
|
||||
continue;
|
||||
}
|
||||
if (key === "displayTypeSignature") {
|
||||
const {type, mappedNames, whereClause} =
|
||||
await entry.displayTypeSignature;
|
||||
entry.displayType = arrayToCode(type);
|
||||
entry.displayMappedNames = [...mappedNames.entries()]
|
||||
.map(([name, qname]) => {
|
||||
return `${name} = ${qname}`;
|
||||
}).join(", ");
|
||||
entry.displayWhereClause = [...whereClause.entries()]
|
||||
.flatMap(([name, value]) => {
|
||||
if (value.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return [`${name}: ${arrayToCode(value)}`];
|
||||
}).join(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
},
|
||||
getCorrections: function(queryStr, filterCrate, currentCrate) {
|
||||
const parsedQuery = searchModule.parseQuery(queryStr);
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Check the "About this Result" popover.
|
||||
// Try a complex result.
|
||||
go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=scroll_traits::Iterator<T>,(T->bool)->(Extend<T>,Extend<T>)"
|
||||
|
||||
// These two commands are used to be sure the search will be run.
|
||||
focus: ".search-input"
|
||||
press-key: "Enter"
|
||||
|
||||
wait-for: "#search-tabs"
|
||||
assert-count: ("#search-tabs button", 1)
|
||||
assert-count: (".search-results > a", 1)
|
||||
|
||||
assert: "//div[@class='type-signature']/strong[text()='Iterator']"
|
||||
assert: "//div[@class='type-signature']/strong[text()='(']"
|
||||
assert: "//div[@class='type-signature']/strong[text()=')']"
|
||||
|
||||
assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='FnMut']"
|
||||
assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='Iterator::Item']"
|
||||
assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='bool']"
|
||||
assert: "//div[@class='type-signature']/div[@class='where']/strong[text()='Extend']"
|
||||
|
||||
assert-text: ("div.type-signature div.where:nth-child(4)", "where")
|
||||
assert-text: ("div.type-signature div.where:nth-child(5)", " T matches Iterator::Item")
|
||||
assert-text: ("div.type-signature div.where:nth-child(6)", " F: FnMut (&Iterator::Item) -> bool")
|
||||
assert-text: ("div.type-signature div.where:nth-child(7)", " B: Default + Extend<Iterator::Item>")
|
||||
|
||||
// Try a simple result that *won't* give an info box.
|
||||
go-to: "file://" + |DOC_PATH| + "/lib2/index.html?search=F->lib2::WhereWhitespace<T>"
|
||||
|
||||
// These two commands are used to be sure the search will be run.
|
||||
focus: ".search-input"
|
||||
press-key: "Enter"
|
||||
|
||||
wait-for: "#search-tabs"
|
||||
assert-text: ("//div[@class='type-signature']", "F -> WhereWhitespace<T>")
|
||||
assert-count: ("#search-tabs button", 1)
|
||||
assert-count: (".search-results > a", 1)
|
||||
assert-count: ("//div[@class='type-signature']/div[@class='where']", 0)
|
||||
|
||||
assert: "//div[@class='type-signature']/strong[text()='F']"
|
||||
assert: "//div[@class='type-signature']/strong[text()='WhereWhitespace']"
|
||||
assert: "//div[@class='type-signature']/strong[text()='T']"
|
||||
@@ -6,79 +6,217 @@ const EXPECTED = [
|
||||
{
|
||||
'query': 'option, fnonce -> option',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'map' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'map',
|
||||
'displayType': '`Option`<T>, F -> `Option`<U>',
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> U",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, fnonce -> option',
|
||||
'others': [
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'map',
|
||||
'displayType': '`Option`<`T`>, F -> `Option`<U>',
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> U",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option -> default',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'unwrap_or_default' },
|
||||
{ 'path': 'std::option::Option', 'name': 'get_or_insert_default' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'unwrap_or_default',
|
||||
'displayType': '`Option`<T> -> `T`',
|
||||
'displayWhereClause': "T: `Default`",
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'get_or_insert_default',
|
||||
'displayType': '&mut `Option`<T> -> &mut `T`',
|
||||
'displayWhereClause': "T: `Default`",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option -> []',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'as_slice' },
|
||||
{ 'path': 'std::option::Option', 'name': 'as_mut_slice' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'as_slice',
|
||||
'displayType': '&`Option`<T> -> &`[`T`]`',
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'as_mut_slice',
|
||||
'displayType': '&mut `Option`<T> -> &mut `[`T`]`',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, option<t> -> option<t>',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'or' },
|
||||
{ 'path': 'std::option::Option', 'name': 'xor' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'or',
|
||||
'displayType': '`Option`<`T`>, `Option`<`T`> -> `Option`<`T`>',
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'xor',
|
||||
'displayType': '`Option`<`T`>, `Option`<`T`> -> `Option`<`T`>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, option<u> -> option<u>',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'and' },
|
||||
{ 'path': 'std::option::Option', 'name': 'zip' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'and',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`U`>',
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'zip',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(T, `U`)>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, option<u> -> option<t>',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'and' },
|
||||
{ 'path': 'std::option::Option', 'name': 'zip' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'and',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<`U`>',
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'zip',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(`T`, U)>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, option<u> -> option<t, u>',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'zip' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'zip',
|
||||
'displayType': '`Option`<`T`>, `Option`<`U`> -> `Option`<(`T`, `U`)>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, e -> result<t, e>',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'ok_or' },
|
||||
{ 'path': 'std::result::Result', 'name': 'transpose' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'ok_or',
|
||||
'displayType': '`Option`<`T`>, `E` -> `Result`<`T`, `E`>',
|
||||
},
|
||||
{
|
||||
'path': 'std::result::Result',
|
||||
'name': 'transpose',
|
||||
'displayType': 'Result<`Option`<`T`>, `E`> -> Option<`Result`<`T`, `E`>>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'result<option<t>, e> -> option<result<t, e>>',
|
||||
'others': [
|
||||
{ 'path': 'std::result::Result', 'name': 'transpose' },
|
||||
{
|
||||
'path': 'std::result::Result',
|
||||
'name': 'transpose',
|
||||
'displayType': '`Result`<`Option`<`T`>, `E`> -> `Option`<`Result`<`T`, `E`>>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, option<t> -> bool',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'eq' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'eq',
|
||||
'displayType': '&`Option`<`T`>, &`Option`<`T`> -> `bool`',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<option<t>> -> option<t>',
|
||||
'others': [
|
||||
{ 'path': 'std::option::Option', 'name': 'flatten' },
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'flatten',
|
||||
'displayType': '`Option`<`Option`<`T`>> -> `Option`<`T`>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>',
|
||||
'returned': [
|
||||
{ 'path': 'std::result::Result', 'name': 'ok' },
|
||||
{
|
||||
'path': 'std::result::Result',
|
||||
'name': 'ok',
|
||||
'displayType': 'Result<T, E> -> `Option`<`T`>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, (fnonce () -> u) -> option',
|
||||
'others': [
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'map',
|
||||
'displayType': '`Option`<`T`>, F -> `Option`<U>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> `U`",
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'and_then',
|
||||
'displayType': '`Option`<`T`>, F -> `Option`<U>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> Option<`U`>",
|
||||
},
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'zip_with',
|
||||
'displayType': 'Option<T>, `Option`<`U`>, F -> `Option`<R>',
|
||||
'displayMappedNames': `U = t, R = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (T, U) -> `R`",
|
||||
},
|
||||
{
|
||||
'path': 'std::task::Poll',
|
||||
'name': 'map_ok',
|
||||
'displayType': 'Poll<`Option`<Result<`T`, E>>>, F -> Poll<`Option`<Result<U, E>>>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> `U`",
|
||||
},
|
||||
{
|
||||
'path': 'std::task::Poll',
|
||||
'name': 'map_err',
|
||||
'displayType': 'Poll<`Option`<Result<`T`, E>>>, F -> Poll<`Option`<Result<T, U>>>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (E) -> `U`",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'option<t>, (fnonce () -> option<u>) -> option',
|
||||
'others': [
|
||||
{
|
||||
'path': 'std::option::Option',
|
||||
'name': 'and_then',
|
||||
'displayType': '`Option`<`T`>, F -> `Option`<U>',
|
||||
'displayMappedNames': `T = t, U = u`,
|
||||
'displayWhereClause': "F: `FnOnce` (T) -> `Option`<`U`>",
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// exact-check
|
||||
|
||||
const EXPECTED = [
|
||||
// Trait-associated types (that is, associated types with no constraints)
|
||||
// are treated like type parameters, so that you can "pattern match"
|
||||
// them. We should avoid redundant output (no `Item=MyIter::Item` stuff)
|
||||
// and should give reasonable results
|
||||
{
|
||||
'query': 'MyIter<T> -> Option<T>',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{
|
||||
'path': 'assoc_type_unbound::MyIter',
|
||||
'name': 'next',
|
||||
'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>',
|
||||
'displayMappedNames': 'MyIter::Item = T',
|
||||
'displayWhereClause': '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'MyIter<Item=T> -> Option<T>',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{
|
||||
'path': 'assoc_type_unbound::MyIter',
|
||||
'name': 'next',
|
||||
'displayType': '&mut `MyIter` -> `Option`<`MyIter::Item`>',
|
||||
'displayMappedNames': 'MyIter::Item = T',
|
||||
'displayWhereClause': '',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'MyIter<T> -> Option<Item=T>',
|
||||
'correction': null,
|
||||
'others': [],
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,4 @@
|
||||
pub trait MyIter {
|
||||
type Item;
|
||||
fn next(&mut self) -> Option<Self::Item>;
|
||||
}
|
||||
@@ -7,16 +7,40 @@ const EXPECTED = [
|
||||
'query': 'iterator<something> -> u32',
|
||||
'correction': null,
|
||||
'others': [
|
||||
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
|
||||
{ 'path': 'assoc_type', 'name': 'my_fn' },
|
||||
{
|
||||
'path': 'assoc_type::my',
|
||||
'name': 'other_fn',
|
||||
'displayType': 'X -> `u32`',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'X: `Iterator`<`Something`>',
|
||||
},
|
||||
{
|
||||
'path': 'assoc_type',
|
||||
'name': 'my_fn',
|
||||
'displayType': 'X -> `u32`',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'X: `Iterator`<Item=`Something`>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'iterator<something>',
|
||||
'correction': null,
|
||||
'in_args': [
|
||||
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
|
||||
{ 'path': 'assoc_type', 'name': 'my_fn' },
|
||||
{
|
||||
'path': 'assoc_type::my',
|
||||
'name': 'other_fn',
|
||||
'displayType': 'X -> u32',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'X: `Iterator`<`Something`>',
|
||||
},
|
||||
{
|
||||
'path': 'assoc_type',
|
||||
'name': 'my_fn',
|
||||
'displayType': 'X -> u32',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'X: `Iterator`<Item=`Something`>',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -26,8 +50,20 @@ const EXPECTED = [
|
||||
{ 'path': 'assoc_type', 'name': 'Something' },
|
||||
],
|
||||
'in_args': [
|
||||
{ 'path': 'assoc_type::my', 'name': 'other_fn' },
|
||||
{ 'path': 'assoc_type', 'name': 'my_fn' },
|
||||
{
|
||||
'path': 'assoc_type::my',
|
||||
'name': 'other_fn',
|
||||
'displayType': '`X` -> u32',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'X: Iterator<`Something`>',
|
||||
},
|
||||
{
|
||||
'path': 'assoc_type',
|
||||
'name': 'my_fn',
|
||||
'displayType': '`X` -> u32',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'X: Iterator<Item=`Something`>',
|
||||
},
|
||||
],
|
||||
},
|
||||
// if I write an explicit binding, only it shows up
|
||||
|
||||
@@ -5,10 +5,22 @@ const EXPECTED = [
|
||||
'query': 'Result<SomeTrait>',
|
||||
'correction': null,
|
||||
'in_args': [
|
||||
{ 'path': 'generics_trait', 'name': 'beta' },
|
||||
{
|
||||
'path': 'generics_trait',
|
||||
'name': 'beta',
|
||||
'displayType': '`Result`<`T`, ()> -> ()',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'T: `SomeTrait`',
|
||||
},
|
||||
],
|
||||
'returned': [
|
||||
{ 'path': 'generics_trait', 'name': 'bet' },
|
||||
{
|
||||
'path': 'generics_trait',
|
||||
'name': 'bet',
|
||||
'displayType': ' -> `Result`<`T`, ()>',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'T: `SomeTrait`',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -25,20 +37,44 @@ const EXPECTED = [
|
||||
'query': 'OtherThingxxxxxxxx',
|
||||
'correction': null,
|
||||
'in_args': [
|
||||
{ 'path': 'generics_trait', 'name': 'alpha' },
|
||||
{
|
||||
'path': 'generics_trait',
|
||||
'name': 'alpha',
|
||||
'displayType': 'Result<`T`, ()> -> ()',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'T: `OtherThingxxxxxxxx`',
|
||||
},
|
||||
],
|
||||
'returned': [
|
||||
{ 'path': 'generics_trait', 'name': 'alef' },
|
||||
{
|
||||
'path': 'generics_trait',
|
||||
'name': 'alef',
|
||||
'displayType': ' -> Result<`T`, ()>',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'T: `OtherThingxxxxxxxx`',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
'query': 'OtherThingxxxxxxxy',
|
||||
'correction': 'OtherThingxxxxxxxx',
|
||||
'in_args': [
|
||||
{ 'path': 'generics_trait', 'name': 'alpha' },
|
||||
{
|
||||
'path': 'generics_trait',
|
||||
'name': 'alpha',
|
||||
'displayType': 'Result<`T`, ()> -> ()',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'T: `OtherThingxxxxxxxx`',
|
||||
},
|
||||
],
|
||||
'returned': [
|
||||
{ 'path': 'generics_trait', 'name': 'alef' },
|
||||
{
|
||||
'path': 'generics_trait',
|
||||
'name': 'alef',
|
||||
'displayType': ' -> Result<`T`, ()>',
|
||||
'displayMappedNames': '',
|
||||
'displayWhereClause': 'T: `OtherThingxxxxxxxx`',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user