diff options
| -rw-r--r-- | Cargo.lock | 74 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/eval.rs | 178 | ||||
| -rw-r--r-- | src/main.rs | 48 | ||||
| -rw-r--r-- | src/parser.rs | 3 |
5 files changed, 77 insertions, 227 deletions
@@ -469,79 +469,6 @@ dependencies = [ ] [[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" -dependencies = [ - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] name = "pango" version = "0.19.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -614,7 +541,6 @@ dependencies = [ "async-channel", "gdk4", "gtk4", - "num", ] [[package]] @@ -10,4 +10,3 @@ license = "GPL3" async-channel = "2.3.1" gdk4 = "0.8.2" gtk4 = "0.8.2" -num = "0.4.3" diff --git a/src/eval.rs b/src/eval.rs index 1045b17..c11614d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,13 +1,12 @@ -use num::pow::Pow; -use num::{BigInt, FromPrimitive, Integer, Signed, ToPrimitive}; use std::fmt::{Display, Formatter}; +#[derive(Clone, Copy)] pub enum Num { - Int(BigInt), + Int(i64), Float(f64), } -pub fn int(i: BigInt) -> Num { +pub fn int(i: i64) -> Num { Num::Int(i) } @@ -15,43 +14,45 @@ pub fn float(f: f64) -> Num { Num::Float(f) } -fn float_from_int(i: &BigInt) -> f64 { - if let Some(f) = i.to_f64() { - return f; - } - if i > &BigInt::ZERO { - std::f64::INFINITY - } else { - std::f64::NEG_INFINITY - } -} - impl Num { - fn as_float(&self) -> f64 { + fn as_float(self) -> f64 { match self { - Num::Int(i) => float_from_int(i), - Num::Float(f) => *f, + Num::Int(i) => i as f64, + Num::Float(f) => f, } } pub fn pow(self, other: Num) -> Num { match (self, other) { + (_, Num::Int(0)) => return int(1), + (Num::Int(-1), Num::Int(i2)) => { + if i2 % 2 == 0 { + return int(1); + } else { + return int(-1); + } + } + (Num::Int(0), _) => return int(0), + (Num::Int(1), _) => return int(1), (Num::Int(i1), Num::Int(i2)) => { - if i2 < BigInt::ZERO { - return float(float_from_int(&i1).powf(float_from_int(&i2))); + if let Ok(u) = u32::try_from(i2) { + if let Some(p) = i1.checked_pow(u) { + return int(p); + } } - let (_, u2) = i2.into_parts(); - int(i1.pow(u2)) } - (n1, n2) => float(n1.as_float().powf(n2.as_float())), + _ => (), } + float(self.as_float().powf(other.as_float())) } pub fn mul(self, other: Num) -> Num { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1 * i2), - (n1, n2) => float(n1.as_float() * n2.as_float()), + if let (Num::Int(i1), Num::Int(i2)) = (self, other) { + if let Some(p) = i1.checked_mul(i2) { + return int(p); + } } + float(self.as_float() * other.as_float()) } pub fn div(self, other: Num) -> Num { @@ -59,57 +60,48 @@ impl Num { } pub fn int_div(self, other: Num) -> Num { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1 / i2), - (Num::Float(f1), Num::Float(f2)) => { - let r = f1 / f2; - if let Some(i) = BigInt::from_f64(r) { - return int(i); - } - float(r) - } - (Num::Int(i), Num::Float(f)) => { - if let Some(fi) = BigInt::from_f64(f) { - return int(i / fi); - } - float(float_from_int(&i) / f) - } - (Num::Float(f), Num::Int(i)) => { - if let Some(fi) = BigInt::from_f64(f) { - return int(fi / i); - } - float(f / float_from_int(&i)) + if let (Num::Int(i1), Num::Int(i2)) = (self, other) { + if let Some(q) = i1.checked_div(i2) { + return int(q); } } + int((self.as_float() / other.as_float()) as i64) } pub fn modulo(self, other: Num) -> Num { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1.mod_floor(&i2)), - (n1, n2) => { - let n1 = n1.as_float(); - let n2 = n2.as_float(); - let r = n1 % n2; - if r < 0. { - return float(r + n2); + if let (Num::Int(i1), Num::Int(i2)) = (self, other) { + if let Some(r) = i1.checked_rem(i2) { + if i2 > 0 && r < 0 || i2 < 0 && r > 0 { + return int(r + i2); } - float(r) + return int(r); } } + let n1 = self.as_float(); + let n2 = other.as_float(); + let r = n1 % n2; + if n2 > 0. && r < 0. || n2 < 0. && r > 0. { + return float(r + n2); + } + float(r) } pub fn add(self, other: Num) -> Num { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1 + i2), - (n1, n2) => float(n1.as_float() + n2.as_float()), + if let (Num::Int(i1), Num::Int(i2)) = (self, other) { + if let Some(s) = i1.checked_add(i2) { + return int(s); + } } + float(self.as_float() + other.as_float()) } pub fn sub(self, other: Num) -> Num { - match (self, other) { - (Num::Int(i1), Num::Int(i2)) => int(i1 - i2), - (n1, n2) => Num::Float(n1.as_float() - n2.as_float()), + if let (Num::Int(i1), Num::Int(i2)) = (self, other) { + if let Some(d) = i1.checked_sub(i2) { + return int(d); + } } + float(self.as_float() - other.as_float()) } pub fn sin(self) -> Num { @@ -126,15 +118,23 @@ impl Num { pub fn sqrt(self) -> Num { match self { - Num::Int(i) if i >= BigInt::ZERO => { - let s = i.sqrt(); - if i != &s * &s { - return float(float_from_int(&i).sqrt()); + Num::Int(i) if i >= 0 => { + if i <= 1 { + return int(i); + } + let mut x0 = i / 2; + let mut x1 = (x0 + i / x0) / 2; + while x1 < x0 { + x0 = x1; + x1 = (x0 + i / x0) / 2; + } + if x0 * x0 == i { + return int(x0); } - int(s) } - n => float(n.as_float().sqrt()), + _ => (), } + float(self.as_float().sqrt()) } pub fn log(self) -> Num { @@ -152,36 +152,21 @@ impl Num { pub fn floor(self) -> Num { match self { Num::Int(i) => int(i), - Num::Float(f) => { - if let Some(i) = BigInt::from_f64(f.floor()) { - return int(i); - } - float(f) - } + Num::Float(f) => int(f.floor() as i64), } } pub fn ceil(self) -> Num { match self { Num::Int(i) => int(i), - Num::Float(f) => { - if let Some(i) = BigInt::from_f64(f.ceil()) { - return int(i); - } - float(f) - } + Num::Float(f) => int(f.ceil() as i64), } } pub fn round(self) -> Num { match self { Num::Int(i) => int(i), - Num::Float(f) => { - if let Some(i) = BigInt::from_f64(f.round_ties_even()) { - return int(i); - } - float(f) - } + Num::Float(f) => int(f.round_ties_even() as i64), } } @@ -193,31 +178,12 @@ impl Num { } } -fn log10(n: &BigInt) -> u64 { - ((n.bits() - 1) as f64 / std::f64::consts::LOG2_10) as u64 -} - impl Display for Num { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { match self { - Num::Int(n) => { - if n.bits() < 100 { - return write!(f, "{n}"); - } - let len = log10(n) + 1; - let rounded = i64::try_from(n / BigInt::from(10).pow(len - 8)).unwrap(); - let rounded_str = format!("{rounded}"); - write!( - f, - "{}.{}e{}", - &rounded_str[..1], - &rounded_str[1..], - len - 8 + rounded_str.len() as u64 - 1 - ) - } + Num::Int(n) => write!(f, "{n}"), Num::Float(n) => { - let n = *n; - if !(-1e30..=1e30).contains(&n) { + if !(-1e30..=1e30).contains(n) { return write!(f, "{n:.7e}"); } let mut buf = format!("{n:.7}"); diff --git a/src/main.rs b/src/main.rs index 9fe62b3..8976e17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,17 +8,6 @@ use gtk4::prelude::{ ApplicationExt, ApplicationExtManual, EditableExt, GridExt, GtkWindowExt, WidgetExt, }; use gtk4::{glib, Application, ApplicationWindow, Entry, EventControllerKey, Grid}; -use std::sync::{Arc, Mutex}; - -fn send_mail<T>(m: &Mutex<Option<T>>, msg: T) { - let mut guard = m.lock().unwrap(); - *guard = Some(msg); -} - -fn get_mail<T>(m: &Mutex<Option<T>>) -> Option<T> { - let mut guard = m.lock().unwrap(); - std::mem::take(&mut guard) -} fn main() -> ExitCode { let app = Application::builder() @@ -40,51 +29,22 @@ fn main() -> ExitCode { let output = Entry::builder().editable(false).build(); grid.attach(&output, 0, 1, 1, 1); - let (ping_send, ping_recv) = async_channel::bounded(1); - let mailbox = Arc::new(Mutex::new(None)); - let key_controller = EventControllerKey::new(); key_controller.connect_key_released( - clone!(@weak window, @weak input, @strong mailbox => move |_, k, _, modifiers| { + clone!(@weak window, @weak input, @weak output => move |_, k, _, modifiers| { if k == Key::Escape || k == Key::Return || k == Key::bracketleft && modifiers.contains(ModifierType::CONTROL_MASK) { window.destroy(); } - send_mail(mailbox.as_ref(), format!("{}", input.text())); - let _ = ping_send.try_send(()); + if let Some(n) = parser::parse(&input.text()) { + output.set_text(&format!("{n}")); + } }), ); window.add_controller(key_controller); - glib::spawn_future_local(async move { - let mut prev_input = String::from(""); - loop { - if ping_recv.recv().await.is_err() { - break; - } - let Some(input) = get_mail(mailbox.as_ref()) else { - continue; - }; - if input == prev_input { - continue; - } - prev_input = input.clone(); - let (output_send, output_recv) = async_channel::bounded(1); - let thread_handle = gtk4::gio::spawn_blocking(move || { - if let Some(result) = parser::parse(&input) { - output_send.send_blocking(format!("{result}")).unwrap(); - } - }); - let _ = thread_handle.await; - let Ok(result) = output_recv.try_recv() else { - continue; - }; - output.set_text(&result); - } - }); - window.present(); }); diff --git a/src/parser.rs b/src/parser.rs index 2b33e0f..c0f3a9b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,6 @@ use crate::eval; use crate::eval::Num; use crate::lexer::Lexer; -use num::BigInt; use std::str::FromStr; enum Op { @@ -58,7 +57,7 @@ impl<'a> Parser<'a> { } return Some(eval::float(f)); } - let Ok(i) = BigInt::from_str(t) else { + let Ok(i) = i64::from_str(t) else { return None; }; if negative { |
