Started work on vectors

This commit is contained in:
Austen Adler 2021-06-01 21:59:56 -04:00
parent bfae3cafce
commit e05b0726f1
3 changed files with 520 additions and 182 deletions

View File

@ -186,6 +186,8 @@ impl Calculator {
CalculatorState::WaitingForSetting => self.setting_input(c), CalculatorState::WaitingForSetting => self.setting_input(c),
} }
} }
// This function is very long, but it is just a match, so it should be fine
#[allow(clippy::too_many_lines)]
fn normal_input(&mut self, c: char) -> CalculatorResult<()> { fn normal_input(&mut self, c: char) -> CalculatorResult<()> {
match c { match c {
c @ '0'..='9' | c @ '.' | c @ 'e' => match c { c @ '0'..='9' | c @ '.' | c @ 'e' => match c {
@ -194,11 +196,7 @@ impl Calculator {
Ok(()) Ok(())
} }
'e' => { 'e' => {
if self.l.is_empty() { self.edit()?;
let f = self.pop().or(Err(CalculatorError::NotEnoughStackEntries))?;
self.l = f.to_string();
}
if !self.l.contains('e') { if !self.l.contains('e') {
self.l.push('e'); self.l.push('e');
@ -437,10 +435,15 @@ impl Calculator {
return Ok(()); return Ok(());
} }
self.l = self // Temporary check to see if we can get an editable string
.pop() let str = self.peek(0)?.to_editable_string()?;
.or(Err(CalculatorError::NotEnoughStackEntries))?
.to_string(); // If we got here, then there was no error. Pop
self.pop()?;
// Set l after popping
self.l = str;
Ok(()) Ok(())
} }
/// Get the value of l /// Get the value of l

View File

@ -1,5 +1,5 @@
// use super::operations::CalculatorStateChange; // TODO: Clippy is recommending pass by value instead of by ref, but I plan to add imaginary numbers, which will change this
// TODO: This file kina blows. Tons of repetition. Do not know how to fix yet though #![allow(clippy::trivially_copy_pass_by_ref)]
use super::errors::{CalculatorError, CalculatorResult}; use super::errors::{CalculatorError, CalculatorResult};
use super::types::CalculatorAngleMode; use super::types::CalculatorAngleMode;
use crate::calc::CalculatorDisplayMode; use crate::calc::CalculatorDisplayMode;
@ -12,15 +12,6 @@ pub struct Number {
pub value: f64, pub value: f64,
} }
impl Number {
fn binary_op(arg: &Entry, op: impl Fn(&Number) -> Number) -> CalculatorResult<Entry> {
match arg {
Entry::Number(number) => Ok(Entry::Number(op(number))),
Entry::Vector(vector) => Ok(vector.map_into(op)),
}
}
}
impl PartialEq for Number { impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
if self.value.is_nan() && other.value.is_nan() if self.value.is_nan() && other.value.is_nan()
@ -45,41 +36,6 @@ pub struct Vector {
pub values: Vec<Number>, pub values: Vec<Number>,
} }
impl Vector {
fn binary_op(
&self,
arg: &Entry,
op: impl Fn((&Number, &Number)) -> Number,
) -> CalculatorResult<Entry> {
match arg {
// Entry::Number(number) => Ok(Entry::Number(op(number))),
Entry::Number(number) => Ok(self.map_into(|t| op((t, number)))),
Entry::Vector(vector) => {
if self.values.len() != vector.values.len() {
return Err(CalculatorError::ArithmeticError);
}
Ok(Entry::Vector(Vector {
values: self
.values
.iter()
.zip(vector.values.iter())
.map(op)
.collect(),
..*self
}))
}
}
}
pub fn map_into(&self, op: impl Fn(&Number) -> Number) -> Entry {
Entry::Vector(Vector {
values: (self.values.iter().map(op).collect()),
..*self
})
}
}
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)] #[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
#[serde(tag = "type")] #[serde(tag = "type")]
pub enum Entry { pub enum Entry {
@ -88,7 +44,28 @@ pub enum Entry {
// Matrix(Vec<Vec<Number>>), // Matrix(Vec<Vec<Number>>),
} }
// macro_rules! op_child_call {
// ($a:ident, $op:ident) => {
// match $a {
// Self::Number(number) => number.$op(),
// Self::Vector(vector) => vector.$op(),
// }
// };
// ($a:ident, $op:ident, $arg:expr) => {
// match $a {
// Self::Number(number) => number.$op($arg),
// Self::Vector(vector) => vector.$op($arg),
// }
// };
// }
impl CalculatorEntry for Entry { impl CalculatorEntry for Entry {
fn to_editable_string(&self) -> CalculatorResult<String> {
match self {
Self::Number(number) => number.to_editable_string(),
Self::Vector(vector) => vector.to_editable_string(),
}
}
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
match self { match self {
Self::Number(number) => number.format_entry(display_mode), Self::Number(number) => number.format_entry(display_mode),
@ -101,36 +78,6 @@ impl CalculatorEntry for Entry {
Self::Vector(vector) => vector.is_valid(), Self::Vector(vector) => vector.is_valid(),
} }
} }
fn add(&self, arg: &Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.add(arg),
Self::Vector(vector) => vector.add(arg),
}
}
fn sub(&self, arg: &Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.sub(arg),
Self::Vector(vector) => vector.sub(arg),
}
}
fn mul(&self, arg: &Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.mul(arg),
Self::Vector(vector) => vector.mul(arg),
}
}
fn div(&self, arg: &Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.div(arg),
Self::Vector(vector) => vector.div(arg),
}
}
fn int_divide(&self, arg: &Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.int_divide(arg),
Self::Vector(vector) => vector.int_divide(arg),
}
}
fn negate(&self) -> CalculatorResult<Self> { fn negate(&self) -> CalculatorResult<Self> {
match self { match self {
Self::Number(number) => number.negate(), Self::Number(number) => number.negate(),
@ -149,12 +96,6 @@ impl CalculatorEntry for Entry {
Self::Vector(vector) => vector.inverse(), Self::Vector(vector) => vector.inverse(),
} }
} }
fn modulo(&self, arg: &Self) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.modulo(arg),
Self::Vector(vector) => vector.modulo(arg),
}
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> { fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Self> {
match self { match self {
Self::Number(number) => number.sin(angle_mode), Self::Number(number) => number.sin(angle_mode),
@ -209,15 +150,141 @@ impl CalculatorEntry for Entry {
Self::Vector(vector) => vector.ln(), Self::Vector(vector) => vector.ln(),
} }
} }
fn add(&self, arg: &Self) -> CalculatorResult<Self> {
match arg {
Self::Number(number) => self.add_num(number),
Self::Vector(vector) => self.add_vec(vector),
}
}
fn sub(&self, arg: &Self) -> CalculatorResult<Self> {
match arg {
Self::Number(number) => self.sub_num(number),
Self::Vector(vector) => self.sub_vec(vector),
}
}
fn mul(&self, arg: &Self) -> CalculatorResult<Self> {
match arg {
Self::Number(number) => self.mul_num(number),
Self::Vector(vector) => self.mul_vec(vector),
}
}
fn div(&self, arg: &Self) -> CalculatorResult<Self> {
match arg {
Self::Number(number) => self.div_num(number),
Self::Vector(vector) => self.div_vec(vector),
}
}
fn int_divide(&self, arg: &Self) -> CalculatorResult<Self> {
match arg {
Self::Number(number) => self.int_divide_num(number),
Self::Vector(vector) => self.int_divide_vec(vector),
}
}
fn modulo(&self, arg: &Self) -> CalculatorResult<Self> {
match arg {
Self::Number(number) => self.modulo_num(number),
Self::Vector(vector) => self.modulo_vec(vector),
}
}
fn pow(&self, arg: &Self) -> CalculatorResult<Self> { fn pow(&self, arg: &Self) -> CalculatorResult<Self> {
match arg {
Self::Number(number) => self.pow_num(number),
Self::Vector(vector) => self.pow_vec(vector),
}
}
fn add_vec(&self, arg: &Vector) -> CalculatorResult<Self> {
match self { match self {
Self::Number(number) => number.pow(arg), Self::Number(number) => number.add_vec(arg),
Self::Vector(vector) => vector.pow(arg), Self::Vector(vector) => vector.add_vec(arg),
}
}
fn sub_vec(&self, arg: &Vector) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.sub_vec(arg),
Self::Vector(vector) => vector.sub_vec(arg),
}
}
fn mul_vec(&self, arg: &Vector) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.mul_vec(arg),
Self::Vector(vector) => vector.mul_vec(arg),
}
}
fn div_vec(&self, arg: &Vector) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.div_vec(arg),
Self::Vector(vector) => vector.div_vec(arg),
}
}
fn int_divide_vec(&self, arg: &Vector) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.int_divide_vec(arg),
Self::Vector(vector) => vector.int_divide_vec(arg),
}
}
fn modulo_vec(&self, arg: &Vector) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.modulo_vec(arg),
Self::Vector(vector) => vector.modulo_vec(arg),
}
}
fn pow_vec(&self, arg: &Vector) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.pow_vec(arg),
Self::Vector(vector) => vector.pow_vec(arg),
}
}
fn add_num(&self, arg: &Number) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.add_num(arg),
Self::Vector(vector) => vector.add_num(arg),
}
}
fn sub_num(&self, arg: &Number) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.sub_num(arg),
Self::Vector(vector) => vector.sub_num(arg),
}
}
fn mul_num(&self, arg: &Number) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.mul_num(arg),
Self::Vector(vector) => vector.mul_num(arg),
}
}
fn div_num(&self, arg: &Number) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.div_num(arg),
Self::Vector(vector) => vector.div_num(arg),
}
}
fn int_divide_num(&self, arg: &Number) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.int_divide_num(arg),
Self::Vector(vector) => vector.int_divide_num(arg),
}
}
fn modulo_num(&self, arg: &Number) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.modulo_num(arg),
Self::Vector(vector) => vector.modulo_num(arg),
}
}
fn pow_num(&self, arg: &Number) -> CalculatorResult<Self> {
match self {
Self::Number(number) => number.pow_num(arg),
Self::Vector(vector) => vector.pow_num(arg),
} }
} }
} }
impl CalculatorEntry for Number { impl CalculatorEntry for Number {
fn to_editable_string(&self) -> CalculatorResult<String> {
Ok(format!("{}", self.value))
}
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
match display_mode { match display_mode {
CalculatorDisplayMode::Default => format!("{}", self.value), CalculatorDisplayMode::Default => format!("{}", self.value),
@ -232,31 +299,6 @@ impl CalculatorEntry for Number {
fn is_valid(&self) -> bool { fn is_valid(&self) -> bool {
!self.value.is_nan() && !self.value.is_infinite() !self.value.is_nan() && !self.value.is_infinite()
} }
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
Number::binary_op(&arg, |b| Self {
value: b.value + self.value,
})
}
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
Number::binary_op(&arg, |b| Self {
value: b.value - self.value,
})
}
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
Number::binary_op(&arg, |b| Self {
value: b.value * self.value,
})
}
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
Number::binary_op(&arg, |b| Self {
value: b.value / self.value,
})
}
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
Number::binary_op(&arg, |b| Self {
value: b.value.div_euclid(self.value),
})
}
fn negate(&self) -> CalculatorResult<Entry> { fn negate(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self { value: -self.value })) Ok(Entry::Number(Self { value: -self.value }))
} }
@ -270,11 +312,6 @@ impl CalculatorEntry for Number {
value: self.value.recip(), value: self.value.recip(),
})) }))
} }
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
Number::binary_op(&arg, |b| Self {
value: b.value % self.value,
})
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self { Ok(Entry::Number(Self {
value: match angle_mode { value: match angle_mode {
@ -344,21 +381,142 @@ impl CalculatorEntry for Number {
value: self.value.ln(), value: self.value.ln(),
})) }))
} }
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.add_vec(vector),
Entry::Number(number) => self.add_num(number),
}
}
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.sub_vec(vector),
Entry::Number(number) => self.sub_num(number),
}
}
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.mul_vec(vector),
Entry::Number(number) => self.mul_num(number),
}
}
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.div_vec(vector),
Entry::Number(number) => self.div_num(number),
}
}
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.int_divide_vec(vector),
Entry::Number(number) => self.int_divide_num(number),
}
}
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.modulo_vec(vector),
Entry::Number(number) => self.modulo_num(number),
}
}
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> { fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
Number::binary_op(&arg, |b| Self { match arg {
value: b.value.powf(self.value), Entry::Vector(vector) => self.pow_vec(vector),
Entry::Number(number) => self.pow_num(number),
}
}
fn add_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
self.iterated_binary(arg, Self::add_num)
}
fn sub_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
self.iterated_binary(arg, Self::sub_num)
}
fn mul_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
self.iterated_binary(arg, Self::mul_num)
}
fn div_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
self.iterated_binary(arg, Self::div_num)
}
fn int_divide_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
self.iterated_binary(arg, Self::int_divide_num)
}
fn modulo_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
self.iterated_binary(arg, Self::modulo_num)
}
fn pow_vec(&self, arg: &Vector) -> CalculatorResult<Entry> {
self.iterated_binary(arg, Self::pow_num)
}
fn add_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: arg.value + self.value,
}))
}
fn sub_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: arg.value - self.value,
}))
}
fn mul_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: arg.value * self.value,
}))
}
fn div_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: arg.value / self.value,
}))
}
fn int_divide_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: arg.value.div_euclid(self.value),
}))
}
fn modulo_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: arg.value % self.value,
}))
}
fn pow_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: arg.value.powf(self.value),
}))
}
}
impl Number {
fn iterated_binary(
self,
vector: &Vector,
op: impl Fn(&Self, &Self) -> CalculatorResult<Entry>,
) -> CalculatorResult<Entry> {
Ok(Entry::Vector(Vector {
values: vector
.values
.iter()
.map(|n| op(&self, n))
.map(|e| match e {
// Only numbers are valid in a vector
Ok(Entry::Number(number)) => Ok(number),
_ => Err(CalculatorError::ArithmeticError),
}) })
.collect::<CalculatorResult<Vec<Self>>>()?,
direction: vector.direction,
}))
} }
} }
impl CalculatorEntry for Vector { impl CalculatorEntry for Vector {
// Misc // Misc
fn to_editable_string(&self) -> CalculatorResult<String> {
// TODO: Eventualy we can parse and edit a vector as a string
Err(CalculatorError::TypeMismatch)
}
fn is_valid(&self) -> bool { fn is_valid(&self) -> bool {
!self self.values
.values
.iter() .iter()
.find(|number| !number.is_valid()) .find(|number| !number.is_valid())
.is_some() .is_none()
} }
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
format!( format!(
@ -371,80 +529,237 @@ impl CalculatorEntry for Vector {
) )
} }
// Mathematical operations // Mathematical operations
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value + a.value,
})
}
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value - a.value,
})
}
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value * a.value,
})
}
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value / a.value,
})
}
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number {
value: b.value.div_euclid(a.value),
})
}
fn negate(&self) -> CalculatorResult<Entry> { fn negate(&self) -> CalculatorResult<Entry> {
Ok(self.map_into(|n| Number { value: -n.value })) self.iterated_unary(Number::negate)
} }
fn abs(&self) -> CalculatorResult<Entry> { fn abs(&self) -> CalculatorResult<Entry> {
Ok(self.map_into(|n| Number { self.iterated_unary(Number::abs)
value: n.value.abs(),
}))
} }
fn inverse(&self) -> CalculatorResult<Entry> { fn inverse(&self) -> CalculatorResult<Entry> {
Ok(Entry::Vector(Vector { self.iterated_unary(Number::inverse)
direction: !self.direction, }
..*self fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
})) self.iterated_unary(|n| n.sin(angle_mode))
}
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.cos(angle_mode))
}
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.tan(angle_mode))
}
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.asin(angle_mode))
}
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.acos(angle_mode))
}
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.atan(angle_mode))
}
fn sqrt(&self) -> CalculatorResult<Entry> {
self.iterated_unary(Number::sqrt)
}
fn log(&self) -> CalculatorResult<Entry> {
self.iterated_unary(Number::log)
}
fn ln(&self) -> CalculatorResult<Entry> {
self.iterated_unary(Number::ln)
}
fn add(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.add_vec(vector),
Entry::Number(number) => self.add_num(number),
}
}
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.sub_vec(vector),
Entry::Number(number) => self.sub_num(number),
}
}
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.mul_vec(vector),
Entry::Number(number) => self.mul_num(number),
}
}
fn div(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.div_vec(vector),
Entry::Number(number) => self.div_num(number),
}
}
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry> {
match arg {
Entry::Vector(vector) => self.int_divide_vec(vector),
Entry::Number(number) => self.int_divide_num(number),
}
} }
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> { fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number { match arg {
value: b.value % a.value, Entry::Vector(vector) => self.modulo_vec(vector),
}) Entry::Number(number) => self.modulo_num(number),
}
} }
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {}
fn sqrt(&self) -> CalculatorResult<Entry> {}
fn log(&self) -> CalculatorResult<Entry> {}
fn ln(&self) -> CalculatorResult<Entry> {}
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> { fn pow(&self, arg: &Entry) -> CalculatorResult<Entry> {
self.binary_op(&arg, |(a, b)| Number { match arg {
value: b.value.powf(a.value), Entry::Vector(vector) => self.pow_vec(vector),
}) Entry::Number(number) => self.pow_num(number),
} }
} }
pub trait CalculatorEntry { fn add_vec(&self, arg: &Self) -> CalculatorResult<Entry> {
self.iterated_binary_vec(arg, Number::add_num)
}
fn sub_vec(&self, arg: &Self) -> CalculatorResult<Entry> {
self.iterated_binary_vec(arg, Number::sub_num)
}
fn mul_vec(&self, arg: &Self) -> CalculatorResult<Entry> {
self.iterated_binary_vec(arg, Number::mul_num)
}
fn div_vec(&self, arg: &Self) -> CalculatorResult<Entry> {
self.iterated_binary_vec(arg, Number::div_num)
}
fn int_divide_vec(&self, arg: &Self) -> CalculatorResult<Entry> {
self.iterated_binary_vec(arg, Number::int_divide_num)
}
fn modulo_vec(&self, arg: &Self) -> CalculatorResult<Entry> {
self.iterated_binary_vec(arg, Number::modulo_num)
}
fn pow_vec(&self, arg: &Self) -> CalculatorResult<Entry> {
self.iterated_binary_vec(arg, Number::pow_num)
}
fn add_num(&self, arg: &Number) -> CalculatorResult<Entry> {
self.iterated_binary_num(arg, Number::add_num)
}
fn sub_num(&self, arg: &Number) -> CalculatorResult<Entry> {
self.iterated_binary_num(arg, Number::sub_num)
}
fn mul_num(&self, arg: &Number) -> CalculatorResult<Entry> {
self.iterated_binary_num(arg, Number::mul_num)
}
fn div_num(&self, arg: &Number) -> CalculatorResult<Entry> {
self.iterated_binary_num(arg, Number::div_num)
}
fn int_divide_num(&self, arg: &Number) -> CalculatorResult<Entry> {
self.iterated_binary_num(arg, Number::int_divide_num)
}
fn modulo_num(&self, arg: &Number) -> CalculatorResult<Entry> {
self.iterated_binary_num(arg, Number::modulo_num)
}
fn pow_num(&self, arg: &Number) -> CalculatorResult<Entry> {
self.iterated_binary_num(arg, Number::pow_num)
}
}
impl Vector {
fn iterated_unary(
&self,
op: impl Fn(&Number) -> CalculatorResult<Entry>,
) -> CalculatorResult<Entry> {
Ok(Entry::Vector(Self {
values: self
.values
.iter()
.map(|n| op(n))
.map(|e| match e {
// Only numbers are valid in a vector
Ok(Entry::Number(number)) => Ok(number),
_ => Err(CalculatorError::ArithmeticError),
})
.collect::<CalculatorResult<Vec<Number>>>()?,
direction: true,
}))
}
fn iterated_binary_vec(
&self,
v2: &Self,
op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>,
) -> CalculatorResult<Entry> {
if self.values.len() != v2.values.len() {
return Err(CalculatorError::ArithmeticError);
}
if self.direction != v2.direction {
// TODO: Return a different error
return Err(CalculatorError::ArithmeticError);
}
Ok(Entry::Vector(Self {
values: self
.values
.iter()
.zip(v2.values.iter())
.map(|(n1, n2)| op(n1, n2))
.map(|e| match e {
// Only numbers are valid in a vector
Ok(Entry::Number(number)) => Ok(number),
_ => Err(CalculatorError::ArithmeticError),
})
.collect::<CalculatorResult<Vec<Number>>>()?,
direction: true,
}))
}
fn iterated_binary_num(
&self,
n2: &Number,
op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>,
) -> CalculatorResult<Entry> {
Ok(Entry::Vector(Self {
values: self
.values
.iter()
.map(|n| op(n, n2))
.map(|e| match e {
// Only numbers are valid in a vector
Ok(Entry::Number(number)) => Ok(number),
_ => Err(CalculatorError::ArithmeticError),
})
.collect::<CalculatorResult<Vec<Number>>>()?,
direction: true,
}))
}
}
pub trait CalculatorEntry
where
Self: Sized,
{
// Misc // Misc
fn is_valid(&self) -> bool; fn is_valid(&self) -> bool;
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String; fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String;
fn to_editable_string(&self) -> CalculatorResult<String>;
// Mathematical operations // Mathematical operations
// Binary
fn add(&self, arg: &Entry) -> CalculatorResult<Entry>; fn add(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn sub(&self, arg: &Entry) -> CalculatorResult<Entry>; fn sub(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn mul(&self, arg: &Entry) -> CalculatorResult<Entry>; fn mul(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn div(&self, arg: &Entry) -> CalculatorResult<Entry>; fn div(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry>; fn int_divide(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn add_vec(&self, arg: &Vector) -> CalculatorResult<Entry>;
fn sub_vec(&self, arg: &Vector) -> CalculatorResult<Entry>;
fn mul_vec(&self, arg: &Vector) -> CalculatorResult<Entry>;
fn div_vec(&self, arg: &Vector) -> CalculatorResult<Entry>;
fn int_divide_vec(&self, arg: &Vector) -> CalculatorResult<Entry>;
fn modulo_vec(&self, arg: &Vector) -> CalculatorResult<Entry>;
fn pow_vec(&self, arg: &Vector) -> CalculatorResult<Entry>;
fn add_num(&self, arg: &Number) -> CalculatorResult<Entry>;
fn sub_num(&self, arg: &Number) -> CalculatorResult<Entry>;
fn mul_num(&self, arg: &Number) -> CalculatorResult<Entry>;
fn div_num(&self, arg: &Number) -> CalculatorResult<Entry>;
fn int_divide_num(&self, arg: &Number) -> CalculatorResult<Entry>;
fn modulo_num(&self, arg: &Number) -> CalculatorResult<Entry>;
fn pow_num(&self, arg: &Number) -> CalculatorResult<Entry>;
// Unary
fn negate(&self) -> CalculatorResult<Entry>; fn negate(&self) -> CalculatorResult<Entry>;
fn abs(&self) -> CalculatorResult<Entry>; fn abs(&self) -> CalculatorResult<Entry>;
fn inverse(&self) -> CalculatorResult<Entry>; fn inverse(&self) -> CalculatorResult<Entry>;
fn modulo(&self, arg: &Entry) -> CalculatorResult<Entry>;
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>; fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>; fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>; fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry>;
@ -454,13 +769,13 @@ pub trait CalculatorEntry {
fn sqrt(&self) -> CalculatorResult<Entry>; fn sqrt(&self) -> CalculatorResult<Entry>;
fn log(&self) -> CalculatorResult<Entry>; fn log(&self) -> CalculatorResult<Entry>;
fn ln(&self) -> CalculatorResult<Entry>; fn ln(&self) -> CalculatorResult<Entry>;
fn pow(&self, arg: &Entry) -> CalculatorResult<Entry>;
} }
impl fmt::Display for Entry { impl fmt::Display for Entry {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Self::Number(Number { value }) => write!(f, "{}", value), Self::Number(number) => write!(f, "{}", number),
Self::Vector(vector) => write!(f, "{}", vector),
} }
} }
} }
@ -471,6 +786,20 @@ impl fmt::Display for Number {
} }
} }
impl fmt::Display for Vector {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"[{}]",
self.values
.iter()
.map(|number| format!("{}", number))
.collect::<Vec<String>>()
.join("; ")
)
}
}
// Based on https://stackoverflow.com/a/65266882 // Based on https://stackoverflow.com/a/65266882
fn scientific(f: f64, precision: usize) -> String { fn scientific(f: f64, precision: usize) -> String {
let mut ret = format!("{:.precision$E}", f, precision = precision); let mut ret = format!("{:.precision$E}", f, precision = precision);

View File

@ -135,7 +135,13 @@ impl App {
.calculator .calculator
.registers .registers
.iter() .iter()
.map(|(key, value)| format!("{}: {}", key, value)) .map(|(key, value)| {
format!(
"{}: {}",
key,
value.format_entry(&self.calculator.display_mode)
)
})
.fold(String::new(), |acc, s| acc + &s + "\n") .fold(String::new(), |acc, s| acc + &s + "\n")
.trim_end(), .trim_end(),
}, },