code improvements
This commit is contained in:
parent
91855d14fc
commit
020064a79e
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -197,6 +197,15 @@ version = "3.9.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byte-unit"
|
||||||
|
version = "4.0.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95ebf10dda65f19ff0f42ea15572a359ed60d7fc74fdc984d90310937be0014b"
|
||||||
|
dependencies = [
|
||||||
|
"utf8-width",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.9.1"
|
version = "1.9.1"
|
||||||
@ -2358,6 +2367,12 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8-width"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5190c9442dcdaf0ddd50f37420417d219ae5261bbf5db120d0f9bab996c9cba1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@ -2768,6 +2783,7 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"benchmarks",
|
"benchmarks",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
"byte-unit",
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"console_error_panic_hook",
|
"console_error_panic_hook",
|
||||||
"const_format",
|
"const_format",
|
||||||
|
|||||||
@ -57,6 +57,7 @@ uuid = { version = "1", features = ["v4", "fast-rng", "js"] }
|
|||||||
bincode = "1.3"
|
bincode = "1.3"
|
||||||
serde = "1"
|
serde = "1"
|
||||||
base64 = { git = "https://github.com/marshallpierce/rust-base64.git" }
|
base64 = { git = "https://github.com/marshallpierce/rust-base64.git" }
|
||||||
|
byte-unit = "4.0.14"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
benchmarks = { path = "./benchmarks" }
|
benchmarks = { path = "./benchmarks" }
|
||||||
|
|||||||
@ -51,5 +51,5 @@ fn generate_hashmap() {
|
|||||||
|
|
||||||
include!(concat!(
|
include!(concat!(
|
||||||
env!("CARGO_MANIFEST_DIR"),
|
env!("CARGO_MANIFEST_DIR"),
|
||||||
"/src/autocomplete_helper.rs"
|
"/src/autocomplete_hashmap.rs"
|
||||||
));
|
));
|
||||||
|
|||||||
112
parsing/src/autocomplete.rs
Normal file
112
parsing/src/autocomplete.rs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
use std::intrinsics::assume;
|
||||||
|
|
||||||
|
use crate::{generate_hint, Hint, HINT_EMPTY};
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
pub enum Movement {
|
||||||
|
Complete,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Down,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
Up,
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Movement {
|
||||||
|
pub const fn is_none(&self) -> bool { matches!(&self, &Self::None) }
|
||||||
|
|
||||||
|
pub const fn is_complete(&self) -> bool { matches!(&self, &Self::Complete) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl const Default for Movement {
|
||||||
|
fn default() -> Self { Self::None }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
pub struct AutoComplete<'a> {
|
||||||
|
pub i: usize,
|
||||||
|
pub hint: &'a Hint<'a>,
|
||||||
|
pub string: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> const Default for AutoComplete<'a> {
|
||||||
|
fn default() -> AutoComplete<'a> { AutoComplete::EMPTY }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> AutoComplete<'a> {
|
||||||
|
const EMPTY: AutoComplete<'a> = Self {
|
||||||
|
i: 0,
|
||||||
|
hint: &HINT_EMPTY,
|
||||||
|
string: String::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn update_string(&mut self, string: &str) {
|
||||||
|
if self.string != string {
|
||||||
|
// catch empty strings here to avoid call to `generate_hint` and unnecessary logic
|
||||||
|
if string.is_empty() {
|
||||||
|
*self = Self::EMPTY;
|
||||||
|
} else {
|
||||||
|
self.string = string.to_owned();
|
||||||
|
self.do_update_logic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Runs update logic assuming that a change to `self.string` has been made
|
||||||
|
fn do_update_logic(&mut self) {
|
||||||
|
self.i = 0;
|
||||||
|
self.hint = generate_hint(&self.string);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn register_movement(&mut self, movement: &Movement) {
|
||||||
|
if movement.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.hint {
|
||||||
|
Hint::Many(hints) => {
|
||||||
|
// Impossible for plural hints to be singular or non-existant
|
||||||
|
unsafe {
|
||||||
|
assume(hints.len() > 1);
|
||||||
|
assume(!hints.is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
match movement {
|
||||||
|
Movement::Up => {
|
||||||
|
// if self.i is below 1, it's at
|
||||||
|
match self.i {
|
||||||
|
0 => self.i = hints.len() - 1,
|
||||||
|
_ => self.i -= 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Movement::Down => {
|
||||||
|
// add one, if resulting value is above maximum i value, set i to 0
|
||||||
|
self.i += 1;
|
||||||
|
if self.i > (hints.len() - 1) {
|
||||||
|
self.i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Movement::Complete => {
|
||||||
|
unsafe { assume(hints.len() >= (self.i + 1)) }
|
||||||
|
|
||||||
|
self.apply_hint(hints[self.i]);
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Hint::Single(hint) => {
|
||||||
|
if movement.is_complete() {
|
||||||
|
self.apply_hint(hint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn apply_hint(&mut self, hint: &str) {
|
||||||
|
self.string.push_str(hint);
|
||||||
|
self.do_update_logic();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,15 +3,17 @@
|
|||||||
#![feature(const_default_impls)]
|
#![feature(const_default_impls)]
|
||||||
#![feature(const_mut_refs)]
|
#![feature(const_mut_refs)]
|
||||||
|
|
||||||
mod autocomplete_helper;
|
mod autocomplete;
|
||||||
|
mod autocomplete_hashmap;
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod suggestions;
|
mod suggestions;
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
autocomplete_helper::compile_hashmap,
|
autocomplete::{AutoComplete, Movement},
|
||||||
|
autocomplete_hashmap::compile_hashmap,
|
||||||
parsing::{process_func_str, BackingFunction},
|
parsing::{process_func_str, BackingFunction},
|
||||||
suggestions::{
|
suggestions::{
|
||||||
generate_hint, get_last_term, split_function, split_function_chars, AutoComplete, Hint,
|
generate_hint, get_last_term, split_function, split_function_chars, Hint, HINT_EMPTY,
|
||||||
Movement, HINT_EMPTY, SUPPORTED_FUNCTIONS,
|
SUPPORTED_FUNCTIONS,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use exmex::prelude::*;
|
use exmex::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub(crate) struct FlatExWrapper {
|
pub(crate) struct FlatExWrapper {
|
||||||
func: Option<FlatEx<f64>>,
|
func: Option<FlatEx<f64>>,
|
||||||
}
|
}
|
||||||
@ -45,7 +45,7 @@ impl const Default for FlatExWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Function that includes f(x), f'(x), f'(x)'s string representation, and f''(x)
|
/// Function that includes f(x), f'(x), f'(x)'s string representation, and f''(x)
|
||||||
#[derive(Clone)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub struct BackingFunction {
|
pub struct BackingFunction {
|
||||||
/// f(x)
|
/// f(x)
|
||||||
function: FlatExWrapper,
|
function: FlatExWrapper,
|
||||||
@ -73,7 +73,7 @@ impl BackingFunction {
|
|||||||
nth_derivative: None,
|
nth_derivative: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn is_none(&self) -> bool { self.function.is_none() }
|
pub const fn is_none(&self) -> bool { self.function.is_none() }
|
||||||
|
|
||||||
/// Create new [`BackingFunction`] instance
|
/// Create new [`BackingFunction`] instance
|
||||||
pub fn new(func_str: &str) -> Result<Self, String> {
|
pub fn new(func_str: &str) -> Result<Self, String> {
|
||||||
|
|||||||
@ -205,15 +205,16 @@ pub fn generate_hint<'a>(input: &str) -> &'a Hint<'a> {
|
|||||||
pub fn get_last_term(chars: &[char]) -> String {
|
pub fn get_last_term(chars: &[char]) -> String {
|
||||||
assert!(!chars.is_empty());
|
assert!(!chars.is_empty());
|
||||||
|
|
||||||
|
let result = split_function_chars(chars, SplitType::Term);
|
||||||
unsafe {
|
unsafe {
|
||||||
split_function_chars(chars, SplitType::Term)
|
assume(!result.is_empty());
|
||||||
.last()
|
assume(result.len() > 0);
|
||||||
.unwrap_unchecked()
|
result.last().unwrap_unchecked()
|
||||||
.to_owned()
|
|
||||||
}
|
}
|
||||||
|
.to_owned()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq, Clone, Copy)]
|
||||||
pub enum Hint<'a> {
|
pub enum Hint<'a> {
|
||||||
Single(&'a str),
|
Single(&'a str),
|
||||||
Many(&'a [&'a str]),
|
Many(&'a [&'a str]),
|
||||||
@ -253,110 +254,3 @@ impl<'a> Hint<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
|
include!(concat!(env!("OUT_DIR"), "/codegen.rs"));
|
||||||
|
|
||||||
#[derive(PartialEq, Debug)]
|
|
||||||
pub enum Movement {
|
|
||||||
Complete,
|
|
||||||
#[allow(dead_code)]
|
|
||||||
Down,
|
|
||||||
#[allow(dead_code)]
|
|
||||||
Up,
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Movement {
|
|
||||||
pub const fn is_none(&self) -> bool { matches!(&self, Self::None) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl const Default for Movement {
|
|
||||||
fn default() -> Self { Self::None }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct AutoComplete<'a> {
|
|
||||||
pub i: usize,
|
|
||||||
pub hint: &'a Hint<'a>,
|
|
||||||
pub string: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> const Default for AutoComplete<'a> {
|
|
||||||
fn default() -> AutoComplete<'a> { AutoComplete::EMPTY }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> AutoComplete<'a> {
|
|
||||||
const EMPTY: AutoComplete<'a> = Self {
|
|
||||||
i: 0,
|
|
||||||
hint: &HINT_EMPTY,
|
|
||||||
string: String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn update_string(&mut self, string: &str) {
|
|
||||||
if self.string != string {
|
|
||||||
// catch empty strings here to avoid call to `generate_hint` and unnecessary logic
|
|
||||||
if string.is_empty() {
|
|
||||||
*self = Self::EMPTY;
|
|
||||||
} else {
|
|
||||||
self.string = string.to_owned();
|
|
||||||
self.do_update_logic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Runs update logic assuming that a change to `self.string` has been made
|
|
||||||
fn do_update_logic(&mut self) {
|
|
||||||
self.i = 0;
|
|
||||||
self.hint = generate_hint(&self.string);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn register_movement(&mut self, movement: &Movement) {
|
|
||||||
if movement.is_none() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.hint {
|
|
||||||
Hint::Many(hints) => {
|
|
||||||
// Impossible for plural hints to be singular or non-existant
|
|
||||||
unsafe {
|
|
||||||
assume(hints.len() > 1);
|
|
||||||
assume(!hints.is_empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
match movement {
|
|
||||||
Movement::Up => {
|
|
||||||
// if self.i is below 1, it's at
|
|
||||||
match self.i {
|
|
||||||
0 => self.i = hints.len() - 1,
|
|
||||||
_ => self.i -= 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Movement::Down => {
|
|
||||||
// add one, if resulting value is above maximum i value, set i to 0
|
|
||||||
self.i += 1;
|
|
||||||
if self.i > (hints.len() - 1) {
|
|
||||||
self.i = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Movement::Complete => {
|
|
||||||
unsafe { assume(hints.len() >= (self.i + 1)) }
|
|
||||||
|
|
||||||
self.apply_hint(hints[self.i]);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Hint::Single(hint) => {
|
|
||||||
if movement == &Movement::Complete {
|
|
||||||
self.apply_hint(hint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn apply_hint(&mut self, hint: &str) {
|
|
||||||
self.string.push_str(hint);
|
|
||||||
self.do_update_logic();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ impl fmt::Display for Riemann {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `FunctionEntry` is a function that can calculate values, integrals, derivatives, etc etc
|
/// `FunctionEntry` is a function that can calculate values, integrals, derivatives, etc etc
|
||||||
#[derive(Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
pub struct FunctionEntry {
|
pub struct FunctionEntry {
|
||||||
/// The `BackingFunction` instance that is used to generate `f(x)`, `f'(x)`, and `f''(x)`
|
/// The `BackingFunction` instance that is used to generate `f(x)`, `f'(x)`, and `f''(x)`
|
||||||
function: BackingFunction,
|
function: BackingFunction,
|
||||||
|
|||||||
@ -24,8 +24,8 @@ pub use crate::{
|
|||||||
function_entry::{FunctionEntry, Riemann},
|
function_entry::{FunctionEntry, Riemann},
|
||||||
math_app::AppSettings,
|
math_app::AppSettings,
|
||||||
misc::{
|
misc::{
|
||||||
decimal_round, option_vec_printer, resolution_helper, storage_create, storage_read,
|
decimal_round, format_bytes, hashed_storage_create, hashed_storage_read,
|
||||||
SteppedVector,
|
option_vec_printer, resolution_helper, SteppedVector,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -125,29 +125,34 @@ impl MathApp {
|
|||||||
tracing::info!("Web Info: {:?}", web_info);
|
tracing::info!("Web Info: {:?}", web_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
let window = web_sys::window().expect("Could not get web_sys window");
|
fn get_window() -> web_sys::Window {
|
||||||
|
web_sys::window().expect("Could not get web_sys window")
|
||||||
|
}
|
||||||
|
|
||||||
let document = window.document().expect("Could not get web_sys document");
|
fn get_localstorage() -> web_sys::Storage {
|
||||||
|
get_window().local_storage().expect("failed to get localstorage1").expect("failed to get localstorage2")
|
||||||
|
}
|
||||||
|
|
||||||
let loading_element = document
|
let loading_element = get_window().document()
|
||||||
|
.expect("Could not get web_sys document")
|
||||||
.get_element_by_id("loading")
|
.get_element_by_id("loading")
|
||||||
.expect("Couldn't get loading indicator element")
|
.expect("Couldn't get loading indicator element")
|
||||||
.dyn_into::<web_sys::HtmlElement>()
|
.dyn_into::<web_sys::HtmlElement>()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
||||||
fn update_loading(loading_element: &web_sys::HtmlElement, add: i32) {
|
fn update_loading(loading_element: &web_sys::HtmlElement, add: i32) {
|
||||||
let value =
|
let value = loading_element.get_attribute("value").expect("unable to get loading_elements's `value`").parse::<i32>().expect("unable to parse value as i32");
|
||||||
unsafe { loading_element.get_attribute("value").unwrap_unchecked().parse::<i32>().unwrap_unchecked() };
|
loading_element.set_attribute("value", &(add + value).to_string()).expect("unable to set loading_element's `value`");
|
||||||
loading_element.set_attribute("value", &(add + value).to_string()).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DATA_NAME: &str = "YTBN-DECOMPRESSED";
|
const DATA_NAME: &str = "YTBN-DECOMPRESSED";
|
||||||
fn get_storage_decompressed() -> Option<Vec<u8>> {
|
fn get_storage_decompressed() -> Option<Vec<u8>> {
|
||||||
if let Ok(Some(data)) = web_sys::window().expect("Could not get web_sys window").local_storage().unwrap().unwrap().get_item("YTBN-DECOMPRESSED") {
|
if let Ok(Some(data)) = get_localstorage().get_item(DATA_NAME) {
|
||||||
let (commit, cached_data) = crate::misc::storage_read(data);
|
let (commit, cached_data) = crate::misc::hashed_storage_read(data);
|
||||||
|
|
||||||
if commit == build::SHORT_COMMIT {
|
if commit == build::SHORT_COMMIT {
|
||||||
tracing::info!("Reading decompression cache");
|
tracing::info!("Reading decompression cache. Bytes: {}, or: {}", cached_data.len(), crate::misc::format_bytes(cached_data.len()));
|
||||||
return Some(cached_data.to_vec());
|
return Some(cached_data.to_vec());
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("Decompression cache are invalid due to differing commits (build: {}, previous: {})", build::SHORT_COMMIT, commit);
|
tracing::info!("Decompression cache are invalid due to differing commits (build: {}, previous: {})", build::SHORT_COMMIT, commit);
|
||||||
@ -155,33 +160,28 @@ impl MathApp {
|
|||||||
// is invalid
|
// is invalid
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_storage_decompressed(data: &Vec<u8>) {
|
fn set_storage_decompressed(data: &Vec<u8>) {
|
||||||
if let Ok(Some(local_storage)) = web_sys::window().expect("Could not get web_sys window").local_storage() {
|
tracing::info!("Setting decompression cache");
|
||||||
tracing::info!("Setting decompression cache");
|
let saved_data = &crate::misc::hashed_storage_create(&build::SHORT_COMMIT.chars().map(|c| c as u8).collect::<Vec<u8>>(), data.as_slice());
|
||||||
let saved_data = &crate::misc::storage_create(&build::SHORT_COMMIT.chars().map(|c| c as u8).collect::<Vec<u8>>(), data.as_slice());
|
tracing::info!("Bytes: {}, or: {}", saved_data.len(), crate::misc::format_bytes(data.len()));
|
||||||
tracing::info!("Data has length of {}", saved_data.len());
|
get_localstorage().set_item(DATA_NAME, saved_data).expect("failed to set local storage cache");
|
||||||
local_storage.set_item("YTBN-DECOMPRESSED", saved_data).expect("failed to set local storage cache");
|
|
||||||
} else {
|
|
||||||
panic!("unable to get local storage")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_functions() -> Option<FunctionManager> {
|
fn get_functions() -> Option<FunctionManager> {
|
||||||
if let Ok(Some(data)) = web_sys::window().expect("Could not get web_sys window").local_storage().unwrap().unwrap().get_item("YTBN-FUNCTIONS") {
|
if let Ok(Some(data)) = get_localstorage().get_item("YTBN-FUNCTIONS") {
|
||||||
let (commit, func_data) = crate::misc::storage_read(data);
|
let (commit, func_data) = crate::misc::hashed_storage_read(data);
|
||||||
|
|
||||||
if commit == build::SHORT_COMMIT {
|
if commit == build::SHORT_COMMIT {
|
||||||
tracing::info!("Reading old functions");
|
tracing::info!("Reading previous function data");
|
||||||
let function_manager: FunctionManager = bincode::deserialize(&func_data).unwrap();
|
let function_manager: FunctionManager = bincode::deserialize(&func_data).unwrap();
|
||||||
return Some(function_manager);
|
return Some(function_manager);
|
||||||
} else {
|
} else {
|
||||||
tracing::info!("Old functions are invalid due to differing commits (build: {}, previous: {})", build::SHORT_COMMIT, commit);
|
tracing::info!("Previous functions are invalid due to differing commits (build: {}, previous: {})", build::SHORT_COMMIT, commit);
|
||||||
// is invalid
|
// is invalid
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -603,14 +603,14 @@ impl App for MathApp {
|
|||||||
.local_storage()
|
.local_storage()
|
||||||
{
|
{
|
||||||
tracing::info!("Setting current functions");
|
tracing::info!("Setting current functions");
|
||||||
let saved_data = &crate::misc::storage_create(
|
let saved_data = &crate::misc::hashed_storage_create(
|
||||||
&build::SHORT_COMMIT
|
&build::SHORT_COMMIT
|
||||||
.chars()
|
.chars()
|
||||||
.map(|c| c as u8)
|
.map(|c| c as u8)
|
||||||
.collect::<Vec<u8>>(),
|
.collect::<Vec<u8>>(),
|
||||||
bincode::serialize(&self.functions).unwrap().as_slice(),
|
bincode::serialize(&self.functions).unwrap().as_slice(),
|
||||||
);
|
);
|
||||||
tracing::info!("Data has length of {}", saved_data.len());
|
tracing::info!("Bytes: {}", saved_data.len());
|
||||||
local_storage
|
local_storage
|
||||||
.set_item("YTBN-FUNCTIONS", saved_data)
|
.set_item("YTBN-FUNCTIONS", saved_data)
|
||||||
.expect("failed to set local function storage");
|
.expect("failed to set local function storage");
|
||||||
|
|||||||
43
src/misc.rs
43
src/misc.rs
@ -251,8 +251,9 @@ where
|
|||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
||||||
let max_i: i32 = (data.len() as i32) - 1;
|
let max_i: i32 = (data.len() as i32) - 1;
|
||||||
"[".to_owned()
|
[
|
||||||
+ &data
|
"[",
|
||||||
|
&data
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|x| {
|
||||||
x.as_ref()
|
x.as_ref()
|
||||||
@ -268,8 +269,10 @@ where
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.concat()
|
.concat(),
|
||||||
+ "]"
|
"]",
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a vector of length `max_i` starting at value `min_x` with resolution of `resolution`
|
/// Returns a vector of length `max_i` starting at value `min_x` with resolution of `resolution`
|
||||||
@ -284,22 +287,36 @@ pub fn step_helper(max_i: usize, min_x: &f64, step: &f64) -> Vec<f64> {
|
|||||||
(0..max_i).map(|x| (x as f64 * step) + min_x).collect()
|
(0..max_i).map(|x| (x as f64 * step) + min_x).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
const HASH_LENGTH: usize = 8;
|
||||||
pub fn storage_create(commit: &[u8], data: &[u8]) -> String {
|
|
||||||
assert_eq!(commit.len(), 8);
|
|
||||||
|
|
||||||
let mut new_data = commit.to_vec();
|
#[allow(dead_code)]
|
||||||
let mut data = data.to_vec();
|
pub fn hashed_storage_create(hash: &[u8], data: &[u8]) -> String {
|
||||||
new_data.append(&mut data);
|
debug_assert_eq!(hash.len(), HASH_LENGTH);
|
||||||
|
debug_assert!(data.len() > 0);
|
||||||
|
|
||||||
|
let new_data = [hash, data].concat();
|
||||||
|
debug_assert_eq!(new_data.len(), data.len() + hash.len());
|
||||||
base64::encode(new_data)
|
base64::encode(new_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn storage_read(data: String) -> (String, Vec<u8>) {
|
pub fn hashed_storage_read(data: String) -> (String, Vec<u8>) {
|
||||||
let decoded_1 = base64::decode(data).expect("unable to read data");
|
let decoded_1 = base64::decode(data).expect("unable to read data");
|
||||||
let (commit, cached_data) = decoded_1.split_at(8);
|
debug_assert!(decoded_1.len() > HASH_LENGTH);
|
||||||
|
|
||||||
|
let (hash, cached_data) = decoded_1.split_at(8);
|
||||||
|
debug_assert_eq!(hash.len(), HASH_LENGTH);
|
||||||
|
debug_assert!(cached_data.len() > 0);
|
||||||
|
|
||||||
(
|
(
|
||||||
commit.iter().map(|c| *c as char).collect::<String>(),
|
hash.iter().map(|c| *c as char).collect::<String>(),
|
||||||
cached_data.to_vec(),
|
cached_data.to_vec(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn format_bytes(bytes: usize) -> String {
|
||||||
|
byte_unit::Byte::from_bytes(bytes as u128)
|
||||||
|
.get_appropriate_unit(false)
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
use ytbn_graphing_software::{storage_create, storage_read};
|
|
||||||
|
|
||||||
/// Tests [`SteppedVector`] to ensure everything works properly (helped me find a bunch of issues)
|
/// Tests [`SteppedVector`] to ensure everything works properly (helped me find a bunch of issues)
|
||||||
#[test]
|
#[test]
|
||||||
fn stepped_vector() {
|
fn stepped_vector() {
|
||||||
@ -97,15 +95,29 @@ fn option_vec_printer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn storage() {
|
fn hash_b64_storage() {
|
||||||
|
use ytbn_graphing_software::{hashed_storage_create, hashed_storage_read};
|
||||||
|
|
||||||
let commit = "abcdefeg".chars().map(|c| c as u8).collect::<Vec<u8>>();
|
let commit = "abcdefeg".chars().map(|c| c as u8).collect::<Vec<u8>>();
|
||||||
let data = "really cool data"
|
let data = "really cool data"
|
||||||
.chars()
|
.chars()
|
||||||
.map(|c| c as u8)
|
.map(|c| c as u8)
|
||||||
.collect::<Vec<u8>>();
|
.collect::<Vec<u8>>();
|
||||||
let storage = storage_create(commit.as_slice(), data.as_slice());
|
let storage = hashed_storage_create(commit.as_slice(), data.as_slice());
|
||||||
|
|
||||||
let read = storage_read(storage);
|
let read = hashed_storage_read(storage);
|
||||||
assert_eq!(read.0.chars().map(|c| c as u8).collect::<Vec<u8>>(), commit);
|
assert_eq!(read.0.chars().map(|c| c as u8).collect::<Vec<u8>>(), commit);
|
||||||
assert_eq!(read.1, data);
|
assert_eq!(read.1, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_bytes() {
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use ytbn_graphing_software::format_bytes;
|
||||||
|
|
||||||
|
let values: HashMap<usize, &str> = HashMap::from([(1000, "1000 B"), (10000, "10.00 KB")]);
|
||||||
|
|
||||||
|
for (key, value) in values {
|
||||||
|
assert_eq!(format_bytes(key), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -198,6 +198,7 @@ fn split_function() {
|
|||||||
("sin(x)*cos(x)", vec!["sin(x)", "cos(x)"]),
|
("sin(x)*cos(x)", vec!["sin(x)", "cos(x)"]),
|
||||||
("x*x", vec!["x", "x"]),
|
("x*x", vec!["x", "x"]),
|
||||||
("10*10", vec!["10", "10"]),
|
("10*10", vec!["10", "10"]),
|
||||||
|
("a1b2c3d4", vec!["a1b2c3d4"]),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for (key, value) in values {
|
for (key, value) in values {
|
||||||
@ -240,6 +241,7 @@ fn get_last_term() {
|
|||||||
("x*x", "x"),
|
("x*x", "x"),
|
||||||
("10*10", "10"),
|
("10*10", "10"),
|
||||||
("sin(cos", "cos"),
|
("sin(cos", "cos"),
|
||||||
|
("exp(cos(exp(sin", "sin"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
for (key, value) in values {
|
for (key, value) in values {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user