Skip to content

Commit

Permalink
Added history function. No support for using it as yet.
Browse files Browse the repository at this point in the history
  • Loading branch information
shartrec committed Jun 17, 2024
1 parent 59eb389 commit 80bfab5
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 4 deletions.
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ log = "^0.4"
palette = "^0.7.6"
preferences = "^1.1.0"
simplelog = "0.12.2"
serde = { version = "1.0.203", features = ["derive"] }
serde_json = "1.0.117"

[dependencies.iced]
git = "https://github.com/iced-rs/iced.git"
Expand Down
7 changes: 5 additions & 2 deletions src/evaluator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@

use std::fmt::{Debug, Display, Formatter};
use std::rc::Rc;
use std::time::{Instant, SystemTime};
use std::time::Instant;
use log::info;

use crate::evaluator::constants::Constant;
use crate::evaluator::functions::Function;
use crate::evaluator::parser::Parser;
use crate::evaluator::tokeniser::tokenize;
use crate::history;

mod functions;
pub(crate) mod parser;
Expand Down Expand Up @@ -172,7 +173,9 @@ impl<'a> Evaluator<'a> {
let ast = parser.parse()?;
Ok(ast.evaluate(&self.angle_mode))
})
.inspect(|_| {
.inspect(|result| {
history::manager().add((&expression, &result));
history::manager().save();
let duration = Instant::now().duration_since(t_start);
info!("Evaluated \"{}\" in {} micro seconds", expression.trim(), duration.as_micros());
})
Expand Down
120 changes: 120 additions & 0 deletions src/history.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2024.
*
* Copyright 2024 Trevor Campbell
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the “Software”), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
* OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/

use std::collections::VecDeque;
use std::fs::File;
use std::io::{self, Read, Write};
use std::path::PathBuf;
use std::sync::RwLock;

use lazy_static::lazy_static;
use log::warn;
use serde::{Deserialize, Serialize};

const HISTORY_FILE: &str = "rusty-calc-history.json";
const HISTORY_SIZE: usize = 100;

lazy_static! {
static ref HISTORY_MANAGER: HistoryManager = {
let mut contents = String::new();
let history = match File::open(HISTORY_FILE)
.and_then(|mut f| {
f.read_to_string(&mut contents)
})
{
Ok(_s) => {
serde_json::from_str(&contents).unwrap_or(History::new(HISTORY_SIZE))
}
Err(_e) => {
History::new(HISTORY_SIZE)
}
};

HistoryManager { history }
};
}

pub struct HistoryManager {
history: History,
}

impl HistoryManager {
fn save_to_file(&self, path: PathBuf) -> io::Result<()> {
let serialized = serde_json::to_string(&self.history)?;
let mut file = File::create(&path)?;
file.write_all(serialized.as_bytes())?;
Ok(())
}

pub fn save(&self) {
if let Some(path) = get_history_path() {
if let Err(e) = self.save_to_file(path) {
warn!("{}", e.to_string());
warn!("Failed to write history.")
}
}
}
pub fn add(&self, entry: (&str, &f64)) {
self.history.add(entry);
}

}

pub fn manager() -> &'static HistoryManager {
&HISTORY_MANAGER
}

fn get_history_path() -> Option<PathBuf> {
home::home_dir().map( |home_path| {
home_path.join(HISTORY_FILE)
})
}
#[derive(Serialize, Deserialize, Debug)]
struct History {
entries: RwLock<VecDeque<(String, f64)>>,
max_size: usize,
}

impl History {
fn new(max_size: usize) -> Self {
Self {
entries: RwLock::new(VecDeque::with_capacity(max_size)),
max_size,
}
}

fn add(&self, entry: (&str, &f64)) {
match self.entries.write() {
Ok(mut vec) => {
if vec.len() == self.max_size {
vec.pop_front();
}
let new_entry = (entry.0.to_string(), entry.1.clone());
vec.push_back(new_entry);
}
Err(_) => {
warn!("Failed to write history.")
}
}
}

}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ mod evaluator;
#[cfg(test)]
mod test;
mod ui;
pub(crate) mod history;

/// Calculate.
fn main() -> iced::Result {
Expand Down
4 changes: 2 additions & 2 deletions src/ui/calc_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,14 @@ impl CalcWindow {
Message::EditorAction(action) => {
match action {
Action::Edit(Edit::Enter) => {
self.result = Some(self.calc.evaluate(&self.content.text()))
self.result = Some(self.calc.evaluate(&self.content.text().trim()))
}
_ => self.content.perform(action)
}
Command::none()
}
Message::Evaluate => {
self.result = Some(self.calc.evaluate(&self.content.text()));
self.result = Some(self.calc.evaluate(&self.content.text().trim()));
Command::none()
}
Message::Clear => {
Expand Down

0 comments on commit 80bfab5

Please sign in to comment.