rustdoc-search: reduce async machinery in value lookups

This commit is a mirrored change from stringdex that
makes `at()` not always return a promise, which is fine because
we can still `await` it.
This commit is contained in:
Michael Howell 2025-09-12 11:32:51 -07:00
parent a171994070
commit 43d45ef2da
3 changed files with 58 additions and 51 deletions

View file

@ -1758,12 +1758,8 @@ class DocSearch {
const l = crateNames.length;
const names = [];
for (let i = 0; i < l; ++i) {
names.push(crateNames.at(i).then(name => {
if (name === undefined) {
return "";
}
return this.utf8decoder.decode(name);
}));
const name = await crateNames.at(i);
names.push(name === undefined ? "" : this.utf8decoder.decode(name));
}
return Promise.all(names);
}

View file

@ -29,7 +29,7 @@ declare namespace stringdex {
*/
interface DataColumn {
isEmpty(id: number): boolean;
at(id: number): Promise<Uint8Array|undefined>;
at(id: number): Promise<Uint8Array>|Uint8Array|undefined;
search(name: Uint8Array|string): Promise<Trie?>;
searchLev(name: Uint8Array|string): AsyncGenerator<Trie>;
length: number,

View file

@ -2261,7 +2261,7 @@ function loadDatabase(hooks) {
this.hashes = hashes;
this.emptyset = emptyset;
this.name = name;
/** @type {{"hash": Uint8Array, "data": Promise<Uint8Array[]>?, "end": number}[]} */
/** @type {{"hash": Uint8Array, "data": Uint8Array[]?, "end": number}[]} */
this.buckets = [];
this.bucket_keys = [];
const l = counts.length;
@ -2295,65 +2295,76 @@ function loadDatabase(hooks) {
/**
* Look up a cell by row ID.
* @param {number} id
* @returns {Promise<Uint8Array|undefined>}
* @returns {Promise<Uint8Array>|Uint8Array|undefined}
*/
async at(id) {
at(id) {
if (this.emptyset.contains(id)) {
return Promise.resolve(EMPTY_UINT8);
return EMPTY_UINT8;
} else {
let idx = -1;
while (this.bucket_keys[idx + 1] <= id) {
idx += 1;
}
if (idx === -1 || idx >= this.bucket_keys.length) {
return Promise.resolve(undefined);
return undefined;
} else {
const start = this.bucket_keys[idx];
const {hash, end} = this.buckets[idx];
const bucket = this.buckets[idx];
let data = this.buckets[idx].data;
if (data === null) {
const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash(
this.name,
hash,
);
// After the `await` resolves, another task might fill
// in the data. If so, we should use that.
data = this.buckets[idx].data;
if (data !== null) {
return (await data)[id - start];
}
const dataSansEmptyset = [...dataSansEmptysetOrig];
/** @type {(Uint8Array[])|null} */
let dataWithEmptyset = null;
let pos = start;
let insertCount = 0;
while (pos < end) {
if (this.emptyset.contains(pos)) {
if (dataWithEmptyset === null) {
dataWithEmptyset = dataSansEmptyset.splice(0, insertCount);
} else if (insertCount !== 0) {
dataWithEmptyset.push(
...dataSansEmptyset.splice(0, insertCount),
);
}
insertCount = 0;
dataWithEmptyset.push(EMPTY_UINT8);
} else {
insertCount += 1;
}
pos += 1;
}
data = Promise.resolve(
dataWithEmptyset === null ?
dataSansEmptyset :
dataWithEmptyset.concat(dataSansEmptyset),
);
this.buckets[idx].data = data;
return this.atAsyncFetch(id, start, bucket);
} else {
return data[id - start];
}
return (await data)[id - start];
}
}
}
/**
* Look up a cell by row ID.
* @param {number} id
* @param {number} start
* @param {{hash: Uint8Array, data: Uint8Array[] | null, end: number}} bucket
* @returns {Promise<Uint8Array>}
*/
async atAsyncFetch(id, start, bucket) {
const {hash, end} = bucket;
const dataSansEmptysetOrig = await registry.dataLoadByNameAndHash(
this.name,
hash,
);
// After the `await` resolves, another task might fill
// in the data. If so, we should use that.
let data = bucket.data;
if (data !== null) {
return data[id - start];
}
const dataSansEmptyset = [...dataSansEmptysetOrig];
/** @type {(Uint8Array[])|null} */
let dataWithEmptyset = null;
let pos = start;
let insertCount = 0;
while (pos < end) {
if (this.emptyset.contains(pos)) {
if (dataWithEmptyset === null) {
dataWithEmptyset = dataSansEmptyset.splice(0, insertCount);
} else if (insertCount !== 0) {
dataWithEmptyset.push(
...dataSansEmptyset.splice(0, insertCount),
);
}
insertCount = 0;
dataWithEmptyset.push(EMPTY_UINT8);
} else {
insertCount += 1;
}
pos += 1;
}
data = dataWithEmptyset === null ?
dataSansEmptyset :
dataWithEmptyset.concat(dataSansEmptyset);
bucket.data = data;
return data[id - start];
}
/**
* Search by exact substring
* @param {Uint8Array|string} name