Skip to content

Commit ed98102

Browse files
authored
feat(fs): improve readTextFile and readTextFileLines performance (tauri-apps#1962)
1 parent 5092ea5 commit ed98102

File tree

4 files changed

+116
-65
lines changed

4 files changed

+116
-65
lines changed

.changes/fs-perf.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"fs": "patch"
3+
"fs-js": "patch"
4+
---
5+
6+
Improve performance of `readTextFile` and `readTextFileLines` APIs

plugins/fs/api-iife.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/fs/guest-js/index.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -770,10 +770,14 @@ async function readTextFile(
770770
throw new TypeError('Must be a file URL.')
771771
}
772772

773-
return await invoke<string>('plugin:fs|read_text_file', {
773+
const arr = await invoke<ArrayBuffer | number[]>('plugin:fs|read_text_file', {
774774
path: path instanceof URL ? path.toString() : path,
775775
options
776776
})
777+
778+
const bytes = arr instanceof ArrayBuffer ? arr : Uint8Array.from(arr)
779+
780+
return new TextDecoder().decode(bytes)
777781
}
778782

779783
/**
@@ -804,6 +808,7 @@ async function readTextFileLines(
804808
return await Promise.resolve({
805809
path: pathStr,
806810
rid: null as number | null,
811+
807812
async next(): Promise<IteratorResult<string>> {
808813
if (this.rid === null) {
809814
this.rid = await invoke<number>('plugin:fs|read_text_file_lines', {
@@ -812,19 +817,35 @@ async function readTextFileLines(
812817
})
813818
}
814819

815-
const [line, done] = await invoke<[string | null, boolean]>(
820+
const arr = await invoke<ArrayBuffer | number[]>(
816821
'plugin:fs|read_text_file_lines_next',
817822
{ rid: this.rid }
818823
)
819824

820-
// an iteration is over, reset rid for next iteration
821-
if (done) this.rid = null
825+
const bytes =
826+
arr instanceof ArrayBuffer ? new Uint8Array(arr) : Uint8Array.from(arr)
827+
828+
// Rust side will never return an empty array for this command and
829+
// ensure there is at least one elements there.
830+
//
831+
// This is an optimization to include whether we finished iteration or not (1 or 0)
832+
// at the end of returned array to avoid serialization overhead of separate values.
833+
const done = bytes[bytes.byteLength - 1] === 1
834+
835+
if (done) {
836+
// a full iteration is over, reset rid for next iteration
837+
this.rid = null
838+
return { value: null, done }
839+
}
840+
841+
const line = new TextDecoder().decode(bytes.slice(0, bytes.byteLength))
822842

823843
return {
824-
value: done ? '' : line!,
844+
value: line,
825845
done
826846
}
827847
},
848+
828849
[Symbol.asyncIterator](): AsyncIterableIterator<string> {
829850
return this
830851
}

0 commit comments

Comments
 (0)