cleanup
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -4145,7 +4145,6 @@ dependencies = [
|
||||
"base64",
|
||||
"benchmarks",
|
||||
"bincode",
|
||||
"cfg-if",
|
||||
"eframe",
|
||||
"egui",
|
||||
"egui_plot",
|
||||
|
||||
@@ -48,7 +48,6 @@ epaint = { git = "https://github.com/titaniumtown/egui.git", default-features =
|
||||
emath = { git = "https://github.com/titaniumtown/egui.git", default-features = false }
|
||||
egui_plot = { version = "0.34.0", default-features = false }
|
||||
|
||||
cfg-if = "1"
|
||||
ruzstd = "0.8"
|
||||
tracing = "0.1"
|
||||
itertools = "0.14"
|
||||
|
||||
@@ -8,10 +8,7 @@ use epaint::Color32;
|
||||
use parsing::{AutoComplete, generate_hint};
|
||||
use parsing::{BackingFunction, process_func_str};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct};
|
||||
use std::{
|
||||
fmt::{self, Debug},
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
use std::fmt::{self, Debug};
|
||||
|
||||
/// Represents the possible variations of Riemann Sums
|
||||
#[derive(PartialEq, Eq, Debug, Copy, Clone, Default)]
|
||||
@@ -35,9 +32,6 @@ pub struct FunctionEntry {
|
||||
/// The `BackingFunction` instance that is used to generate `f(x)`, `f'(x)`, and `f''(x)`
|
||||
function: BackingFunction,
|
||||
|
||||
/// Stores a function string (that hasn't been processed via `process_func_str`) to display to the user
|
||||
pub raw_func_str: String,
|
||||
|
||||
/// If calculating/displayingintegrals are enabled
|
||||
pub integral: bool,
|
||||
|
||||
@@ -61,23 +55,13 @@ pub struct FunctionEntry {
|
||||
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_derivative.hash(state);
|
||||
self.curr_nth.hash(state);
|
||||
self.settings_opened.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for FunctionEntry {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let mut s = serializer.serialize_struct("FunctionEntry", 4)?;
|
||||
s.serialize_field("raw_func_str", &self.raw_func_str)?;
|
||||
s.serialize_field("raw_func_str", &self.autocomplete.string)?;
|
||||
s.serialize_field("integral", &self.integral)?;
|
||||
s.serialize_field("derivative", &self.derivative)?;
|
||||
s.serialize_field("curr_nth", &self.curr_nth)?;
|
||||
@@ -126,7 +110,6 @@ impl Default for FunctionEntry {
|
||||
fn default() -> FunctionEntry {
|
||||
FunctionEntry {
|
||||
function: BackingFunction::default(),
|
||||
raw_func_str: String::new(),
|
||||
integral: false,
|
||||
derivative: false,
|
||||
nth_derivative: false,
|
||||
@@ -151,7 +134,7 @@ impl FunctionEntry {
|
||||
|
||||
pub fn settings_window(&mut self, ctx: &Context) {
|
||||
let mut invalidate_nth = false;
|
||||
egui::Window::new(format!("Settings: {}", self.raw_func_str))
|
||||
egui::Window::new(format!("Settings: {}", self.func_str()))
|
||||
.open(&mut self.settings_opened)
|
||||
.default_pos([200.0, 200.0])
|
||||
.resizable(false)
|
||||
@@ -181,13 +164,32 @@ impl FunctionEntry {
|
||||
&self.test_result
|
||||
}
|
||||
|
||||
/// Get the raw function string
|
||||
#[inline]
|
||||
pub fn func_str(&self) -> &str {
|
||||
&self.autocomplete.string
|
||||
}
|
||||
|
||||
/// Update function string and test it
|
||||
pub fn update_string(&mut self, raw_func_str: &str) {
|
||||
if raw_func_str == self.raw_func_str {
|
||||
if raw_func_str == self.func_str() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.raw_func_str = raw_func_str.to_owned();
|
||||
// Update the autocomplete string (which is now the source of truth for the raw string)
|
||||
self.autocomplete.update_string(raw_func_str);
|
||||
|
||||
self.reparse_function(raw_func_str);
|
||||
}
|
||||
|
||||
/// Re-parse the function from the current autocomplete string.
|
||||
/// Call this when the autocomplete string was updated externally (e.g., via hint application).
|
||||
pub fn sync_from_autocomplete(&mut self) {
|
||||
self.reparse_function(&self.autocomplete.string.clone());
|
||||
}
|
||||
|
||||
/// Internal helper to parse a function string and update internal state
|
||||
fn reparse_function(&mut self, raw_func_str: &str) {
|
||||
let processed_func = process_func_str(raw_func_str);
|
||||
let new_func_result = BackingFunction::new(&processed_func);
|
||||
|
||||
@@ -213,17 +215,16 @@ impl FunctionEntry {
|
||||
) -> (Vec<(f64, f64)>, f64) {
|
||||
let step = (integral_max_x - integral_min_x) / (integral_num as f64);
|
||||
|
||||
// let sum_func = self.get_sum_func(sum);
|
||||
|
||||
let data2: Vec<(f64, f64)> = step_helper(integral_num, integral_min_x, step)
|
||||
let data: Vec<(f64, f64)> = step_helper(integral_num, integral_min_x, step)
|
||||
.into_iter()
|
||||
.map(|x| {
|
||||
let step_offset = step.copysign(x); // store the offset here so it doesn't have to be calculated multiple times
|
||||
let x2: f64 = x + step_offset;
|
||||
let step_offset = step.copysign(x);
|
||||
let x2 = x + step_offset;
|
||||
|
||||
let (left_x, right_x) = match x.is_sign_positive() {
|
||||
true => (x, x2),
|
||||
false => (x2, x),
|
||||
let (left_x, right_x) = if x.is_sign_positive() {
|
||||
(x, x2)
|
||||
} else {
|
||||
(x2, x)
|
||||
};
|
||||
|
||||
let y = match sum {
|
||||
@@ -239,9 +240,9 @@ impl FunctionEntry {
|
||||
.filter(|(_, y)| y.is_finite())
|
||||
.collect();
|
||||
|
||||
let area = data2.iter().map(move |(_, y)| y * step).sum();
|
||||
let area = data.iter().map(|(_, y)| y * step).sum();
|
||||
|
||||
(data2, area)
|
||||
(data, area)
|
||||
}
|
||||
|
||||
/// Helps with processing newton's method depending on level of derivative
|
||||
@@ -377,26 +378,9 @@ impl FunctionEntry {
|
||||
let step = (settings.max_x - settings.min_x) / (settings.plot_width as f64);
|
||||
debug_assert!(step > 0.0);
|
||||
|
||||
// Collect special points (extrema and roots) for exclusion from line hover detection
|
||||
let special_points: Vec<&PlotPoint> = {
|
||||
let mut points = Vec::new();
|
||||
if settings.do_extrema {
|
||||
points.extend(self.extrema_data.iter());
|
||||
}
|
||||
if settings.do_roots {
|
||||
points.extend(self.root_data.iter());
|
||||
}
|
||||
points
|
||||
};
|
||||
|
||||
// Helper to check if a point is near any special point
|
||||
// Uses a radius in x-axis units based on the step size
|
||||
let exclusion_radius = step * 3.0; // Exclude points within 3 steps of special points
|
||||
let is_near_special_point = |p: &PlotPoint| -> bool {
|
||||
special_points
|
||||
.iter()
|
||||
.any(|sp| (p.x - sp.x).abs() < exclusion_radius)
|
||||
};
|
||||
// Check if we have any special points that need exclusion zones
|
||||
let has_special_points = (settings.do_extrema && !self.extrema_data.is_empty())
|
||||
|| (settings.do_roots && !self.root_data.is_empty());
|
||||
|
||||
// Plot back data, filtering out points near special points for better hover detection
|
||||
if !self.back_data.is_empty() {
|
||||
@@ -417,31 +401,62 @@ impl FunctionEntry {
|
||||
);
|
||||
}
|
||||
|
||||
// Filter out points near special points so cursor snaps to them more easily
|
||||
let filtered_back_data: Vec<PlotPoint> = self
|
||||
.back_data
|
||||
.iter()
|
||||
.filter(|p| !is_near_special_point(p))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
plot_ui.line(
|
||||
filtered_back_data
|
||||
// Only filter when there are special points to avoid
|
||||
let main_line = if has_special_points {
|
||||
let exclusion_radius = step * 3.0;
|
||||
let is_near_special = |p: &PlotPoint| {
|
||||
(settings.do_extrema
|
||||
&& self
|
||||
.extrema_data
|
||||
.iter()
|
||||
.any(|sp| (p.x - sp.x).abs() < exclusion_radius))
|
||||
|| (settings.do_roots
|
||||
&& self
|
||||
.root_data
|
||||
.iter()
|
||||
.any(|sp| (p.x - sp.x).abs() < exclusion_radius))
|
||||
};
|
||||
self.back_data
|
||||
.iter()
|
||||
.filter(|p| !is_near_special(p))
|
||||
.cloned()
|
||||
.collect::<Vec<PlotPoint>>()
|
||||
.to_line()
|
||||
.stroke(egui::Stroke::new(4.0, main_plot_color)),
|
||||
);
|
||||
} else {
|
||||
// No filtering needed - use data directly
|
||||
self.back_data.clone().to_line()
|
||||
};
|
||||
|
||||
plot_ui.line(main_line.stroke(egui::Stroke::new(4.0, main_plot_color)));
|
||||
}
|
||||
|
||||
// Plot derivative data, also filtering near special points
|
||||
// Plot derivative data
|
||||
if self.derivative && !self.derivative_data.is_empty() {
|
||||
let filtered_derivative_data: Vec<PlotPoint> = self
|
||||
.derivative_data
|
||||
.iter()
|
||||
.filter(|p| !is_near_special_point(p))
|
||||
.cloned()
|
||||
.collect();
|
||||
let derivative_line = if has_special_points {
|
||||
let exclusion_radius = step * 3.0;
|
||||
let is_near_special = |p: &PlotPoint| {
|
||||
(settings.do_extrema
|
||||
&& self
|
||||
.extrema_data
|
||||
.iter()
|
||||
.any(|sp| (p.x - sp.x).abs() < exclusion_radius))
|
||||
|| (settings.do_roots
|
||||
&& self
|
||||
.root_data
|
||||
.iter()
|
||||
.any(|sp| (p.x - sp.x).abs() < exclusion_radius))
|
||||
};
|
||||
self.derivative_data
|
||||
.iter()
|
||||
.filter(|p| !is_near_special(p))
|
||||
.cloned()
|
||||
.collect::<Vec<PlotPoint>>()
|
||||
.to_line()
|
||||
} else {
|
||||
self.derivative_data.clone().to_line()
|
||||
};
|
||||
|
||||
plot_ui.line(filtered_derivative_data.to_line().color(Color32::GREEN));
|
||||
plot_ui.line(derivative_line.color(Color32::GREEN));
|
||||
}
|
||||
|
||||
// Plot extrema points
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
use crate::{consts::COLORS, function_entry::FunctionEntry, widgets::widgets_ontop};
|
||||
use crate::{function_entry::FunctionEntry, widgets::widgets_ontop};
|
||||
use egui::{Button, Id, Key, Modifiers, PopupCloseBehavior, TextEdit, WidgetText};
|
||||
use emath::vec2;
|
||||
use parsing::Movement;
|
||||
use serde::ser::SerializeStruct;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::ops::BitXorAssign;
|
||||
|
||||
type Functions = Vec<(Id, FunctionEntry)>;
|
||||
@@ -33,8 +30,8 @@ fn func_manager_roundtrip_serdes() {
|
||||
let ser = bincode::serialize(&func_manager).expect("unable to serialize");
|
||||
let des: FunctionManager = bincode::deserialize(&ser).expect("unable to deserialize");
|
||||
assert_eq!(
|
||||
func_manager.functions[0].1.raw_func_str,
|
||||
des.functions[0].1.raw_func_str
|
||||
func_manager.functions[0].1.func_str(),
|
||||
des.functions[0].1.func_str()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -50,17 +47,9 @@ impl FunctionManager {
|
||||
}
|
||||
}
|
||||
|
||||
#[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 mut changed = false;
|
||||
let can_remove = self.functions.len() > 1;
|
||||
|
||||
let available_width = ui.available_width();
|
||||
@@ -68,7 +57,6 @@ impl FunctionManager {
|
||||
let target_size = vec2(available_width, crate::consts::FONT_SIZE);
|
||||
for (i, (te_id, function)) in self.functions.iter_mut().map(|(a, b)| (*a, b)).enumerate() {
|
||||
let mut new_string = function.autocomplete.string.clone();
|
||||
function.update_string(&new_string);
|
||||
|
||||
let mut movement: Movement = Movement::default();
|
||||
|
||||
@@ -92,11 +80,15 @@ impl FunctionManager {
|
||||
// Only keep valid chars
|
||||
new_string.retain(crate::misc::is_valid_char);
|
||||
|
||||
// Track if function string changed and update the function
|
||||
if new_string != function.autocomplete.string {
|
||||
changed = true;
|
||||
function.update_string(&new_string);
|
||||
}
|
||||
|
||||
// If not fully open, return here as buttons cannot yet be displayed, therefore the user is inable to mark it for deletion
|
||||
let animate_bool = ui.ctx().animate_bool(te_id, re.has_focus());
|
||||
if animate_bool == 1.0 {
|
||||
function.autocomplete.update_string(&new_string);
|
||||
|
||||
if function.autocomplete.hint.is_some() {
|
||||
// only register up and down arrow movements if hint is type `Hint::Many`
|
||||
if !function.autocomplete.hint.is_single() {
|
||||
@@ -121,9 +113,18 @@ impl FunctionManager {
|
||||
movement = Movement::Complete;
|
||||
}
|
||||
|
||||
// Remember string before movement to detect changes
|
||||
let string_before = function.autocomplete.string.clone();
|
||||
|
||||
// Register movement and apply proper changes
|
||||
function.autocomplete.register_movement(&movement);
|
||||
|
||||
// If the string changed (hint was applied), update the backing function
|
||||
if function.autocomplete.string != string_before {
|
||||
function.sync_from_autocomplete();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if movement != Movement::Complete
|
||||
&& let Some(hints) = function.autocomplete.hint.many()
|
||||
{
|
||||
@@ -153,6 +154,9 @@ impl FunctionManager {
|
||||
function
|
||||
.autocomplete
|
||||
.apply_hint(hints[function.autocomplete.i]);
|
||||
// Update the backing function with the new string after hint was applied
|
||||
function.sync_from_autocomplete();
|
||||
changed = true;
|
||||
|
||||
movement = Movement::Complete;
|
||||
} else {
|
||||
@@ -230,11 +234,10 @@ impl FunctionManager {
|
||||
// Remove function if the user requests it
|
||||
if let Some(remove_i_unwrap) = remove_i {
|
||||
self.functions.remove(remove_i_unwrap);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
let final_hash = self.get_hash();
|
||||
|
||||
initial_hash != final_hash
|
||||
changed
|
||||
}
|
||||
|
||||
/// Create and push new empty function entry
|
||||
|
||||
108
src/lib.rs
108
src/lib.rs
@@ -17,59 +17,71 @@ pub use crate::{
|
||||
unicode_helper::{to_chars_array, to_unicode_hash},
|
||||
};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "wasm32")] {
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::HtmlCanvasElement;
|
||||
// WASM-specific setup
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod wasm {
|
||||
use super::math_app;
|
||||
use eframe::WebRunner;
|
||||
use lol_alloc::{FreeListAllocator, LockedAllocator};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use web_sys::HtmlCanvasElement;
|
||||
|
||||
use lol_alloc::{FreeListAllocator, LockedAllocator};
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: LockedAllocator<FreeListAllocator> = LockedAllocator::new(FreeListAllocator::new());
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: LockedAllocator<FreeListAllocator> =
|
||||
LockedAllocator::new(FreeListAllocator::new());
|
||||
|
||||
use eframe::WebRunner;
|
||||
// use tracing::metadata::LevelFilter;
|
||||
#[derive(Clone)]
|
||||
#[wasm_bindgen]
|
||||
pub struct WebHandle {
|
||||
runner: WebRunner,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
#[wasm_bindgen]
|
||||
pub struct WebHandle {
|
||||
runner: WebRunner,
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
impl WebHandle {
|
||||
/// Installs a panic hook, then returns.
|
||||
#[allow(clippy::new_without_default)]
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
// eframe::WebLogger::init(LevelFilter::Debug).ok();
|
||||
tracing_wasm::set_as_global_default();
|
||||
|
||||
Self {
|
||||
runner: WebRunner::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Call this once from JavaScript to start your app.
|
||||
#[wasm_bindgen]
|
||||
pub async fn start(&self, canvas_id: HtmlCanvasElement) -> Result<(), wasm_bindgen::JsValue> {
|
||||
self.runner
|
||||
.start(
|
||||
canvas_id,
|
||||
eframe::WebOptions::default(),
|
||||
Box::new(|cc| Ok(Box::new(math_app::MathApp::new(cc)))),
|
||||
)
|
||||
.await
|
||||
}
|
||||
#[wasm_bindgen]
|
||||
impl WebHandle {
|
||||
/// Installs a panic hook, then returns.
|
||||
#[allow(clippy::new_without_default)]
|
||||
#[wasm_bindgen(constructor)]
|
||||
pub fn new() -> Self {
|
||||
tracing_wasm::set_as_global_default();
|
||||
Self {
|
||||
runner: WebRunner::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(start)]
|
||||
pub async fn start() {
|
||||
tracing::info!("Starting...");
|
||||
|
||||
let document = web_sys::window().unwrap().document().unwrap();
|
||||
let canvas = document.get_element_by_id("canvas").unwrap().dyn_into::<HtmlCanvasElement>().unwrap();
|
||||
|
||||
let web_handle = WebHandle::new();
|
||||
web_handle.start(canvas).await.unwrap()
|
||||
/// Call this once from JavaScript to start your app.
|
||||
#[wasm_bindgen]
|
||||
pub async fn start(
|
||||
&self,
|
||||
canvas_id: HtmlCanvasElement,
|
||||
) -> Result<(), wasm_bindgen::JsValue> {
|
||||
self.runner
|
||||
.start(
|
||||
canvas_id,
|
||||
eframe::WebOptions::default(),
|
||||
Box::new(|cc| Ok(Box::new(math_app::MathApp::new(cc)))),
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen(start)]
|
||||
pub async fn start() {
|
||||
tracing::info!("Starting...");
|
||||
|
||||
let document = web_sys::window()
|
||||
.expect("no window")
|
||||
.document()
|
||||
.expect("no document");
|
||||
let canvas = document
|
||||
.get_element_by_id("canvas")
|
||||
.expect("no canvas element")
|
||||
.dyn_into::<HtmlCanvasElement>()
|
||||
.expect("canvas is not an HtmlCanvasElement");
|
||||
|
||||
let web_handle = WebHandle::new();
|
||||
web_handle
|
||||
.start(canvas)
|
||||
.await
|
||||
.expect("failed to start web app");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,60 +124,48 @@ const DATA_NAME: &str = "YTBN-DECOMPRESSED";
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
const FUNC_NAME: &str = "YTBN-FUNCTIONS";
|
||||
|
||||
/// Load functions from localStorage (WASM only)
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn load_functions() -> Option<FunctionManager> {
|
||||
let data = get_localstorage().get_item(FUNC_NAME).ok()??;
|
||||
let func_data = crate::misc::hashed_storage_read(&data)?;
|
||||
|
||||
tracing::info!("Reading previous function data");
|
||||
match bincode::deserialize(&func_data) {
|
||||
Ok(Some(function_manager)) => Some(function_manager),
|
||||
_ => {
|
||||
tracing::info!("Unable to load functionManager instance");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decompress_fonts() -> epaint::text::FontDefinitions {
|
||||
let mut data = Vec::new();
|
||||
ruzstd::decoding::StreamingDecoder::new(
|
||||
const { include_bytes!(concat!(env!("OUT_DIR"), "/compressed_data")).as_slice() },
|
||||
)
|
||||
.expect("unable to decode compressed data")
|
||||
.read_to_end(&mut data)
|
||||
.expect("unable to read compressed data");
|
||||
|
||||
bincode::deserialize(data.as_slice()).expect("unable to deserialize bincode")
|
||||
}
|
||||
|
||||
impl MathApp {
|
||||
#[allow(dead_code)] // This is used lol
|
||||
/// Create new instance of [`MathApp`] and return it
|
||||
pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
tracing::info!("Initializing...");
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_arch = "wasm32")] {
|
||||
|
||||
tracing::info!("Web Info: {:?}", &cc.integration_info.web_info);
|
||||
|
||||
fn load_functions() -> Option<FunctionManager> {
|
||||
let data = get_localstorage().get_item(FUNC_NAME).ok()??;
|
||||
let func_data = crate::misc::hashed_storage_read(&data)?;
|
||||
|
||||
|
||||
tracing::info!("Reading previous function data");
|
||||
if let Ok(Some(function_manager)) = bincode::deserialize(&func_data) {
|
||||
return Some(function_manager);
|
||||
} else {
|
||||
tracing::info!("Unable to load functionManager instance");
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn decompress_fonts() -> epaint::text::FontDefinitions {
|
||||
let mut data = Vec::new();
|
||||
let _ =
|
||||
ruzstd::decoding::StreamingDecoder::new(
|
||||
&mut const {
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/compressed_data")).as_slice()
|
||||
},
|
||||
)
|
||||
.expect("unable to decode compressed data")
|
||||
.read_to_end(&mut data)
|
||||
.expect("unable to read compressed data");
|
||||
|
||||
bincode::deserialize(data.as_slice()).expect("unable to deserialize bincode")
|
||||
}
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
tracing::info!("Web Info: {:?}", &cc.integration_info.web_info);
|
||||
|
||||
tracing::info!("Reading fonts...");
|
||||
|
||||
// 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({ decompress_fonts() });
|
||||
|
||||
// Set dark mode by default
|
||||
// cc.egui_ctx.set_visuals(crate::style::style());
|
||||
|
||||
// Set spacing
|
||||
// cc.egui_ctx.set_spacing(crate::style::SPACING);
|
||||
cc.egui_ctx.set_fonts(decompress_fonts());
|
||||
|
||||
tracing::info!("Initialized!");
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ fn do_test(sum: Riemann, area_target: f64) {
|
||||
{
|
||||
function.update_string("sin(x)");
|
||||
assert!(function.get_test_result().is_none());
|
||||
assert_eq!(&function.raw_func_str, "sin(x)");
|
||||
assert_eq!(function.func_str(), "sin(x)");
|
||||
|
||||
function.integral = false;
|
||||
function.derivative = false;
|
||||
|
||||
Reference in New Issue
Block a user