From 25a692aab93a4d143aede44398a479d0443d9a53 Mon Sep 17 00:00:00 2001 From: Alain Emilia Anna Zscheile Date: Mon, 30 Sep 2024 11:55:53 +0200 Subject: [PATCH] egui/file_handler: run parsing in file loader thread - also embed I/O errors with other errors --- src/bin/topola-egui/app.rs | 55 +++++++++++++++++------------ src/bin/topola-egui/file_handler.rs | 21 +++++++---- src/bin/topola-egui/menu_bar.rs | 24 ++++++++++--- src/specctra/design.rs | 3 +- 4 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/bin/topola-egui/app.rs b/src/bin/topola-egui/app.rs index 2b09140..4ae4176 100644 --- a/src/bin/topola-egui/app.rs +++ b/src/bin/topola-egui/app.rs @@ -9,8 +9,11 @@ use std::{ use unic_langid::{langid, LanguageIdentifier}; use topola::{ - autorouter::{invoker::Invoker, Autorouter}, - specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata}, + autorouter::{history::History, invoker::Invoker, Autorouter}, + specctra::{ + design::{LoadingError as SpecctraLoadingError, SpecctraDesign}, + mesadata::SpecctraMesadata, + }, stepper::Step, }; @@ -38,12 +41,12 @@ pub struct App { maybe_activity: Option, content_channel: ( - Sender>, - Receiver>, + Sender>, + Receiver>, ), history_channel: ( - Sender>, - Receiver>, + Sender>>, + Receiver>>, ), viewport: Viewport, @@ -109,13 +112,23 @@ impl App { fn update_state(&mut self) -> bool { if let Ok(data) = self.content_channel.1.try_recv() { match data { - Ok(data) => match self.load_specctra_dsn(data) { + Ok(design) => match self.load_specctra_dsn(design) { Ok(()) => {} Err(err) => { self.error_dialog.push_error("tr-module-specctra-dsn-file-loader", err); } }, - Err(err) => { + Err(SpecctraLoadingError::Parse(err)) => { + self.error_dialog.push_error( + "tr-module-specctra-dsn-file-loader", + format!( + "{}; {}", + self.translator.text("tr-error_failed-to-parse-as-specctra-dsn"), + err + ), + ); + } + Err(SpecctraLoadingError::Io(err)) => { self.error_dialog.push_error( "tr-module-specctra-dsn-file-loader", format!("{}; {}", self.translator.text("tr-error_unable-to-read-file"), err), @@ -125,18 +138,18 @@ impl App { } if let Some(invoker) = self.arc_mutex_maybe_invoker.lock().unwrap().as_mut() { - if let Ok(input) = self.history_channel.1.try_recv() { + if let Ok(data) = self.history_channel.1.try_recv() { let tr = &self.translator; - match input { - Ok(bufread) => match serde_json::from_reader(bufread) { - Ok(res) => invoker.replay(res), - Err(err) => { - self.error_dialog.push_error( - "tr-module-history-file-loader", - format!("{}; {}", tr.text("tr-error_failed-to-parse-as-history-json"), err), - ); - } - }, + match data { + Ok(Ok(data)) => { + invoker.replay(data); + } + Ok(Err(err)) => { + self.error_dialog.push_error( + "tr-module-history-file-loader", + format!("{}; {}", tr.text("tr-error_failed-to-parse-as-history-json"), err), + ); + } Err(err) => { self.error_dialog.push_error( "tr-module-history-file-loader", @@ -161,10 +174,8 @@ impl App { false } - fn load_specctra_dsn(&mut self, bufread: FileHandlerData) -> Result<(), String> { + fn load_specctra_dsn(&mut self, design: SpecctraDesign) -> Result<(), String> { let tr = &self.translator; - let design = SpecctraDesign::load(bufread) - .map_err(|err| format!("{}; {}", tr.text("tr-error_failed-to-parse-as-specctra-dsn"), err))?; let board = design.make_board(); let overlay = Overlay::new(&board) .map_err(|err| format!("{}; {}", tr.text("tr-error_unable-to-initialize-overlay"), err))?; diff --git a/src/bin/topola-egui/file_handler.rs b/src/bin/topola-egui/file_handler.rs index 9f94c50..c196875 100644 --- a/src/bin/topola-egui/file_handler.rs +++ b/src/bin/topola-egui/file_handler.rs @@ -46,19 +46,28 @@ impl io::BufRead for FileHandlerData { fhd_forward!(fn consume(&mut self, amt: usize)); } -pub async fn push_file_to_read( +#[inline] +pub async fn push_file_to_read( file_handle: &rfd::FileHandle, - sender: Sender>, -) { - let _ = sender.send(handle_text(&file_handle).await); + sender: Sender>, + callback: C, +) where + E: From, + C: FnOnce(FileHandlerData) -> Result, +{ + let _ = sender.send(handle_text(&file_handle, callback).await); } -async fn handle_text(file_handle: &rfd::FileHandle) -> std::io::Result { +async fn handle_text(file_handle: &rfd::FileHandle, callback: C) -> Result +where + E: From, + C: FnOnce(FileHandlerData) -> Result, +{ #[cfg(not(target_arch = "wasm32"))] let res = FileHandlerData::File(io::BufReader::new(std::fs::File::open(file_handle.path())?)); #[cfg(target_arch = "wasm32")] let res = FileHandlerData::Contents(io::Cursor::new(file_handle.read().await)); - Ok(res) + callback(res) } diff --git a/src/bin/topola-egui/menu_bar.rs b/src/bin/topola-egui/menu_bar.rs index e689b4d..a48ae05 100644 --- a/src/bin/topola-egui/menu_bar.rs +++ b/src/bin/topola-egui/menu_bar.rs @@ -6,11 +6,15 @@ use std::{ use topola::{ autorouter::{ command::Command, + history::History, invoker::{Invoker, InvokerError}, AutorouterOptions, }, router::RouterOptions, - specctra::{design::SpecctraDesign, mesadata::SpecctraMesadata}, + specctra::{ + design::{LoadingError as SpecctraLoadingError, SpecctraDesign}, + mesadata::SpecctraMesadata, + }, stepper::Abort, }; @@ -59,8 +63,8 @@ impl MenuBar { &mut self, ctx: &egui::Context, tr: &Translator, - content_sender: Sender>, - history_sender: Sender>, + content_sender: Sender>, + history_sender: Sender>>, arc_mutex_maybe_invoker: Arc>>>, maybe_activity: &mut Option, viewport: &mut Viewport, @@ -239,7 +243,10 @@ impl MenuBar { execute(async move { if let Some(file_handle) = task.await { - push_file_to_read(&file_handle, content_sender).await; + push_file_to_read(&file_handle, content_sender, |data| { + SpecctraDesign::load(data) + }) + .await; ctx.request_repaint(); } }); @@ -278,7 +285,14 @@ impl MenuBar { execute(async move { if let Some(file_handle) = task.await { - push_file_to_read(&file_handle, history_sender).await; + push_file_to_read(&file_handle, history_sender, |data| { + match serde_json::from_reader(data) { + Ok(history) => Ok(Ok(history)), + Err(err) if err.is_io() => Err(err.into()), + Err(err) => Ok(Err(err)), + } + }) + .await; ctx.request_repaint(); } }); diff --git a/src/specctra/design.rs b/src/specctra/design.rs index 30f14e2..8f39e8d 100644 --- a/src/specctra/design.rs +++ b/src/specctra/design.rs @@ -26,9 +26,10 @@ use crate::{ }, }; -#[derive(Error, Debug)] +pub use read::ParseErrorContext; /// Errors raised by [`SpecctraDesign::load`] +#[derive(Error, Debug)] pub enum LoadingError { /// I/O file reading error from [`std::io::Error`] #[error(transparent)]