From 123c49a5d8dbad7061cc3705e2153ced42616b33 Mon Sep 17 00:00:00 2001 From: Simon Gardling Date: Wed, 25 May 2022 12:24:25 -0400 Subject: [PATCH] cleanup + properly handle saving function data --- src/function_entry.rs | 11 +++++++++++ src/function_manager.rs | 23 ++++++++++++++++++++-- src/math_app.rs | 42 +++++++++++++++++------------------------ src/misc.rs | 14 +++++++------- 4 files changed, 56 insertions(+), 34 deletions(-) diff --git a/src/function_entry.rs b/src/function_entry.rs index 5cb0b26..94c7dd1 100644 --- a/src/function_entry.rs +++ b/src/function_entry.rs @@ -11,6 +11,7 @@ use parsing::{process_func_str, BackingFunction}; use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer}; use std::{ fmt::{self, Debug}, + hash::{Hash, Hasher}, intrinsics::assume, }; @@ -62,6 +63,16 @@ pub struct FunctionEntry { pub settings_opened: bool, } +impl Hash for FunctionEntry { + fn hash(&self, state: &mut H) { + self.raw_func_str.hash(state); + self.integral.hash(state); + self.nth_derviative.hash(state); + self.curr_nth.hash(state); + self.settings_opened.hash(state); + } +} + impl Serialize for FunctionEntry { fn serialize(&self, serializer: S) -> Result where diff --git a/src/function_manager.rs b/src/function_manager.rs index 697b23f..9400399 100644 --- a/src/function_manager.rs +++ b/src/function_manager.rs @@ -9,6 +9,9 @@ use serde::Deserialize; use serde::Deserializer; use serde::Serialize; use serde::Serializer; +use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; +use std::hash::Hasher; use std::ops::BitXorAssign; pub struct FunctionManager { @@ -19,7 +22,7 @@ impl Default for FunctionManager { fn default() -> Self { Self { functions: vec![( - Id::new_from_u64(11414819524356497634), // Random number here to avoid call to random + Id::new_from_u64(11414819524356497634), // Random number here to avoid call to crate::misc::random_u64() FunctionEntry::EMPTY, )], } @@ -72,7 +75,17 @@ const fn button_area_button(text: impl Into) -> Button { } impl FunctionManager { - pub fn display_entries(&mut self, ui: &mut egui::Ui) { + #[inline] + fn get_hash(&self) -> u64 { + let mut hasher = DefaultHasher::new(); + self.functions.hash(&mut hasher); + hasher.finish() + } + + /// Displays function entries alongside returning whether or not functions have been modified + pub fn display_entries(&mut self, ui: &mut egui::Ui) -> bool { + let initial_hash = self.get_hash(); + let can_remove = self.functions.len() > 1; let available_width = ui.available_width(); @@ -127,6 +140,8 @@ impl FunctionManager { if movement != Movement::Complete && let Some(hints) = function.autocomplete.hint.many() { // Doesn't need to have a number in id as there should only be 1 autocomplete popup in the entire gui + + // hashed "autocomplete_popup" const POPUP_ID: Id = Id::new_from_u64(7574801616484505465); let mut clicked = false; @@ -217,6 +232,10 @@ impl FunctionManager { if let Some(remove_i_unwrap) = remove_i { self.functions.remove(remove_i_unwrap); } + + let final_hash = self.get_hash(); + + initial_hash != final_hash } /// Create and push new empty function entry diff --git a/src/math_app.rs b/src/math_app.rs index f9e3c9d..457f862 100644 --- a/src/math_app.rs +++ b/src/math_app.rs @@ -386,7 +386,23 @@ impl MathApp { ); }); - self.functions.display_entries(ui); + if self.functions.display_entries(ui) { + #[cfg(target_arch = "wasm32")] + { + tracing::info!("Saving function data"); + let hash: crate::misc::HashBytes = unsafe { + std::mem::transmute::<&str, crate::misc::HashBytes>(build::SHORT_COMMIT) + }; + let saved_data = &crate::misc::hashed_storage_create( + hash, + bincode::serialize(&self.functions).unwrap().as_slice(), + ); + // tracing::info!("Bytes: {}", saved_data.len()); + get_localstorage() + .set_item(FUNC_NAME, saved_data) + .expect("failed to set local function storage"); + } + } // Only render if there's enough space if ui.available_height() > crate::data::FONT_SIZE { @@ -633,31 +649,7 @@ impl App for MathApp { self.last_info.1 = start.map(|a| format!("Took: {:?}", a.elapsed())); } - fn save(&mut self, _: &mut dyn eframe::Storage) { - #[cfg(target_arch = "wasm32")] - self.save_functions(); - } - - fn auto_save_interval(&self) -> std::time::Duration { std::time::Duration::from_secs(10) } - fn clear_color(&self, _visuals: &egui::Visuals) -> egui::Rgba { crate::style::STYLE.window_fill().into() } } - -impl MathApp { - #[cfg(target_arch = "wasm32")] - fn save_functions(&self) { - tracing::info!("Saving function data"); - let hash: crate::misc::HashBytes = - unsafe { std::mem::transmute::<&str, crate::misc::HashBytes>(build::SHORT_COMMIT) }; - let saved_data = &crate::misc::hashed_storage_create( - hash, - bincode::serialize(&self.functions).unwrap().as_slice(), - ); - // tracing::info!("Bytes: {}", saved_data.len()); - get_localstorage() - .set_item(FUNC_NAME, saved_data) - .expect("failed to set local function storage"); - } -} diff --git a/src/misc.rs b/src/misc.rs index 8a4ff1d..807fe51 100644 --- a/src/misc.rs +++ b/src/misc.rs @@ -1,5 +1,3 @@ -use std::intrinsics::assume; - use egui::plot::{Line, Points, Value, Values}; use getrandom::getrandom; use itertools::Itertools; @@ -163,25 +161,27 @@ pub fn hashed_storage_create(hash: HashBytes, data: &[u8]) -> String { #[allow(dead_code)] pub const fn hashed_storage_read(data: &str) -> Option<(HashBytes, &[u8])> { + // Make sure data is long enough to decode if HASH_LENGTH >= data.len() { return None; } - unsafe { - assume(!data.is_empty()); - assume(data.len() > HASH_LENGTH); - } - + // Transmute data into slice let decoded_1: &[u8] = unsafe { std::mem::transmute::<&str, &[u8]>(data) }; + // return hash and decoded data Some(( unsafe { *(decoded_1[..HASH_LENGTH].as_ptr() as *const HashBytes) }, &decoded_1[HASH_LENGTH..], )) } +/// Creates and returns random u64 pub fn random_u64() -> Result { + // Buffer of 8 `u8`s that are later merged into one u64 let mut buf = [0u8; 8]; + // Populate buffer with random values getrandom(&mut buf)?; + // Merge buffer into u64 Ok(u64::from_be_bytes(buf)) }