cleanup + properly handle saving function data
This commit is contained in:
parent
24526d138d
commit
123c49a5d8
@ -11,6 +11,7 @@ use parsing::{process_func_str, BackingFunction};
|
|||||||
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Debug},
|
fmt::{self, Debug},
|
||||||
|
hash::{Hash, Hasher},
|
||||||
intrinsics::assume,
|
intrinsics::assume,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,6 +63,16 @@ pub struct FunctionEntry {
|
|||||||
pub settings_opened: bool,
|
pub settings_opened: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Hash for FunctionEntry {
|
||||||
|
fn hash<H: Hasher>(&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 {
|
impl Serialize for FunctionEntry {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
|
|||||||
@ -9,6 +9,9 @@ use serde::Deserialize;
|
|||||||
use serde::Deserializer;
|
use serde::Deserializer;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::Serializer;
|
use serde::Serializer;
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::hash::Hasher;
|
||||||
use std::ops::BitXorAssign;
|
use std::ops::BitXorAssign;
|
||||||
|
|
||||||
pub struct FunctionManager {
|
pub struct FunctionManager {
|
||||||
@ -19,7 +22,7 @@ impl Default for FunctionManager {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
functions: vec![(
|
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,
|
FunctionEntry::EMPTY,
|
||||||
)],
|
)],
|
||||||
}
|
}
|
||||||
@ -72,7 +75,17 @@ const fn button_area_button(text: impl Into<WidgetText>) -> Button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionManager {
|
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 can_remove = self.functions.len() > 1;
|
||||||
|
|
||||||
let available_width = ui.available_width();
|
let available_width = ui.available_width();
|
||||||
@ -127,6 +140,8 @@ impl FunctionManager {
|
|||||||
|
|
||||||
if movement != Movement::Complete && let Some(hints) = function.autocomplete.hint.many() {
|
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
|
// 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);
|
const POPUP_ID: Id = Id::new_from_u64(7574801616484505465);
|
||||||
|
|
||||||
let mut clicked = false;
|
let mut clicked = false;
|
||||||
@ -217,6 +232,10 @@ impl FunctionManager {
|
|||||||
if let Some(remove_i_unwrap) = remove_i {
|
if let Some(remove_i_unwrap) = remove_i {
|
||||||
self.functions.remove(remove_i_unwrap);
|
self.functions.remove(remove_i_unwrap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let final_hash = self.get_hash();
|
||||||
|
|
||||||
|
initial_hash != final_hash
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create and push new empty function entry
|
/// Create and push new empty function entry
|
||||||
|
|||||||
@ -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
|
// Only render if there's enough space
|
||||||
if ui.available_height() > crate::data::FONT_SIZE {
|
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()));
|
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 {
|
fn clear_color(&self, _visuals: &egui::Visuals) -> egui::Rgba {
|
||||||
crate::style::STYLE.window_fill().into()
|
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
14
src/misc.rs
14
src/misc.rs
@ -1,5 +1,3 @@
|
|||||||
use std::intrinsics::assume;
|
|
||||||
|
|
||||||
use egui::plot::{Line, Points, Value, Values};
|
use egui::plot::{Line, Points, Value, Values};
|
||||||
use getrandom::getrandom;
|
use getrandom::getrandom;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@ -163,25 +161,27 @@ pub fn hashed_storage_create(hash: HashBytes, data: &[u8]) -> String {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub const fn hashed_storage_read(data: &str) -> Option<(HashBytes, &[u8])> {
|
pub const fn hashed_storage_read(data: &str) -> Option<(HashBytes, &[u8])> {
|
||||||
|
// Make sure data is long enough to decode
|
||||||
if HASH_LENGTH >= data.len() {
|
if HASH_LENGTH >= data.len() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
// Transmute data into slice
|
||||||
assume(!data.is_empty());
|
|
||||||
assume(data.len() > HASH_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
let decoded_1: &[u8] = unsafe { std::mem::transmute::<&str, &[u8]>(data) };
|
let decoded_1: &[u8] = unsafe { std::mem::transmute::<&str, &[u8]>(data) };
|
||||||
|
|
||||||
|
// return hash and decoded data
|
||||||
Some((
|
Some((
|
||||||
unsafe { *(decoded_1[..HASH_LENGTH].as_ptr() as *const HashBytes) },
|
unsafe { *(decoded_1[..HASH_LENGTH].as_ptr() as *const HashBytes) },
|
||||||
&decoded_1[HASH_LENGTH..],
|
&decoded_1[HASH_LENGTH..],
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates and returns random u64
|
||||||
pub fn random_u64() -> Result<u64, getrandom::Error> {
|
pub fn random_u64() -> Result<u64, getrandom::Error> {
|
||||||
|
// Buffer of 8 `u8`s that are later merged into one u64
|
||||||
let mut buf = [0u8; 8];
|
let mut buf = [0u8; 8];
|
||||||
|
// Populate buffer with random values
|
||||||
getrandom(&mut buf)?;
|
getrandom(&mut buf)?;
|
||||||
|
// Merge buffer into u64
|
||||||
Ok(u64::from_be_bytes(buf))
|
Ok(u64::from_be_bytes(buf))
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user