Get vectors working

This commit is contained in:
Austen Adler 2021-06-01 23:52:51 -04:00
parent 53891274f1
commit 0405d25998
4 changed files with 1509 additions and 1538 deletions

View File

@ -16,8 +16,8 @@ use std::collections::{BTreeMap, HashMap};
use std::collections::{HashSet, VecDeque}; use std::collections::{HashSet, VecDeque};
use types::{ use types::{
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants, CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState,
CalculatorState, RegisterState, RegisterState,
}; };
/// The maximum precision allowed for the calculator /// The maximum precision allowed for the calculator
@ -283,13 +283,11 @@ impl Calculator {
Ok(()) Ok(())
} }
'r' => { 'r' => {
self.state = self.state = CalculatorState::WaitingForRegister(RegisterState::Load);
CalculatorState::WaitingForRegister(RegisterState::Load);
Ok(()) Ok(())
} }
'R' => { 'R' => {
self.state = self.state = CalculatorState::WaitingForRegister(RegisterState::Save);
CalculatorState::WaitingForRegister(RegisterState::Save);
Ok(()) Ok(())
} }
'`' => { '`' => {
@ -348,11 +346,7 @@ impl Calculator {
Ok(()) Ok(())
} }
fn register_input( fn register_input(&mut self, register_state: RegisterState, c: char) -> CalculatorResult<()> {
&mut self,
register_state: RegisterState,
c: char,
) -> CalculatorResult<()> {
match register_state { match register_state {
RegisterState::Save => { RegisterState::Save => {
let f = self.pop()?; let f = self.pop()?;
@ -379,14 +373,8 @@ impl Calculator {
'r' => self.angle_mode = CalculatorAngleMode::Radians, 'r' => self.angle_mode = CalculatorAngleMode::Radians,
'g' => self.angle_mode = CalculatorAngleMode::Grads, 'g' => self.angle_mode = CalculatorAngleMode::Grads,
'_' => self.display_mode = CalculatorDisplayMode::Default, '_' => self.display_mode = CalculatorDisplayMode::Default,
',' => { ',' => self.display_mode = CalculatorDisplayMode::Separated { separator: ',' },
self.display_mode = ' ' => self.display_mode = CalculatorDisplayMode::Separated { separator: ' ' },
CalculatorDisplayMode::Separated { separator: ',' }
}
' ' => {
self.display_mode =
CalculatorDisplayMode::Separated { separator: ' ' }
}
's' => { 's' => {
self.display_mode = CalculatorDisplayMode::Scientific { self.display_mode = CalculatorDisplayMode::Scientific {
precision: DEFAULT_PRECISION, precision: DEFAULT_PRECISION,
@ -517,7 +505,7 @@ impl Calculator {
} }
} }
/// Pops a usize /// Pops a usize
pub fn pop_usize(&mut self) -> CalculatorResult<usize> { pub fn peek_usize(&mut self) -> CalculatorResult<(usize, Entry)> {
let entry = self.peek(0)?; let entry = self.peek(0)?;
let f = match entry { let f = match entry {
Entry::Number(Number { value }) => value, Entry::Number(Number { value }) => value,
@ -530,26 +518,11 @@ impl Calculator {
#[allow(clippy::cast_sign_loss)] #[allow(clippy::cast_sign_loss)]
let u = f as usize; let u = f as usize;
self.direct_state_change(CalculatorStateChange { Ok((u, entry))
pop: OpArgs::Unary(entry),
push: OpArgs::None,
})?;
Ok(u)
} }
/// Pops a precision instead of an Entry. Precisions are of type usize /// Pops a precision instead of an Entry. Precisions are of type usize
pub fn pop_precision(&mut self) -> CalculatorResult<usize> { pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
let entry = self.peek(0)?; let (u, entry) = self.peek_usize()?;
let f = match entry {
Entry::Number(Number { value }) => value,
Entry::Vector(_) => return Err(CalculatorError::TypeMismatch),
};
// Ensure this can be cast to a usize
if !f.is_finite() || f.is_sign_negative() {
return Err(CalculatorError::ArithmeticError);
}
#[allow(clippy::cast_sign_loss)]
let u = f as usize;
if u > MAX_PRECISION { if u > MAX_PRECISION {
return Err(CalculatorError::PrecisionTooHigh); return Err(CalculatorError::PrecisionTooHigh);
@ -563,16 +536,14 @@ impl Calculator {
} }
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> { pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
let count = self.pop_usize()?; let (count, count_entry) = self.peek_usize()?;
let (entries, values): (Vec<Entry>, Vec<Number>) = (0..count) let (mut entries, values): (VecDeque<Entry>, Vec<Number>) = (1..=count)
.map(|i| { .map(|i| {
let e = self.peek(i)?; let e = self.peek(i)?;
match e { match e {
// TODO: For now, vectors only contain numbers // TODO: For now, vectors only contain numbers
Entry::Number(number) => Ok((e, number)), Entry::Number(number) => Ok((e, number)),
Entry::Vector(_vector) => { Entry::Vector(_vector) => Err(CalculatorError::TypeMismatch),
Err(CalculatorError::TypeMismatch)
}
} }
}) })
.collect::<CalculatorResult<Vec<(Entry, Number)>>>()? .collect::<CalculatorResult<Vec<(Entry, Number)>>>()?
@ -583,8 +554,9 @@ impl Calculator {
values, values,
direction: true, direction: true,
}); });
entries.push_front(count_entry);
Ok(CalculatorStateChange { Ok(CalculatorStateChange {
pop: OpArgs::Variable(entries), pop: OpArgs::Variable(Vec::from(entries)),
push: OpArgs::Unary(entry), push: OpArgs::Unary(entry),
}) })
} }
@ -610,15 +582,15 @@ impl Calculator {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => { CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?))) self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?)))
} }
CalculatorOperation::ArithmeticOperation( CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide) => {
ArithmeticOperation::IntegerDivide, self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?)))
) => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?))), }
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => { CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?))) self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
} }
CalculatorOperation::ArithmeticOperation( CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue) => {
ArithmeticOperation::AbsoluteValue, self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?)))
) => self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))), }
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => { CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Inverse) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?))) self.unary_op(|a| Ok(OpArgs::Unary(a.inverse()?)))
} }
@ -662,13 +634,9 @@ impl Calculator {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(&a)?))) self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.pow(&a)?)))
} }
CalculatorOperation::BuildVector => self.build_vector(), CalculatorOperation::BuildVector => self.build_vector(),
CalculatorOperation::Dup => { CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a]))),
self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a])))
}
CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)), CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)),
CalculatorOperation::Swap => { CalculatorOperation::Swap => self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a]))),
self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a])))
}
CalculatorOperation::Undo => return self.history_op(false), CalculatorOperation::Undo => return self.history_op(false),
CalculatorOperation::Redo => return self.history_op(true), CalculatorOperation::Redo => return self.history_op(true),
// Macros are a no-op operator; need to insert for undo/redo // Macros are a no-op operator; need to insert for undo/redo
@ -699,11 +667,7 @@ impl Calculator {
} }
.last() .last()
.ok_or_else(|| { .ok_or_else(|| {
CalculatorError::EmptyHistory(String::from(if forward { CalculatorError::EmptyHistory(String::from(if forward { "redo" } else { "undo" }))
"redo"
} else {
"undo"
}))
})?; })?;
let target_history_mode = if forward { let target_history_mode = if forward {
@ -826,7 +790,7 @@ impl Calculator {
self.stack.push_front(a.clone()); // TODO: Remove the clones self.stack.push_front(a.clone()); // TODO: Remove the clones
} }
OpArgs::Variable(entries) => { OpArgs::Variable(entries) => {
for e in entries { for e in entries.iter().rev() {
self.stack.push_front(e.clone()); self.stack.push_front(e.clone());
} }
} }

View File

@ -281,249 +281,6 @@ impl CalculatorEntry for Entry {
} }
} }
impl CalculatorEntry for Number {
fn to_editable_string(&self) -> CalculatorResult<String> {
Ok(format!("{}", self.value))
}
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
match display_mode {
CalculatorDisplayMode::Default => format!("{}", self.value),
CalculatorDisplayMode::Separated { separator } => {
separated(self.value, *separator)
}
CalculatorDisplayMode::Scientific { precision } => {
scientific(self.value, *precision)
}
CalculatorDisplayMode::Engineering { precision } => {
engineering(self.value, *precision)
}
CalculatorDisplayMode::Fixed { precision } => {
format!("{:0>.precision$}", self.value, precision = precision)
}
}
}
fn is_valid(&self) -> bool {
!self.value.is_nan() && !self.value.is_infinite()
}
fn negate(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self { value: -self.value }))
}
fn abs(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.abs(),
}))
}
fn inverse(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.recip(),
}))
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
CalculatorAngleMode::Radians => self.value.sin(),
CalculatorAngleMode::Grads => {
(self.value * std::f64::consts::PI / 200.0).sin()
}
},
}))
}
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
CalculatorAngleMode::Radians => self.value.cos(),
CalculatorAngleMode::Grads => {
(self.value * std::f64::consts::PI / 200.0).cos()
}
},
}))
}
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
CalculatorAngleMode::Radians => self.value.tan(),
CalculatorAngleMode::Grads => {
(self.value * std::f64::consts::PI / 200.0).tan()
}
},
}))
}
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
CalculatorAngleMode::Radians => self.value.asin(),
CalculatorAngleMode::Grads => {
self.value.asin() * std::f64::consts::PI / 200.0
}
},
}))
}
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
CalculatorAngleMode::Radians => self.value.acos(),
CalculatorAngleMode::Grads => {
self.value.acos() * std::f64::consts::PI / 200.0
}
},
}))
}
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
CalculatorAngleMode::Radians => self.value.atan(),
CalculatorAngleMode::Grads => {
self.value.atan() * std::f64::consts::PI / 200.0
}
},
}))
}
fn sqrt(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.sqrt(),
}))
}
fn log(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.log10(),
}))
}
fn ln(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
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> {
match arg {
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> { fn to_editable_string(&self) -> CalculatorResult<String> {
@ -531,10 +288,7 @@ impl CalculatorEntry for Vector {
Err(CalculatorError::TypeMismatch) Err(CalculatorError::TypeMismatch)
} }
fn is_valid(&self) -> bool { fn is_valid(&self) -> bool {
self.values self.values.iter().all(|number| number.is_valid())
.iter()
.find(|number| !number.is_valid())
.is_none()
} }
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String { fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
format!( format!(
@ -543,7 +297,7 @@ impl CalculatorEntry for Vector {
.iter() .iter()
.map(|number| number.format_entry(display_mode)) .map(|number| number.format_entry(display_mode))
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("; ") .join(if self.direction { "; " } else { " " })
) )
} }
// Mathematical operations // Mathematical operations
@ -551,10 +305,19 @@ impl CalculatorEntry for Vector {
self.iterated_unary(Number::negate) self.iterated_unary(Number::negate)
} }
fn abs(&self) -> CalculatorResult<Entry> { fn abs(&self) -> CalculatorResult<Entry> {
self.iterated_unary(Number::abs) let value: Entry = self
.values
.iter()
.try_fold(Entry::Number(Number::ZERO), |acc, n2| {
acc.add(&n2.pow_num(&Number { value: 2.0_f64 })?)
})?;
Ok(value.sqrt()?)
} }
fn inverse(&self) -> CalculatorResult<Entry> { fn inverse(&self) -> CalculatorResult<Entry> {
self.iterated_unary(Number::inverse) Ok(Entry::Vector(Vector {
values: self.values.clone(),
direction: !self.direction,
}))
} }
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> { fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.sin(angle_mode)) self.iterated_unary(|n| n.sin(angle_mode))
@ -698,11 +461,10 @@ impl Vector {
op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>, op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>,
) -> CalculatorResult<Entry> { ) -> CalculatorResult<Entry> {
if self.values.len() != v2.values.len() { if self.values.len() != v2.values.len() {
return Err(CalculatorError::ArithmeticError); return Err(CalculatorError::DimensionMismatch);
} }
if self.direction != v2.direction { if self.direction != v2.direction {
// TODO: Return a different error return Err(CalculatorError::DimensionMismatch);
return Err(CalculatorError::ArithmeticError);
} }
Ok(Entry::Vector(Self { Ok(Entry::Vector(Self {
values: self values: self
@ -740,6 +502,248 @@ impl Vector {
} }
} }
impl CalculatorEntry for Number {
fn to_editable_string(&self) -> CalculatorResult<String> {
Ok(format!("{}", self.value))
}
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
match display_mode {
CalculatorDisplayMode::Default => format!("{}", self.value),
CalculatorDisplayMode::Separated { separator } => separated(self.value, *separator),
CalculatorDisplayMode::Scientific { precision } => scientific(self.value, *precision),
CalculatorDisplayMode::Engineering { precision } => engineering(self.value, *precision),
CalculatorDisplayMode::Fixed { precision } => {
format!("{:0>.precision$}", self.value, precision = precision)
}
}
}
fn is_valid(&self) -> bool {
!self.value.is_nan() && !self.value.is_infinite()
}
fn negate(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self { value: -self.value }))
}
fn abs(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.abs(),
}))
}
fn inverse(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.recip(),
}))
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().sin(),
CalculatorAngleMode::Radians => self.value.sin(),
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).sin(),
},
}))
}
fn cos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().cos(),
CalculatorAngleMode::Radians => self.value.cos(),
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).cos(),
},
}))
}
fn tan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.to_radians().tan(),
CalculatorAngleMode::Radians => self.value.tan(),
CalculatorAngleMode::Grads => (self.value * std::f64::consts::PI / 200.0).tan(),
},
}))
}
fn asin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.asin().to_degrees(),
CalculatorAngleMode::Radians => self.value.asin(),
CalculatorAngleMode::Grads => self.value.asin() * std::f64::consts::PI / 200.0,
},
}))
}
fn acos(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.acos().to_degrees(),
CalculatorAngleMode::Radians => self.value.acos(),
CalculatorAngleMode::Grads => self.value.acos() * std::f64::consts::PI / 200.0,
},
}))
}
fn atan(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: match angle_mode {
CalculatorAngleMode::Degrees => self.value.atan().to_degrees(),
CalculatorAngleMode::Radians => self.value.atan(),
CalculatorAngleMode::Grads => self.value.atan() * std::f64::consts::PI / 200.0,
},
}))
}
fn sqrt(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.sqrt(),
}))
}
fn log(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
value: self.value.log10(),
}))
}
fn ln(&self) -> CalculatorResult<Entry> {
Ok(Entry::Number(Self {
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> {
match arg {
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> {
Self {
value: self.value + arg.value,
}
.validate()
}
fn sub_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Self {
value: self.value - arg.value,
}
.validate()
}
fn mul_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Self {
value: self.value * arg.value,
}
.validate()
}
fn div_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Self {
value: self.value / arg.value,
}
.validate()
}
fn int_divide_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Self {
value: self.value.div_euclid(arg.value),
}
.validate()
}
fn modulo_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Self {
value: self.value % arg.value,
}
.validate()
}
fn pow_num(&self, arg: &Number) -> CalculatorResult<Entry> {
Self {
value: self.value.powf(arg.value),
}
.validate()
}
}
impl Number {
pub const ZERO: Self = Self { value: 0.0_f64 };
fn validate(&self) -> CalculatorResult<Entry> {
if self.is_valid() {
Ok(Entry::Number(*self))
} else {
Err(CalculatorError::ArithmeticError)
}
}
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,
}))
}
}
pub trait CalculatorEntry pub trait CalculatorEntry
where where
Self: Sized, Self: Sized,
@ -800,7 +804,7 @@ impl fmt::Display for Entry {
impl fmt::Display for Number { impl fmt::Display for Number {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self) write!(f, "{}", self.value)
} }
} }

View File

@ -13,6 +13,8 @@ pub enum CalculatorError {
NotEnoughStackEntries, NotEnoughStackEntries,
/// Requested type does not match target type /// Requested type does not match target type
TypeMismatch, TypeMismatch,
/// Dimensions must match
DimensionMismatch,
/// Thrown when an undo or redo cannot be performed /// Thrown when an undo or redo cannot be performed
CorruptStateChange(String), CorruptStateChange(String),
/// Cannot undo or redo /// Cannot undo or redo
@ -47,6 +49,7 @@ impl fmt::Display for CalculatorError {
Self::ArithmeticError => write!(f, "Arithmetic Error"), Self::ArithmeticError => write!(f, "Arithmetic Error"),
Self::NotEnoughStackEntries => write!(f, "Not enough items in the stack"), Self::NotEnoughStackEntries => write!(f, "Not enough items in the stack"),
Self::TypeMismatch => write!(f, "Type mismatch"), Self::TypeMismatch => write!(f, "Type mismatch"),
Self::DimensionMismatch => write!(f, "Dimension mismatch"),
Self::CorruptStateChange(msg) => { Self::CorruptStateChange(msg) => {
write!(f, "Corrupt state change: {}", msg) write!(f, "Corrupt state change: {}", msg)
} }