Skip to content

Commit ff486f9

Browse files
amrbashirlucasfernog
authored andcommitted
perf(fs): improve FileHandle.read performance (tauri-apps#1950)
* perf(fs): improve `FileHandle.read` performance * handle different target pointer width * improve `writeTextFile` performance * revert packageManager field * change file --------- Co-authored-by: Lucas Nogueira <[email protected]>
1 parent 91c9676 commit ff486f9

File tree

4 files changed

+104
-57
lines changed

4 files changed

+104
-57
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 the `FileHandle.read` and `writeTextFile` 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: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,25 @@ function parseFileInfo(r: UnparsedFileInfo): FileInfo {
243243
}
244244
}
245245

246+
// https://mstn.github.io/2018/06/08/fixed-size-arrays-in-typescript/
247+
type FixedSizeArray<T, N extends number> = ReadonlyArray<T> & {
248+
length: N
249+
}
250+
251+
// https://gist.github.com/zapthedingbat/38ebfbedd98396624e5b5f2ff462611d
252+
/** Converts a big-endian eight byte array to number */
253+
function fromBytes(buffer: FixedSizeArray<number, 8>): number {
254+
const bytes = new Uint8ClampedArray(buffer)
255+
const size = bytes.byteLength
256+
let x = 0
257+
for (let i = 0; i < size; i++) {
258+
const byte = bytes[i]
259+
x *= 0x100
260+
x += byte
261+
}
262+
return x
263+
}
264+
246265
/**
247266
* The Tauri abstraction for reading and writing files.
248267
*
@@ -285,12 +304,20 @@ class FileHandle extends Resource {
285304
return 0
286305
}
287306

288-
const [data, nread] = await invoke<[number[], number]>('plugin:fs|read', {
307+
const data = await invoke<ArrayBuffer | number[]>('plugin:fs|read', {
289308
rid: this.rid,
290309
len: buffer.byteLength
291310
})
292311

293-
buffer.set(data)
312+
// Rust side will never return an empty array for this command and
313+
// ensure there is at least 8 elements there.
314+
//
315+
// This is an optimization to include the number of read bytes (as bigendian bytes)
316+
// at the end of returned array to avoid serialization overhead of separate values.
317+
const nread = fromBytes(data.slice(-8) as FixedSizeArray<number, 8>)
318+
319+
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data
320+
buffer.set(bytes.slice(0, bytes.length - 8))
294321

295322
return nread === 0 ? null : nread
296323
}
@@ -1041,10 +1068,13 @@ async function writeTextFile(
10411068
throw new TypeError('Must be a file URL.')
10421069
}
10431070

1044-
await invoke('plugin:fs|write_text_file', {
1045-
path: path instanceof URL ? path.toString() : path,
1046-
data,
1047-
options
1071+
const encoder = new TextEncoder()
1072+
1073+
await invoke('plugin:fs|write_text_file', encoder.encode(data), {
1074+
headers: {
1075+
path: path instanceof URL ? path.toString() : path,
1076+
options: JSON.stringify(options)
1077+
}
10481078
})
10491079
}
10501080

0 commit comments

Comments
 (0)