use crate::{rpn_resolver::RpnResolver, token::Number};
use num_bigint::BigInt;
use std::{cell::RefCell, collections::HashMap, rc::Rc};
pub struct Session {
variable_heap: Rc<RefCell<HashMap<String, Number>>>,
}
const BUILTIN_CONSTANTS: [&str; 5] = ["pi", "e", "tau", "phi", "gamma"];
impl Session {
#[must_use]
pub fn init() -> Session {
Session {
variable_heap: Rc::new(RefCell::new(Session::init_local_heap())),
}
}
#[must_use]
pub fn process<'a>(&'a self, line: &'a str) -> RpnResolver<'a> {
let clone = Rc::clone(&self.variable_heap); RpnResolver::parse_with_borrowed_heap(line, clone)
}
fn init_local_heap() -> HashMap<String, Number> {
let mut local_heap: HashMap<String, Number> = HashMap::new();
local_heap.insert(
"pi".to_string(),
Number::DecimalNumber(
num_rational::BigRational::from_float(std::f64::consts::PI).unwrap(),
),
);
local_heap.insert(
"e".to_string(),
Number::DecimalNumber(
num_rational::BigRational::from_float(std::f64::consts::E).unwrap(),
),
);
local_heap.insert(
"tau".to_string(),
Number::DecimalNumber(
num_rational::BigRational::from_float(std::f64::consts::TAU).unwrap(),
),
);
local_heap.insert(
"phi".to_string(),
Number::DecimalNumber(
num_rational::BigRational::from_float((1.0 + 5.0f64.sqrt()) / 2.0).unwrap(),
),
);
local_heap.insert(
"gamma".to_string(),
Number::DecimalNumber(
num_rational::BigRational::from_float(0.577_215_664_901_532_9_f64).unwrap(),
),
);
local_heap
}
pub(crate) fn is_constant_name(key: &str) -> bool {
BUILTIN_CONSTANTS.contains(&key)
}
pub fn set(&self, key: &str, value: i64) {
let key = key.to_lowercase();
if Self::is_constant_name(&key) {
return;
}
self.variable_heap
.borrow_mut()
.insert(key, Number::NaturalNumber(BigInt::from(value)));
}
pub fn setf(&self, key: &str, value: f64) {
let key = key.to_lowercase();
if Self::is_constant_name(&key) {
return;
}
if let Some(value) = num_rational::BigRational::from_float(value) {
self.variable_heap
.borrow_mut()
.insert(key, Number::DecimalNumber(value));
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::token::Number;
#[test]
fn test_session() {
let session = Session::init();
let mut resolver: RpnResolver = session.process("1+2*3/(4-5)");
assert_eq!(
resolver.resolve().unwrap(),
Number::DecimalNumber(num_rational::BigRational::from_float(-5.0).unwrap())
);
}
#[test]
fn test_session_set() {
let session = Session::init();
session.set("x", 4);
let mut resolver: RpnResolver = session.process("x+2*3/(4-5)");
assert_eq!(
resolver.resolve().unwrap(),
Number::DecimalNumber(num_rational::BigRational::from_float(-2.0).unwrap())
);
}
#[test]
fn test_session_setf() {
let session = Session::init();
session.setf("x", 4.5);
let mut resolver: RpnResolver = session.process("x+2*3/(4-5)");
assert_eq!(
resolver.resolve().unwrap(),
Number::DecimalNumber(num_rational::BigRational::from_float(-1.5).unwrap())
);
}
#[test]
fn test_session_default_vars() {
let session = Session::init();
let mut resolver: RpnResolver = session.process("pi + e");
assert_eq!(
resolver.resolve().unwrap(),
Number::DecimalNumber(
num_rational::BigRational::from_float(std::f64::consts::PI).unwrap()
+ num_rational::BigRational::from_float(std::f64::consts::E).unwrap()
)
);
}
#[test]
fn test_session_tau() {
let session = Session::init();
let mut resolver: RpnResolver = session.process("tau / 2");
assert_eq!(
resolver.resolve().unwrap(),
Number::DecimalNumber(
num_rational::BigRational::from_float(std::f64::consts::TAU / 2.0).unwrap(),
)
);
}
}