From 91ea1f786a02200e680d3378f9fbe9a3975ee2aa Mon Sep 17 00:00:00 2001 From: ergrelet Date: Sun, 22 May 2022 17:12:32 +0200 Subject: [PATCH] Properly transmit Results from the backend to the frontend This allows the frontend to act on the results, instead of 'waiting indefinitely' on error. Also compute column width on update for the line number columns in resym. --- resym/src/main.rs | 185 +++++++++++++++++++++++++------------ resym_core/src/backend.rs | 67 ++++++-------- resym_core/src/frontend.rs | 4 +- resymc/src/main.rs | 92 ++++++++++-------- 4 files changed, 205 insertions(+), 143 deletions(-) diff --git a/resym/src/main.rs b/resym/src/main.rs index c8c0fd3..9829f09 100644 --- a/resym/src/main.rs +++ b/resym/src/main.rs @@ -53,6 +53,16 @@ struct ResymApp { backend: Backend, } +#[derive(PartialEq)] +enum ResymAppMode { + /// Mode in which the application starts + Idle, + /// This mode means we're browsing a single PDB file + Browsing(String, usize, String), + /// This mode means we're comparing two PDB files for differences + Comparing(String, String, usize, Vec, String), +} + // GUI-related trait impl eframe::App for ResymApp { fn save(&mut self, storage: &mut dyn eframe::Storage) { @@ -199,7 +209,7 @@ impl<'p> ResymApp { } self.current_mode = - ResymAppMode::Browsing(String::default(), String::default()); + ResymAppMode::Browsing(String::default(), 0, String::default()); // Request a type list update if let Err(err) = self.backend.send_command(BackendCommand::UpdateTypeFilter( @@ -215,6 +225,7 @@ impl<'p> ResymApp { self.current_mode = ResymAppMode::Comparing( String::default(), String::default(), + 0, vec![], String::default(), ); @@ -234,46 +245,70 @@ impl<'p> ResymApp { } }, - FrontendCommand::UpdateReconstructedType(data) => { - let line_numbers = - (1..1 + data.lines().count()).fold(String::default(), |mut acc, e| { - let _r = writeln!(&mut acc, "{}", e); - acc - }); - self.current_mode = ResymAppMode::Browsing(line_numbers, data); + FrontendCommand::ReconstructTypeResult(type_reconstruction_result) => { + match type_reconstruction_result { + Err(err) => { + log::error!("Failed to reconstruct type: {}", err); + } + Ok(reconstructed_type) => { + let last_line_number = 1 + reconstructed_type.lines().count(); + let line_numbers = + (1..last_line_number).fold(String::default(), |mut acc, e| { + let _r = writeln!(&mut acc, "{}", e); + acc + }); + self.current_mode = ResymAppMode::Browsing( + line_numbers, + last_line_number, + reconstructed_type, + ); + } + } } - FrontendCommand::UpdateReconstructedTypeDiff(type_diff) => { - let (line_numbers_old, line_numbers_new, line_changes) = - type_diff.metadata.iter().fold( - (String::default(), String::default(), vec![]), - |(mut acc_old, mut acc_new, mut acc_changes), metadata| { - let indices = metadata.0; - - if let Some(indice) = indices.0 { - let _r = writeln!(&mut acc_old, "{}", 1 + indice); - } else { - let _r = writeln!(&mut acc_old); - } + FrontendCommand::DiffTypeResult(type_diff_result) => match type_diff_result { + Err(err) => { + log::error!("Failed to diff type: {}", err); + } + Ok(type_diff) => { + let mut last_line_number = 1; + let (line_numbers_old, line_numbers_new, line_changes) = + type_diff.metadata.iter().fold( + (String::default(), String::default(), vec![]), + |(mut acc_old, mut acc_new, mut acc_changes), metadata| { + let indices = metadata.0; + + if let Some(indice) = indices.0 { + last_line_number = + std::cmp::max(last_line_number, 1 + indice); + let _r = writeln!(&mut acc_old, "{}", 1 + indice); + } else { + let _r = writeln!(&mut acc_old); + } - if let Some(indice) = indices.1 { - let _r = writeln!(&mut acc_new, "{}", 1 + indice); - } else { - let _r = writeln!(&mut acc_new); - } + if let Some(indice) = indices.1 { + last_line_number = + std::cmp::max(last_line_number, 1 + indice); + let _r = writeln!(&mut acc_new, "{}", 1 + indice); + } else { + let _r = writeln!(&mut acc_new); + } - acc_changes.push(metadata.1); + acc_changes.push(metadata.1); - (acc_old, acc_new, acc_changes) - }, + (acc_old, acc_new, acc_changes) + }, + ); + + self.current_mode = ResymAppMode::Comparing( + line_numbers_old, + line_numbers_new, + last_line_number, + line_changes, + type_diff.data, ); - self.current_mode = ResymAppMode::Comparing( - line_numbers_old, - line_numbers_new, - line_changes, - type_diff.data, - ); - } + } + }, FrontendCommand::UpdateFilteredTypes(filtered_types) => { self.filtered_type_list = filtered_types; @@ -408,11 +443,12 @@ impl<'p> ResymApp { CodeTheme::dark() }; - let line_desc = if let ResymAppMode::Comparing(_, _, line_changes, _) = &self.current_mode { - Some(line_changes) - } else { - None - }; + let line_desc = + if let ResymAppMode::Comparing(_, _, _, line_changes, _) = &self.current_mode { + Some(line_changes) + } else { + None + }; // Layouter that'll disable wrapping and apply syntax highlighting if needed let mut layouter = |ui: &egui::Ui, string: &str, _wrap_width: f32| { @@ -431,28 +467,45 @@ impl<'p> ResymApp { egui::ScrollArea::both() .auto_shrink([false, false]) .show(ui, |ui| { - let num_colums = if self.settings.print_line_numbers { - if let ResymAppMode::Comparing(..) = self.current_mode { - // Old index + new index + code editor - 3 - } else { - // Line numbers + code editor - 2 + const LINE_NUMBER_DIGIT_WIDTH: usize = 10; + let (num_colums, min_column_width) = if self.settings.print_line_numbers { + match self.current_mode { + ResymAppMode::Comparing(_, _, last_line_number, ..) => { + // Compute the columns' sizes from the number of digits + let char_count = int_log10(last_line_number); + let line_number_width = (char_count * LINE_NUMBER_DIGIT_WIDTH) as f32; + + // Old index + new index + code editor + (3, line_number_width) + } + ResymAppMode::Browsing(_, last_line_number, _) => { + // Compute the columns' sizes from the number of digits + let char_count = int_log10(last_line_number); + let line_number_width = (char_count * LINE_NUMBER_DIGIT_WIDTH) as f32; + + // Line numbers + code editor + (2, line_number_width) + } + _ => { + // Code editor only + (1, 0.0) + } } } else { // Code editor only - 1 + (1, 0.0) }; - const LINE_NUMBER_WIDTH: f32 = 40.0; + egui::Grid::new("code_editor_grid") .num_columns(num_colums) - .min_col_width(LINE_NUMBER_WIDTH) + .min_col_width(min_column_width) .show(ui, |ui| { match &self.current_mode { ResymAppMode::Comparing( line_numbers_old, line_numbers_new, _, + _, reconstructed_type_diff, ) => { // Line numbers @@ -460,12 +513,12 @@ impl<'p> ResymApp { ui.add( egui::TextEdit::multiline(&mut line_numbers_old.as_str()) .interactive(false) - .desired_width(LINE_NUMBER_WIDTH), + .desired_width(min_column_width), ); ui.add( egui::TextEdit::multiline(&mut line_numbers_new.as_str()) .interactive(false) - .desired_width(LINE_NUMBER_WIDTH), + .desired_width(min_column_width), ); } // Text content @@ -477,13 +530,13 @@ impl<'p> ResymApp { .layouter(&mut layouter), ); } - ResymAppMode::Browsing(line_numbers, reconstructed_type_content) => { + ResymAppMode::Browsing(line_numbers, _, reconstructed_type_content) => { // Line numbers if self.settings.print_line_numbers { ui.add( egui::TextEdit::multiline(&mut line_numbers.as_str()) .interactive(false) - .desired_width(LINE_NUMBER_WIDTH), + .desired_width(min_column_width), ); } // Text content @@ -582,9 +635,23 @@ impl Default for ResymAppSettings { } } -#[derive(PartialEq)] -enum ResymAppMode { - Idle, - Browsing(String, String), - Comparing(String, String, Vec, String), +// FIXME: Replace with `checked_log10` once it's stabilized. +fn int_log10(mut i: T) -> usize +where + T: std::ops::DivAssign + std::cmp::PartialOrd + From + Copy, +{ + let zero = T::from(0); + if i == zero { + return 1; + } + + let mut len = 0; + let ten = T::from(10); + + while i > zero { + i /= ten; + len += 1; + } + + len } diff --git a/resym_core/src/backend.rs b/resym_core/src/backend.rs index 0cf604c..8afd348 100644 --- a/resym_core/src/backend.rs +++ b/resym_core/src/backend.rs @@ -119,15 +119,15 @@ fn worker_thread_routine( print_access_specifiers, ) => { if let Some(pdb_file) = pdb_files.get(&pdb_slot) { - let reconstructed_type = reconstruct_type_by_index_command( + let reconstructed_type_result = reconstruct_type_by_index_command( pdb_file, type_index, print_header, reconstruct_dependencies, print_access_specifiers, ); - frontend_controller.send_command(FrontendCommand::UpdateReconstructedType( - reconstructed_type, + frontend_controller.send_command(FrontendCommand::ReconstructTypeResult( + reconstructed_type_result, ))?; } } @@ -140,15 +140,15 @@ fn worker_thread_routine( print_access_specifiers, ) => { if let Some(pdb_file) = pdb_files.get(&pdb_slot) { - let reconstructed_type = reconstruct_type_by_name_command( + let reconstructed_type_result = reconstruct_type_by_name_command( pdb_file, &type_name, print_header, reconstruct_dependencies, print_access_specifiers, ); - frontend_controller.send_command(FrontendCommand::UpdateReconstructedType( - reconstructed_type, + frontend_controller.send_command(FrontendCommand::ReconstructTypeResult( + reconstructed_type_result, ))?; } } @@ -211,17 +211,16 @@ fn worker_thread_routine( ) => { if let Some(pdb_file_from) = pdb_files.get(&pdb_from_slot) { if let Some(pdb_file_to) = pdb_files.get(&pdb_to_slot) { - let type_diff = diff_type_by_name( + let type_diff_result = diff_type_by_name( pdb_file_from, pdb_file_to, &type_name, print_header, reconstruct_dependencies, print_access_specifiers, - )?; - frontend_controller.send_command( - FrontendCommand::UpdateReconstructedTypeDiff(type_diff), - )?; + ); + frontend_controller + .send_command(FrontendCommand::DiffTypeResult(type_diff_result))?; } } } @@ -237,24 +236,17 @@ fn reconstruct_type_by_index_command( print_header: bool, reconstruct_dependencies: bool, print_access_specifiers: bool, -) -> String { - match pdb_file.reconstruct_type_by_type_index( +) -> Result { + let data = pdb_file.reconstruct_type_by_type_index( type_index, reconstruct_dependencies, print_access_specifiers, - ) { - Err(err) => { - // Make it obvious an error occured - format!("Error: {}", err) - } - Ok(data) => { - if print_header { - let file_header = generate_file_header(pdb_file, true); - format!("{}{}", file_header, data) - } else { - data - } - } + )?; + if print_header { + let file_header = generate_file_header(pdb_file, true); + Ok(format!("{}{}", file_header, data)) + } else { + Ok(data) } } @@ -264,24 +256,17 @@ fn reconstruct_type_by_name_command( print_header: bool, reconstruct_dependencies: bool, print_access_specifiers: bool, -) -> String { - match pdb_file.reconstruct_type_by_name( +) -> Result { + let data = pdb_file.reconstruct_type_by_name( type_name, reconstruct_dependencies, print_access_specifiers, - ) { - Err(err) => { - // Make it obvious an error occured - format!("Error: {}", err) - } - Ok(data) => { - if print_header { - let file_header = generate_file_header(pdb_file, true); - format!("{}{}", file_header, data) - } else { - data - } - } + )?; + if print_header { + let file_header = generate_file_header(pdb_file, true); + Ok(format!("{}{}", file_header, data)) + } else { + Ok(data) } } diff --git a/resym_core/src/frontend.rs b/resym_core/src/frontend.rs index 73ac4d4..3612849 100644 --- a/resym_core/src/frontend.rs +++ b/resym_core/src/frontend.rs @@ -7,8 +7,8 @@ pub type TypeList = Vec<(String, pdb::TypeIndex)>; pub enum FrontendCommand { LoadPDBResult(Result), UpdateFilteredTypes(TypeList), - UpdateReconstructedType(String), - UpdateReconstructedTypeDiff(DiffedType), + ReconstructTypeResult(Result), + DiffTypeResult(Result), } pub trait FrontendController { diff --git a/resymc/src/main.rs b/resymc/src/main.rs index 312bde4..02b7744 100644 --- a/resymc/src/main.rs +++ b/resymc/src/main.rs @@ -247,25 +247,30 @@ impl ResymcApp { print_access_specifiers, ))?; // Wait for the backend to finish filtering types - if let FrontendCommand::UpdateReconstructedType(reconstructed_type) = + if let FrontendCommand::ReconstructTypeResult(reconstructed_type_result) = self.frontend_controller.rx_ui.recv()? { - // Dump output - if let Some(output_file_path) = output_file_path { - let mut output_file = File::create(output_file_path)?; - output_file.write_all(reconstructed_type.as_bytes())?; - } else if highlight_syntax { - const LANGUAGE_SYNTAX: &str = "cpp"; - let theme = CodeTheme::dark(); - if let Some(colorized_reconstructed_type) = - highlight_code(&theme, &reconstructed_type, LANGUAGE_SYNTAX, None) - { - println!("{}", colorized_reconstructed_type); + match reconstructed_type_result { + Err(err) => Err(err), + Ok(reconstructed_type) => { + // Dump output + if let Some(output_file_path) = output_file_path { + let mut output_file = File::create(output_file_path)?; + output_file.write_all(reconstructed_type.as_bytes())?; + } else if highlight_syntax { + const LANGUAGE_SYNTAX: &str = "cpp"; + let theme = CodeTheme::dark(); + if let Some(colorized_reconstructed_type) = + highlight_code(&theme, &reconstructed_type, LANGUAGE_SYNTAX, None) + { + println!("{}", colorized_reconstructed_type); + } + } else { + println!("{}", reconstructed_type); + } + Ok(()) } - } else { - println!("{}", reconstructed_type); } - Ok(()) } else { Err(anyhow!("Invalid response received from the backend?")) } @@ -329,36 +334,41 @@ impl ResymcApp { print_access_specifiers, ))?; // Wait for the backend to finish - if let FrontendCommand::UpdateReconstructedTypeDiff(reconstructed_type_diff) = + if let FrontendCommand::DiffTypeResult(reconstructed_type_diff_result) = self.frontend_controller.rx_ui.recv()? { - // Dump output - if let Some(output_file_path) = output_file_path { - let mut output_file = File::create(output_file_path)?; - output_file.write_all(reconstructed_type_diff.data.as_bytes())?; - } else if highlight_syntax { - const LANGUAGE_SYNTAX: &str = "cpp"; - let theme = CodeTheme::dark(); - let line_descriptions = - reconstructed_type_diff - .metadata - .iter() - .fold(vec![], |mut acc, e| { - acc.push(e.1); - acc - }); - if let Some(colorized_reconstructed_type) = highlight_code( - &theme, - &reconstructed_type_diff.data, - LANGUAGE_SYNTAX, - Some(line_descriptions), - ) { - println!("{}", colorized_reconstructed_type); + match reconstructed_type_diff_result { + Err(err) => Err(err), + Ok(reconstructed_type_diff) => { + // Dump output + if let Some(output_file_path) = output_file_path { + let mut output_file = File::create(output_file_path)?; + output_file.write_all(reconstructed_type_diff.data.as_bytes())?; + } else if highlight_syntax { + const LANGUAGE_SYNTAX: &str = "cpp"; + let theme = CodeTheme::dark(); + let line_descriptions = + reconstructed_type_diff + .metadata + .iter() + .fold(vec![], |mut acc, e| { + acc.push(e.1); + acc + }); + if let Some(colorized_reconstructed_type) = highlight_code( + &theme, + &reconstructed_type_diff.data, + LANGUAGE_SYNTAX, + Some(line_descriptions), + ) { + println!("{}", colorized_reconstructed_type); + } + } else { + println!("{}", reconstructed_type_diff.data); + } + Ok(()) } - } else { - println!("{}", reconstructed_type_diff.data); } - Ok(()) } else { Err(anyhow!("Invalid response received from the backend?")) }