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 types::{
CalculatorAlignment, CalculatorAngleMode, CalculatorConstant, CalculatorConstants,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters,
CalculatorState, RegisterState,
CalculatorDisplayMode, CalculatorMacro, CalculatorMacros, CalculatorRegisters, CalculatorState,
RegisterState,
};
/// The maximum precision allowed for the calculator
@ -283,13 +283,11 @@ impl Calculator {
Ok(())
}
'r' => {
self.state =
CalculatorState::WaitingForRegister(RegisterState::Load);
self.state = CalculatorState::WaitingForRegister(RegisterState::Load);
Ok(())
}
'R' => {
self.state =
CalculatorState::WaitingForRegister(RegisterState::Save);
self.state = CalculatorState::WaitingForRegister(RegisterState::Save);
Ok(())
}
'`' => {
@ -348,11 +346,7 @@ impl Calculator {
Ok(())
}
fn register_input(
&mut self,
register_state: RegisterState,
c: char,
) -> CalculatorResult<()> {
fn register_input(&mut self, register_state: RegisterState, c: char) -> CalculatorResult<()> {
match register_state {
RegisterState::Save => {
let f = self.pop()?;
@ -379,14 +373,8 @@ impl Calculator {
'r' => self.angle_mode = CalculatorAngleMode::Radians,
'g' => self.angle_mode = CalculatorAngleMode::Grads,
'_' => self.display_mode = CalculatorDisplayMode::Default,
',' => {
self.display_mode =
CalculatorDisplayMode::Separated { separator: ',' }
}
' ' => {
self.display_mode =
CalculatorDisplayMode::Separated { separator: ' ' }
}
',' => self.display_mode = CalculatorDisplayMode::Separated { separator: ',' },
' ' => self.display_mode = CalculatorDisplayMode::Separated { separator: ' ' },
's' => {
self.display_mode = CalculatorDisplayMode::Scientific {
precision: DEFAULT_PRECISION,
@ -517,7 +505,7 @@ impl Calculator {
}
}
/// 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 f = match entry {
Entry::Number(Number { value }) => value,
@ -530,26 +518,11 @@ impl Calculator {
#[allow(clippy::cast_sign_loss)]
let u = f as usize;
self.direct_state_change(CalculatorStateChange {
pop: OpArgs::Unary(entry),
push: OpArgs::None,
})?;
Ok(u)
Ok((u, entry))
}
/// Pops a precision instead of an Entry. Precisions are of type usize
pub fn pop_precision(&mut self) -> CalculatorResult<usize> {
let entry = self.peek(0)?;
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;
let (u, entry) = self.peek_usize()?;
if u > MAX_PRECISION {
return Err(CalculatorError::PrecisionTooHigh);
@ -563,16 +536,14 @@ impl Calculator {
}
pub fn build_vector(&mut self) -> CalculatorResult<CalculatorStateChange> {
let count = self.pop_usize()?;
let (entries, values): (Vec<Entry>, Vec<Number>) = (0..count)
let (count, count_entry) = self.peek_usize()?;
let (mut entries, values): (VecDeque<Entry>, Vec<Number>) = (1..=count)
.map(|i| {
let e = self.peek(i)?;
match e {
// TODO: For now, vectors only contain numbers
Entry::Number(number) => Ok((e, number)),
Entry::Vector(_vector) => {
Err(CalculatorError::TypeMismatch)
}
Entry::Vector(_vector) => Err(CalculatorError::TypeMismatch),
}
})
.collect::<CalculatorResult<Vec<(Entry, Number)>>>()?
@ -583,8 +554,9 @@ impl Calculator {
values,
direction: true,
});
entries.push_front(count_entry);
Ok(CalculatorStateChange {
pop: OpArgs::Variable(entries),
pop: OpArgs::Variable(Vec::from(entries)),
push: OpArgs::Unary(entry),
})
}
@ -610,15 +582,15 @@ impl Calculator {
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Divide) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.div(&a)?)))
}
CalculatorOperation::ArithmeticOperation(
ArithmeticOperation::IntegerDivide,
) => self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?))),
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::IntegerDivide) => {
self.binary_op(|[a, b]| Ok(OpArgs::Unary(b.int_divide(&a)?)))
}
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::Negate) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.negate()?)))
}
CalculatorOperation::ArithmeticOperation(
ArithmeticOperation::AbsoluteValue,
) => self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?))),
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::AbsoluteValue) => {
self.unary_op(|a| Ok(OpArgs::Unary(a.abs()?)))
}
CalculatorOperation::ArithmeticOperation(ArithmeticOperation::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)?)))
}
CalculatorOperation::BuildVector => self.build_vector(),
CalculatorOperation::Dup => {
self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a])))
}
CalculatorOperation::Dup => self.unary_op(|a| Ok(OpArgs::Binary([a.clone(), a]))),
CalculatorOperation::Drop => self.unary_op(|_| Ok(OpArgs::None)),
CalculatorOperation::Swap => {
self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a])))
}
CalculatorOperation::Swap => self.binary_op(|[a, b]| Ok(OpArgs::Binary([b, a]))),
CalculatorOperation::Undo => return self.history_op(false),
CalculatorOperation::Redo => return self.history_op(true),
// Macros are a no-op operator; need to insert for undo/redo
@ -699,11 +667,7 @@ impl Calculator {
}
.last()
.ok_or_else(|| {
CalculatorError::EmptyHistory(String::from(if forward {
"redo"
} else {
"undo"
}))
CalculatorError::EmptyHistory(String::from(if forward { "redo" } else { "undo" }))
})?;
let target_history_mode = if forward {
@ -826,7 +790,7 @@ impl Calculator {
self.stack.push_front(a.clone()); // TODO: Remove the clones
}
OpArgs::Variable(entries) => {
for e in entries {
for e in entries.iter().rev() {
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 {
// Misc
fn to_editable_string(&self) -> CalculatorResult<String> {
@ -531,10 +288,7 @@ impl CalculatorEntry for Vector {
Err(CalculatorError::TypeMismatch)
}
fn is_valid(&self) -> bool {
self.values
.iter()
.find(|number| !number.is_valid())
.is_none()
self.values.iter().all(|number| number.is_valid())
}
fn format_entry(&self, display_mode: &CalculatorDisplayMode) -> String {
format!(
@ -543,7 +297,7 @@ impl CalculatorEntry for Vector {
.iter()
.map(|number| number.format_entry(display_mode))
.collect::<Vec<String>>()
.join("; ")
.join(if self.direction { "; " } else { " " })
)
}
// Mathematical operations
@ -551,10 +305,19 @@ impl CalculatorEntry for Vector {
self.iterated_unary(Number::negate)
}
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> {
self.iterated_unary(Number::inverse)
Ok(Entry::Vector(Vector {
values: self.values.clone(),
direction: !self.direction,
}))
}
fn sin(&self, angle_mode: CalculatorAngleMode) -> CalculatorResult<Entry> {
self.iterated_unary(|n| n.sin(angle_mode))
@ -698,11 +461,10 @@ impl Vector {
op: impl Fn(&Number, &Number) -> CalculatorResult<Entry>,
) -> CalculatorResult<Entry> {
if self.values.len() != v2.values.len() {
return Err(CalculatorError::ArithmeticError);
return Err(CalculatorError::DimensionMismatch);
}
if self.direction != v2.direction {
// TODO: Return a different error
return Err(CalculatorError::ArithmeticError);
return Err(CalculatorError::DimensionMismatch);
}
Ok(Entry::Vector(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
where
Self: Sized,
@ -800,7 +804,7 @@ impl fmt::Display for Entry {
impl fmt::Display for Number {
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,
/// Requested type does not match target type
TypeMismatch,
/// Dimensions must match
DimensionMismatch,
/// Thrown when an undo or redo cannot be performed
CorruptStateChange(String),
/// Cannot undo or redo
@ -47,6 +49,7 @@ impl fmt::Display for CalculatorError {
Self::ArithmeticError => write!(f, "Arithmetic Error"),
Self::NotEnoughStackEntries => write!(f, "Not enough items in the stack"),
Self::TypeMismatch => write!(f, "Type mismatch"),
Self::DimensionMismatch => write!(f, "Dimension mismatch"),
Self::CorruptStateChange(msg) => {
write!(f, "Corrupt state change: {}", msg)
}