From f916de75240e9b8c1cb35f62eb871c1738404fcf Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Thu, 12 May 2022 20:03:53 -0400 Subject: [PATCH] improvements General code improvements and optimizations. --- Cargo.lock | 6 ----- Cargo.toml | 3 +-- parsing/src/lib.rs | 4 ++-- parsing/src/parsing.rs | 3 ++- parsing/src/suggestions.rs | 4 ++-- src/function_entry.rs | 49 +++++++++++++++++++++----------------- src/function_manager.rs | 6 ++--- src/math_app.rs | 25 +++++++++---------- src/misc.rs | 20 +++++++++++++--- src/widgets.rs | 4 +++- tests/misc.rs | 2 +- tests/parsing.rs | 28 +++++++++++++++++++--- 12 files changed, 94 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d30e2b..78e7471 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,11 +143,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.20.0-alpha.1" -source = "git+https://github.com/marshallpierce/rust-base64.git#a675443d327e175f735a37f574de803d6a332591" - [[package]] name = "benchmarks" version = "0.1.0" @@ -2780,7 +2775,6 @@ name = "ytbn_graphing_software" version = "0.1.0" dependencies = [ "async-lock", - "base64", "benchmarks", "bincode", "byte-unit", diff --git a/Cargo.toml b/Cargo.toml index 63d692b..e0be4c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ panic = "abort" debug = true codegen-units = 8 opt-level = 0 -lto = "thin" +lto = false strip = false [profile.bench] @@ -56,7 +56,6 @@ static_assertions = "1.1" uuid = { version = "1", features = ["v4", "fast-rng", "js"] } bincode = "1.3" serde = "1" -base64 = { git = "https://github.com/marshallpierce/rust-base64.git" } byte-unit = { version = "4", default-features = false } [dev-dependencies] diff --git a/parsing/src/lib.rs b/parsing/src/lib.rs index e1af03c..d298b3b 100644 --- a/parsing/src/lib.rs +++ b/parsing/src/lib.rs @@ -13,7 +13,7 @@ pub use crate::{ autocomplete_hashmap::compile_hashmap, parsing::{process_func_str, BackingFunction}, suggestions::{ - generate_hint, get_last_term, split_function, split_function_chars, Hint, HINT_EMPTY, - SUPPORTED_FUNCTIONS, + generate_hint, get_last_term, split_function, split_function_chars, Hint, SplitType, + HINT_EMPTY, SUPPORTED_FUNCTIONS, }, }; diff --git a/parsing/src/parsing.rs b/parsing/src/parsing.rs index e1abff8..f16a5f7 100644 --- a/parsing/src/parsing.rs +++ b/parsing/src/parsing.rs @@ -191,5 +191,6 @@ pub fn process_func_str(function_in: &str) -> String { return String::new(); } - crate::suggestions::split_function(&function_in).join("*") + crate::suggestions::split_function(&function_in, crate::suggestions::SplitType::Multiplication) + .join("*") } diff --git a/parsing/src/suggestions.rs b/parsing/src/suggestions.rs index 15be53e..673f890 100644 --- a/parsing/src/suggestions.rs +++ b/parsing/src/suggestions.rs @@ -14,7 +14,7 @@ macro_rules! test_print { }; } -pub fn split_function(input: &str) -> Vec { +pub fn split_function(input: &str, split: SplitType) -> Vec { split_function_chars( &input .replace("pi", "π") // replace "pi" text with pi symbol @@ -22,7 +22,7 @@ pub fn split_function(input: &str) -> Vec { .replace("exp", "\u{1fc93}") // stop-gap solution to fix the `exp` function .chars() .collect::>(), - SplitType::Multiplication, + split, ) .iter() .map(|x| x.replace("\u{1fc93}", "exp")) // Convert back to `exp` text diff --git a/src/function_entry.rs b/src/function_entry.rs index 64d3dac..3e9f63e 100644 --- a/src/function_entry.rs +++ b/src/function_entry.rs @@ -143,6 +143,8 @@ impl FunctionEntry { settings_opened: false, }; + pub const fn is_some(&self) -> bool { !self.function.is_none() } + pub fn settings_window(&mut self, ctx: &Context) { let mut invalidate_nth = false; egui::Window::new(format!("Settings: {}", self.raw_func_str)) @@ -310,34 +312,37 @@ impl FunctionEntry { .as_slice() .into(); - let back_data: Vec = dyn_iter(&resolution_iter) - .map(|x| { - if let Some(i) = x_data.get_index(x) { - self.back_data[i] - } else { - Value::new(*x, self.function.get(*x)) - } - }) - .collect(); + let (back_data, derivative_data_1): (Vec, Vec>) = + dyn_iter(&resolution_iter) + .map(|x| { + if let Some(i) = x_data.get_index(x) { + ( + self.back_data[i], + derivative_required.then(|| self.derivative_data[i]), + ) + } else { + ( + Value::new(*x, self.function.get(*x)), + derivative_required + .then(|| Value::new(*x, self.function.get_derivative_1(*x))), + ) + } + }) + .collect::)>>() + .into_iter() + .unzip(); debug_assert_eq!(back_data.len(), settings.plot_width + 1); + debug_assert_eq!(derivative_data_1.len(), settings.plot_width + 1); self.back_data = back_data; if derivative_required { - let new_derivative_data: Vec = dyn_iter(&resolution_iter) - .map(|x| { - if let Some(i) = x_data.get_index(x) { - self.derivative_data[i] - } else { - Value::new(*x, self.function.get_derivative_1(*x)) - } - }) - .collect(); - - debug_assert_eq!(new_derivative_data.len(), settings.plot_width + 1); - - self.derivative_data = new_derivative_data; + debug_assert!(derivative_data_1[0].is_some()); + self.derivative_data = derivative_data_1 + .into_iter() + .map(|ele| unsafe { ele.unwrap_unchecked() }) + .collect::>(); } else { self.invalidate_derivative(); } diff --git a/src/function_manager.rs b/src/function_manager.rs index 87ea8ff..f22ba7c 100644 --- a/src/function_manager.rs +++ b/src/function_manager.rs @@ -196,7 +196,7 @@ impl FunctionManager { // Toggle integral being enabled or not function.integral.bitxor_assign( - ui.add(button_area_button("∫")) + ui.add_enabled(function.is_some(), button_area_button("∫")) .on_hover_text(match function.integral { true => "Don't integrate", false => "Integrate", @@ -206,7 +206,7 @@ impl FunctionManager { // Toggle showing the derivative (even though it's already calculated this option just toggles if it's displayed or not) function.derivative.bitxor_assign( - ui.add(button_area_button("d/dx")) + ui.add_enabled(function.is_some(), button_area_button("d/dx")) .on_hover_text(match function.derivative { true => "Don't Differentiate", false => "Differentiate", @@ -215,7 +215,7 @@ impl FunctionManager { ); function.settings_opened.bitxor_assign( - ui.add(button_area_button("⚙")) + ui.add_enabled(function.is_some(), button_area_button("⚙")) .on_hover_text(match function.settings_opened { true => "Close Settings", false => "Open Settings", diff --git a/src/math_app.rs b/src/math_app.rs index 63c73aa..15b8f16 100644 --- a/src/math_app.rs +++ b/src/math_app.rs @@ -148,26 +148,23 @@ impl MathApp { const DATA_NAME: &str = "YTBN-DECOMPRESSED"; fn get_storage_decompressed() -> Option> { - if let Ok(Some(data)) = get_localstorage().get_item(DATA_NAME) { - let (commit, cached_data) = crate::misc::hashed_storage_read(data); + let data = get_localstorage().get_item(DATA_NAME).ok()??; + let (commit, cached_data) = crate::misc::hashed_storage_read(data); - if commit == build::SHORT_COMMIT { - tracing::info!("Reading decompression cache. Bytes: {}, or: {}", cached_data.len(), crate::misc::format_bytes(cached_data.len())); - return Some(cached_data.to_vec()); - } else { - tracing::info!("Decompression cache are invalid due to differing commits (build: {}, previous: {})", build::SHORT_COMMIT, commit); - - // is invalid - None - } + if commit == build::SHORT_COMMIT { + tracing::info!("Reading decompression cache. Bytes: {}, or: {}", cached_data.len(), crate::misc::format_bytes(cached_data.len())); + return Some(cached_data.to_vec()); } else { + tracing::info!("Decompression cache are invalid (build: {}, previous: {})", build::SHORT_COMMIT, commit); + + // is invalid None } } - fn set_storage_decompressed(data: &Vec) { + fn set_storage_decompressed(data: &[u8]) { tracing::info!("Setting decompression cache"); - let saved_data = &crate::misc::hashed_storage_create(&build::SHORT_COMMIT.chars().map(|c| c as u8).collect::>(), data.as_slice()); + let saved_data = &crate::misc::hashed_storage_create(&build::SHORT_COMMIT.as_bytes(), data); tracing::info!("Bytes: {}, or: {}", saved_data.len(), crate::misc::format_bytes(data.len())); get_localstorage().set_item(DATA_NAME, saved_data).expect("failed to set local storage cache"); } @@ -610,7 +607,7 @@ impl App for MathApp { .collect::>(), bincode::serialize(&self.functions).unwrap().as_slice(), ); - tracing::info!("Bytes: {}", saved_data.len()); + // tracing::info!("Bytes: {}", saved_data.len()); local_storage .set_item("YTBN-FUNCTIONS", saved_data) .expect("failed to set local function storage"); diff --git a/src/misc.rs b/src/misc.rs index 3256e98..ebc04cf 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -298,15 +298,29 @@ pub fn hashed_storage_create(hash: &[u8], data: &[u8]) -> String { debug_assert_eq!(hash.len(), HASH_LENGTH); debug_assert!(data.len() > 0); + unsafe { + assume(data.len() > 0); + assume(!data.is_empty()); + assume(hash.len() == HASH_LENGTH); + } + let new_data = [hash, data].concat(); debug_assert_eq!(new_data.len(), data.len() + hash.len()); - base64::encode(new_data) + + // cannot use `from_utf8` seems to break on wasm. no clue why + new_data.iter().map(|b| *b as char).collect::() } #[allow(dead_code)] pub fn hashed_storage_read(data: String) -> (String, Vec) { - let decoded_1 = base64::decode(data).expect("unable to read data"); - debug_assert!(decoded_1.len() > HASH_LENGTH); + debug_assert!(data.len() > HASH_LENGTH); + unsafe { + assume(!data.is_empty()); + assume(data.len() > 0); + } + + // can't use data.as_bytes() here for some reason, seems to break on wasm? + let decoded_1 = data.chars().map(|c| c as u8).collect::>(); let (hash, cached_data) = decoded_1.split_at(8); debug_assert_eq!(hash.len(), HASH_LENGTH); diff --git a/src/widgets.rs b/src/widgets.rs index 809e702..5df6919 100644 --- a/src/widgets.rs +++ b/src/widgets.rs @@ -1,5 +1,7 @@ +use std::hash::Hash; + pub fn widgets_ontop( - ui: &egui::Ui, id: String, re: &egui::Response, y_offset: f32, + ui: &egui::Ui, id: impl Hash, re: &egui::Response, y_offset: f32, add_contents: impl FnOnce(&mut egui::Ui) -> R, ) -> R { let area = egui::Area::new(id) diff --git a/tests/misc.rs b/tests/misc.rs index 337aebf..8c3eabd 100644 --- a/tests/misc.rs +++ b/tests/misc.rs @@ -95,7 +95,7 @@ fn option_vec_printer() { } #[test] -fn hash_b64_storage() { +fn hashed_storage() { use ytbn_graphing_software::{hashed_storage_create, hashed_storage_read}; let commit = "abcdefeg".chars().map(|c| c as u8).collect::>(); diff --git a/tests/parsing.rs b/tests/parsing.rs index f5f80c1..7207369 100644 --- a/tests/parsing.rs +++ b/tests/parsing.rs @@ -159,6 +159,8 @@ fn hint_to_string() { #[test] fn invalid_function() { + use parsing::SplitType; + SUPPORTED_FUNCTIONS .iter() .flat_map(|func1| { @@ -169,7 +171,7 @@ fn invalid_function() { }) .filter(|func| !SUPPORTED_FUNCTIONS.contains(&func.as_str())) .for_each(|key| { - let split = parsing::split_function(&key); + let split = parsing::split_function(&key, SplitType::Multiplication); if split.len() != 1 { panic!("failed: {} (len: {}, split: {:?})", key, split.len(), split); @@ -185,7 +187,9 @@ fn invalid_function() { } #[test] -fn split_function() { +fn split_function_multiplication() { + use parsing::SplitType; + let values = HashMap::from([ ("cos(x)", vec!["cos(x)"]), ("cos(", vec!["cos("]), @@ -199,10 +203,28 @@ fn split_function() { ("x*x", vec!["x", "x"]), ("10*10", vec!["10", "10"]), ("a1b2c3d4", vec!["a1b2c3d4"]), + ("cos(sin(x)cos(x))", vec!["cos(sin(x)", "cos(x))"]), ]); for (key, value) in values { - assert_eq!(parsing::split_function(key), value); + assert_eq!( + parsing::split_function(key, SplitType::Multiplication), + value + ); + } +} + +#[test] +fn split_function_terms() { + use parsing::SplitType; + + let values = HashMap::from([( + "cos(sin(x)cos(x))", + vec!["cos(", "sin(", "x)", "cos(", "x))"], + )]); + + for (key, value) in values { + assert_eq!(parsing::split_function(key, SplitType::Term), value); } }