improve `readTextFileLines`

pull/1962/head
amrbashir 9 months ago
parent 91424276aa
commit c8b8f9ed59
No known key found for this signature in database
GPG Key ID: BBD7A47A2003FF33

File diff suppressed because one or more lines are too long

@ -796,6 +796,7 @@ async function readTextFileLines(
return await Promise.resolve({ return await Promise.resolve({
path: pathStr, path: pathStr,
rid: null as number | null, rid: null as number | null,
async next(): Promise<IteratorResult<string>> { async next(): Promise<IteratorResult<string>> {
if (this.rid === null) { if (this.rid === null) {
this.rid = await invoke<number>('plugin:fs|read_text_file_lines', { this.rid = await invoke<number>('plugin:fs|read_text_file_lines', {
@ -804,19 +805,31 @@ async function readTextFileLines(
}) })
} }
const [line, done] = await invoke<[string | null, boolean]>( const arr = await invoke<ArrayBuffer | number[]>(
'plugin:fs|read_text_file_lines_next', 'plugin:fs|read_text_file_lines_next',
{ rid: this.rid } { rid: this.rid }
) )
// an iteration is over, reset rid for next iteration const bytes =
if (done) this.rid = null arr instanceof ArrayBuffer ? new Uint8Array(arr) : Uint8Array.from(arr)
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 data = bytes.slice(0, bytes.byteLength)
const line = data.byteLength !== 0 ? new TextDecoder().decode(data) : ''
return { return {
value: done ? '' : line!, value: line,
done done
} }
}, },
[Symbol.asyncIterator](): AsyncIterableIterator<string> { [Symbol.asyncIterator](): AsyncIterableIterator<string> {
return this return this
} }

@ -15,7 +15,7 @@ use tauri::{
use std::{ use std::{
borrow::Cow, borrow::Cow,
fs::File, fs::File,
io::{BufReader, Lines, Read, Write}, io::{BufRead, BufReader, Read, Write},
path::{Path, PathBuf}, path::{Path, PathBuf},
str::FromStr, str::FromStr,
sync::Mutex, sync::Mutex,
@ -389,8 +389,6 @@ pub fn read_text_file_lines<R: Runtime>(
path: SafeFilePath, path: SafeFilePath,
options: Option<BaseOptions>, options: Option<BaseOptions>,
) -> CommandResult<ResourceId> { ) -> CommandResult<ResourceId> {
use std::io::BufRead;
let resolved_path = resolve_path( let resolved_path = resolve_path(
&webview, &webview,
&global_scope, &global_scope,
@ -406,7 +404,7 @@ pub fn read_text_file_lines<R: Runtime>(
) )
})?; })?;
let lines = BufReader::new(file).lines(); let lines = BufReader::new(file);
let rid = webview.resources_table().add(StdLinesResource::new(lines)); let rid = webview.resources_table().add(StdLinesResource::new(lines));
Ok(rid) Ok(rid)
@ -416,18 +414,34 @@ pub fn read_text_file_lines<R: Runtime>(
pub async fn read_text_file_lines_next<R: Runtime>( pub async fn read_text_file_lines_next<R: Runtime>(
webview: Webview<R>, webview: Webview<R>,
rid: ResourceId, rid: ResourceId,
) -> CommandResult<(Option<String>, bool)> { ) -> CommandResult<tauri::ipc::Response> {
let mut resource_table = webview.resources_table(); let mut resource_table = webview.resources_table();
let lines = resource_table.get::<StdLinesResource>(rid)?; let lines = resource_table.get::<StdLinesResource>(rid)?;
let ret = StdLinesResource::with_lock(&lines, |lines| { let ret = StdLinesResource::with_lock(&lines, |lines| -> CommandResult<Vec<u8>> {
lines.next().map(|a| (a.ok(), false)).unwrap_or_else(|| { let mut buf = Vec::new();
let _ = resource_table.close(rid);
(None, true) match lines.read_until(b'\n', &mut buf) {
}) Ok(0) => {
resource_table.close(rid)?;
buf.push(true as u8);
}
// retain same behavior as `BufReader::lines` and `Lines` iterator
Err(_) | Ok(_) => {
if buf.last() == Some(&b'\n') {
buf.pop();
if buf.last() == Some(&b'\r') {
buf.pop();
}
}
buf.push(false as u8);
}
}
Ok(buf)
}); });
Ok(ret) ret.map(tauri::ipc::Response::new)
} }
#[derive(Debug, Clone, Deserialize)] #[derive(Debug, Clone, Deserialize)]
@ -1012,14 +1026,14 @@ impl StdFileResource {
impl Resource for StdFileResource {} impl Resource for StdFileResource {}
struct StdLinesResource(Mutex<Lines<BufReader<File>>>); struct StdLinesResource(Mutex<BufReader<File>>);
impl StdLinesResource { impl StdLinesResource {
fn new(lines: Lines<BufReader<File>>) -> Self { fn new(lines: BufReader<File>) -> Self {
Self(Mutex::new(lines)) Self(Mutex::new(lines))
} }
fn with_lock<R, F: FnMut(&mut Lines<BufReader<File>>) -> R>(&self, mut f: F) -> R { fn with_lock<R, F: FnMut(&mut BufReader<File>) -> R>(&self, mut f: F) -> R {
let mut lines = self.0.lock().unwrap(); let mut lines = self.0.lock().unwrap();
f(&mut lines) f(&mut lines)
} }

Loading…
Cancel
Save