it works!!

This commit is contained in:
Simon Gardling 2022-05-11 12:38:24 -04:00
parent a9a870ec2f
commit 24d2a5bbd8
13 changed files with 106 additions and 142 deletions

3
.gitignore vendored
View File

@ -1,6 +1,5 @@
/target
/pkg
/tmp
/assets.tar.zst
/Cargo.lock
/assets/font_data
/assets/data

64
Cargo.lock generated
View File

@ -794,18 +794,6 @@ dependencies = [
"instant",
]
[[package]]
name = "filetime"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0408e2626025178a6a7f7ffc05a25bc47103229f19c113755de7bf63816290c"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"winapi",
]
[[package]]
name = "findshlibs"
version = "0.10.2"
@ -2164,17 +2152,6 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "tar"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6"
dependencies = [
"filetime",
"libc",
"xattr",
]
[[package]]
name = "tempfile"
version = "3.3.0"
@ -2783,15 +2760,6 @@ dependencies = [
"winapi-wsapoll",
]
[[package]]
name = "xattr"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
dependencies = [
"libc",
]
[[package]]
name = "xcursor"
version = "0.3.4"
@ -2828,10 +2796,10 @@ dependencies = [
"parsing",
"rayon",
"ruzstd",
"serde",
"serde_json",
"shadow-rs",
"static_assertions",
"tar",
"tracing",
"tracing-subscriber",
"tracing-wasm",
@ -2839,4 +2807,34 @@ dependencies = [
"wasm-bindgen",
"web-sys",
"wee_alloc",
"zstd",
]
[[package]]
name = "zstd"
version = "0.11.1+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a16b8414fde0414e90c612eba70985577451c4c504b99885ebed24762cb81a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "5.0.1+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c12659121420dd6365c5c3de4901f97145b79651fb1d25814020ed2ed0585ae"
dependencies = [
"libc",
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.1+zstd.1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b"
dependencies = [
"cc",
"libc",
]

View File

@ -47,7 +47,6 @@ shadow-rs = { version = "0.11", default-features = false }
const_format = { version = "0.2", default-features = false, features = ["fmt"] }
cfg-if = "1"
lazy_static = "1"
tar = "0.4"
ruzstd = { git = "https://github.com/Titaniumtown/zstd-rs.git", branch = "ringbuffer" }
serde_json = "1.0"
tracing = "0.1"
@ -55,6 +54,7 @@ itertools = "0.10"
static_assertions = "1.1"
uuid = { version = "1", features = ["v4", "fast-rng", "js"] }
bincode = "1.3.3"
serde = "1"
[dev-dependencies]
@ -67,6 +67,9 @@ epaint = { git = "https://github.com/Titaniumtown/egui.git", default-features =
"serde",
] }
bincode = "1.3.3"
serde = "1"
serde_json = "1.0"
zstd = "0.11.1+zstd.1.5.2"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
instant = "0.1"

View File

@ -21,3 +21,4 @@
11. Fix mobile text input
12. Don't use json for text storage
13. Write custom plotter
14. Cache decompressed data in browser's [Local Storage](https://rustwasm.github.io/wasm-bindgen/api/web_sys/struct.Storage.html)

View File

@ -13,7 +13,7 @@
"- The 'Info' button provides information on the build currently running.",
"- The Sun/Moon button toggles Dark and Light mode."
],
"help_func": [
"help_function": [
"(From Left to Right)",
"- The `✖` allows you to delete the function in question. Deleting a function is prevented if only 1 function exists.",
"- The `∫` indicates whether to integrate the function in question.",
@ -24,7 +24,7 @@
"- Extrema (local minimums and maximums) and Roots (intersections with the x-axis) are displayed though yellow and light blue points on the graph. You can toggle these in the Side Panel.",
"- In some edge cases, math functions may not parse correctly. More specifically with implicit multiplication. If you incounter this issue, please do report it on the project's Github page (linked on the side panel). But a current workaround would be explicitly stating a multiplication operation through the use of an asterisk."
],
"agpl_info": "The AGPL license ensures that the end user, even if not hosting the program itself, is still guaranteed access to the source code of the project in question.",
"license_info": "The AGPL license ensures that the end user, even if not hosting the program itself, is still guaranteed access to the source code of the project in question.",
"welcome": [
"Welcome to the (Yet-to-be-named) Graphing Software!",
"This project aims to provide an intuitive experience graphing mathematical functions with features such as Integration, differentiation, extrema, roots, and much more! (see Help menu for more details)"

View File

@ -9,6 +9,8 @@ use epaint::{
FontFamily,
};
include!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/data.rs"));
fn main() {
// rebuild if new commit or contents of `assets` folder changed
println!("cargo:rerun-if-changed=.git/logs/HEAD");
@ -49,16 +51,34 @@ fn main() {
]),
};
let path = "./assets/font_data";
let mut file = BufWriter::new(File::create("./assets/data").expect("Could not create file"));
let fonts_data = bincode::serialize(&fonts).unwrap();
// ::to_string(&fonts).expect("Failed to serialize fonts");
let aa: serde_json::Value = serde_json::from_str(include_str!("assets/text.json")).unwrap();
let mut json_file_array = aa.as_object().unwrap().clone();
for value in json_file_array.iter_mut() {
if let serde_json::Value::Array(values) = value.1 {
let values_copy = values.clone();
*value.1 = serde_json::Value::String(
values_copy
.iter()
.map(|s| s.as_str().unwrap())
.collect::<Vec<&str>>()
.join("\n"),
);
}
}
let mut file = BufWriter::new(File::create(&path).expect("Could not create file"));
let text_data: TextData =
serde_json::from_value(serde_json::Value::Object(json_file_array)).unwrap();
file.write_all(fonts_data.as_slice()).unwrap();
let data = bincode::serialize(&TotalData {
text: text_data,
fonts,
})
.unwrap();
let _ = command_run::Command::with_args("./pack_assets.sh", &[&path])
.enable_capture()
.run();
let data_compressed = zstd::encode_all(data.as_slice(), 22).unwrap();
println!("{:?}", data_compressed);
file.write_all(data_compressed.as_slice()).unwrap();
}

View File

@ -1,3 +0,0 @@
#!/bin/bash
rm -fr assets.tar.zst | true
tar -I 'zstd --ultra -22' --strip-components=9999 -cf ./assets.tar.zst assets/text.json $1

18
src/data.rs Normal file
View File

@ -0,0 +1,18 @@
use serde::{Deserialize, Serialize};
#[derive(PartialEq, Debug, Serialize, Deserialize)]
pub struct TextData {
pub help_expr: String,
pub help_vars: String,
pub help_panel: String,
pub help_function: String,
pub help_other: String,
pub license_info: String,
pub welcome: String,
}
#[derive(Serialize, Deserialize)]
pub struct TotalData {
pub text: TextData,
pub fonts: epaint::text::FontDefinitions,
}

View File

@ -32,7 +32,7 @@ impl FunctionManager {
// ui.label("Functions:");
let can_remove = self.functions.len() > 1;
// update if font settings are ever changed
// Update if font settings are ever changed
const ROW_HEIGHT: f32 = 14.0;
// ui.fonts().row_height(&egui::FontSelection::default().resolve(ui.style()));
@ -55,9 +55,9 @@ impl FunctionManager {
egui::TextEdit::singleline(&mut new_string)
.hint_forward(true) // Make the hint appear after the last text in the textbox
.lock_focus(true)
.id(*te_id) // set widget's id to `te_id`
.id(*te_id) // Set widget's id to `te_id`
.hint_text({
// if there's a single hint, go ahead and apply the hint here, if not, set the hint to an empty string
// If there's a single hint, go ahead and apply the hint here, if not, set the hint to an empty string
if let Hint::Single(single_hint) = function.autocomplete.hint {
*single_hint
} else {
@ -66,7 +66,7 @@ impl FunctionManager {
}),
);
// if not fully open, return here as buttons cannot yet be displayed, therefore the user is inable to mark it for deletion
// If not fully open, return here as buttons cannot yet be displayed, therefore the user is inable to mark it for deletion
if ui.ctx().animate_bool(*te_id, re.has_focus()) >= 1.0 {
function.autocomplete.update_string(&new_string);
@ -110,7 +110,7 @@ impl FunctionManager {
if clicked {
function.autocomplete.apply_hint(hints[function.autocomplete.i]);
// don't need this here as it simply won't be display next frame
// Don't need this here as it simply won't be display next frame
// ui.memory().close_popup();
movement = Movement::Complete;
@ -190,11 +190,13 @@ impl FunctionManager {
}
}
/// Create and push new empty function entry
pub fn push_empty(&mut self) {
self.functions
.push((Id::new(Uuid::new_v4()), FunctionEntry::EMPTY));
}
/// Detect if any functions are using integrals
pub fn any_using_integral(&self) -> bool {
self.functions.iter().any(|(_, func)| func.integral)
}

View File

@ -13,6 +13,7 @@ extern crate static_assertions;
extern crate uuid;
mod consts;
mod data;
mod function_entry;
mod function_manager;
mod math_app;

View File

@ -11,6 +11,7 @@ extern crate static_assertions;
extern crate uuid;
mod consts;
mod data;
mod function_entry;
mod function_manager;
mod math_app;

View File

@ -1,17 +1,17 @@
use crate::consts::*;
use crate::data::TextData;
use crate::function_entry::Riemann;
use crate::function_manager::FunctionManager;
use crate::misc::{dyn_mut_iter, option_vec_printer, TextData};
use crate::misc::{dyn_mut_iter, option_vec_printer};
use eframe::App;
use egui::{
plot::Plot, style::Margin, vec2, Button, CentralPanel, Color32, ComboBox, Context,
FontDefinitions, Frame, Key, Label, Layout, RichText, SidePanel, Slider, TopBottomPanel, Vec2,
Visuals, Window,
plot::Plot, style::Margin, vec2, Button, CentralPanel, Color32, ComboBox, Context, Frame, Key,
Label, Layout, RichText, SidePanel, Slider, TopBottomPanel, Vec2, Visuals, Window,
};
use emath::{Align, Align2};
use epaint::Rounding;
use instant::Duration;
use std::{io::Read, ops::BitXorAssign, str};
use std::{io::Read, ops::BitXorAssign};
#[cfg(threading)]
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
@ -142,55 +142,24 @@ impl MathApp {
tracing::info!("Initializing...");
let start = instant::Instant::now();
let mut tar_file_data = Vec::new();
let mut data = Vec::new();
let _ = unsafe {
ruzstd::StreamingDecoder::new(&mut include_bytes!("../assets.tar.zst").as_slice())
ruzstd::StreamingDecoder::new(&mut include_bytes!("../assets/data").as_slice())
.unwrap_unchecked()
.read_to_end(&mut tar_file_data)
.read_to_end(&mut data)
.unwrap_unchecked()
};
let data: crate::data::TotalData = bincode::deserialize(data.as_slice()).unwrap();
#[cfg(target_arch = "wasm32")]
update_loading(&loading_element, 30);
// Stores fonts
let mut font_data: Option<FontDefinitions> = None;
// Stores text
let mut text_data: Option<TextData> = None;
tracing::info!("Reading assets...");
// Iterate through all entries in the tarball
for file in unsafe {
tar::Archive::new(&*tar_file_data)
.entries()
.unwrap_unchecked()
} {
let mut file = unsafe { file.unwrap_unchecked() };
let mut data: Vec<u8> = Vec::new();
unsafe { file.read_to_end(&mut data).unwrap_unchecked() };
let path = unsafe { file.header().path().unwrap_unchecked() };
let path_string = path.to_string_lossy();
// Match the file extention
if path_string.ends_with("font_data") {
font_data = Some(bincode::deserialize(&data).unwrap());
} else if path_string.ends_with("text.json") {
#[cfg(target_arch = "wasm32")]
update_loading(&loading_element, 10);
text_data = Some(TextData::from_json_str(unsafe {
str::from_utf8(&data).unwrap_unchecked()
}));
} else {
panic!("File {} not expected!", path_string);
}
}
// Initialize fonts
// This used to be in the `update` method, but (after a ton of digging) this actually caused OOMs. that was a pain to debug
cc.egui_ctx
.set_fonts(font_data.expect("Failed to load font_data"));
cc.egui_ctx.set_fonts(data.fonts);
// Set dark mode by default
cc.egui_ctx.set_visuals(Visuals::dark());
@ -208,7 +177,7 @@ impl MathApp {
functions: Default::default(),
last_info: (vec![None], None),
dark_mode: true, // dark mode is default and is previously set
text: text_data.expect("Didn't find text.json"),
text: data.text,
opened: Opened::default(),
settings: Default::default(),
}

View File

@ -1,6 +1,5 @@
use eframe::egui::plot::{Line, Points, Value as EguiValue, Values};
use itertools::Itertools;
use serde_json::Value as JsonValue;
#[cfg(threading)]
use rayon::prelude::*;
@ -185,50 +184,6 @@ impl EguiHelper for Vec<EguiValue> {
fn to_tuple(&self) -> Vec<(f64, f64)> { self.iter().map(|ele| (ele.x, ele.y)).collect() }
}
#[derive(PartialEq, Debug)]
pub struct TextData {
pub help_expr: String,
pub help_vars: String,
pub help_panel: String,
pub help_function: String,
pub help_other: String,
pub license_info: String,
pub welcome: String,
}
/// Parses an array of strings at `self.value[key]` as a multiline string
fn parse_multiline(value: &JsonValue, key: &str) -> String {
(value[key])
.as_array()
.expect("Cannot cast to array")
.iter()
.map(|ele| ele.as_str().unwrap())
.fold(String::new(), |s, l| s + l + "\n")
.trim_end()
.to_owned()
}
/// Parses `self.value[key]` as a single line string
fn parse_singleline(value: &JsonValue, key: &str) -> String {
value[key].as_str().expect("cannot cast to str").to_owned()
}
impl TextData {
pub fn from_json_str(string: &str) -> Self {
let value = serde_json::from_str(string).expect("Cannot parse json file");
Self {
help_expr: parse_multiline(&value, "help_expr"),
help_vars: parse_multiline(&value, "help_vars"),
help_panel: parse_multiline(&value, "help_panel"),
help_function: parse_multiline(&value, "help_func"),
help_other: parse_multiline(&value, "help_other"),
license_info: parse_singleline(&value, "agpl_info"),
welcome: parse_multiline(&value, "welcome"),
}
}
}
/// Rounds f64 to `n` decimal places
pub fn decimal_round(x: f64, n: usize) -> f64 {
let large_number: f64 = 10.0_f64.powf(n as f64); // 10^n