Skip to content

Commit

Permalink
feat(fs): improve readTextFile and readTextFileLines performance (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
amrbashir authored Nov 21, 2024
1 parent 5092ea5 commit ed98102
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 65 deletions.
6 changes: 6 additions & 0 deletions .changes/fs-perf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"fs": "patch"
"fs-js": "patch"
---

Improve performance of `readTextFile` and `readTextFileLines` APIs
2 changes: 1 addition & 1 deletion plugins/fs/api-iife.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 26 additions & 5 deletions plugins/fs/guest-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -770,10 +770,14 @@ async function readTextFile(
throw new TypeError('Must be a file URL.')
}

return await invoke<string>('plugin:fs|read_text_file', {
const arr = await invoke<ArrayBuffer | number[]>('plugin:fs|read_text_file', {
path: path instanceof URL ? path.toString() : path,
options
})

const bytes = arr instanceof ArrayBuffer ? arr : Uint8Array.from(arr)

return new TextDecoder().decode(bytes)
}

/**
Expand Down Expand Up @@ -804,6 +808,7 @@ async function readTextFileLines(
return await Promise.resolve({
path: pathStr,
rid: null as number | null,

async next(): Promise<IteratorResult<string>> {
if (this.rid === null) {
this.rid = await invoke<number>('plugin:fs|read_text_file_lines', {
Expand All @@ -812,19 +817,35 @@ async function readTextFileLines(
})
}

const [line, done] = await invoke<[string | null, boolean]>(
const arr = await invoke<ArrayBuffer | number[]>(
'plugin:fs|read_text_file_lines_next',
{ rid: this.rid }
)

// an iteration is over, reset rid for next iteration
if (done) this.rid = null
const bytes =
arr instanceof ArrayBuffer ? new Uint8Array(arr) : Uint8Array.from(arr)

// Rust side will never return an empty array for this command and
// ensure there is at least one elements there.
//
// This is an optimization to include whether we finished iteration or not (1 or 0)
// at the end of returned array to avoid serialization overhead of separate values.
const done = bytes[bytes.byteLength - 1] === 1

if (done) {
// a full iteration is over, reset rid for next iteration
this.rid = null
return { value: null, done }
}

const line = new TextDecoder().decode(bytes.slice(0, bytes.byteLength))

return {
value: done ? '' : line!,
value: line,
done
}
},

[Symbol.asyncIterator](): AsyncIterableIterator<string> {
return this
}
Expand Down
Loading

0 comments on commit ed98102

Please sign in to comment.