strict stack op
This commit is contained in:
104
src/calc.rs
104
src/calc.rs
@@ -1,46 +1,83 @@
|
||||
use core::{convert::Infallible, error::Error, fmt::Display};
|
||||
|
||||
use num_traits::{PrimInt, Unsigned};
|
||||
|
||||
use crate::{Decimal, DecimalError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StackCalcError {
|
||||
StackOverflow,
|
||||
StackUnderflow,
|
||||
DecimalError(DecimalError),
|
||||
}
|
||||
|
||||
impl Error for StackCalcError {}
|
||||
impl Display for StackCalcError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
StackCalcError::StackOverflow => f.write_str("stack overflow"),
|
||||
StackCalcError::StackUnderflow => f.write_str("stack underflow"),
|
||||
StackCalcError::DecimalError(de) => de.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RPNCalc<const SS: usize = 2, const DS: usize = 5, E = u16> {
|
||||
pub struct StackCalc<const SS: usize = 2, const DS: usize = 5, E = u16> {
|
||||
stack: [Decimal<DS, E>; SS],
|
||||
cur: usize,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<const SS: usize, const DS: usize, E: PrimInt> Default for RPNCalc<SS, DS, E> {
|
||||
impl<const SS: usize, const DS: usize, E: PrimInt> Default for StackCalc<SS, DS, E> {
|
||||
fn default() -> Self {
|
||||
RPNCalc {
|
||||
StackCalc {
|
||||
stack: [Decimal::default(); SS],
|
||||
cur: 0,
|
||||
index: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SS: usize, const DS: usize, E: PrimInt + Unsigned> RPNCalc<SS, DS, E> {
|
||||
pub fn enter(&mut self, val: Decimal<DS, E>) {
|
||||
self.stack[self.cur] = val;
|
||||
if self.cur == SS - 1 {
|
||||
self.cur = 0;
|
||||
} else {
|
||||
self.cur += 1;
|
||||
impl From<DecimalError> for StackCalcError {
|
||||
fn from(val: DecimalError) -> Self {
|
||||
StackCalcError::DecimalError(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Infallible> for StackCalcError {
|
||||
fn from(_: Infallible) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const SS: usize, const DS: usize, E: PrimInt + Unsigned> StackCalc<SS, DS, E> {
|
||||
pub fn push<V>(&mut self, val: V) -> Result<(), StackCalcError>
|
||||
where
|
||||
V: TryInto<Decimal<DS, E>>,
|
||||
StackCalcError: From<<V as TryInto<Decimal<DS, E>>>::Error>,
|
||||
{
|
||||
if self.index == SS {
|
||||
return Err(StackCalcError::StackOverflow);
|
||||
}
|
||||
self.stack[self.index] = val.try_into()?;
|
||||
self.index += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Decimal<DS, E> {
|
||||
self.cur = if self.cur == 0 { SS - 1 } else { self.cur - 1 };
|
||||
let ret = self.stack[self.cur];
|
||||
self.stack[self.cur] = Decimal::default();
|
||||
ret
|
||||
pub fn pop(&mut self) -> Result<Decimal<DS, E>, StackCalcError> {
|
||||
if self.index == 0 {
|
||||
return Err(StackCalcError::StackUnderflow);
|
||||
}
|
||||
self.index -= 1;
|
||||
Ok(self.stack[self.index])
|
||||
}
|
||||
|
||||
pub fn add(&mut self) -> Result<Decimal<DS, E>, DecimalError> {
|
||||
let a = self.pop();
|
||||
let b = self.pop();
|
||||
pub fn add(&mut self) -> Result<Decimal<DS, E>, StackCalcError> {
|
||||
let a = self.pop()?;
|
||||
let b = self.pop()?;
|
||||
let a = f64::try_from(a)?;
|
||||
let b = f64::try_from(b)?;
|
||||
let res = Decimal::try_from(a + b)?;
|
||||
self.enter(res);
|
||||
self.push(res)?;
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
@@ -49,20 +86,25 @@ impl<const SS: usize, const DS: usize, E: PrimInt + Unsigned> RPNCalc<SS, DS, E>
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_add() -> Result<(), DecimalError> {
|
||||
let mut calc = RPNCalc::<3, 5>::default();
|
||||
calc.enter(Decimal::try_from(1337.42)?);
|
||||
fn test_add() -> Result<(), StackCalcError> {
|
||||
let mut calc = StackCalc::<3, 7>::default();
|
||||
calc.push(Decimal::default())?;
|
||||
calc.push(1337.42)?;
|
||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42)?);
|
||||
calc.enter(Decimal::try_from(1337.42)?);
|
||||
calc.push(1337.42)?;
|
||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0)?);
|
||||
calc.enter(Decimal::try_from(2.0)?);
|
||||
calc.enter(Decimal::try_from(3.0)?);
|
||||
calc.push(2.0)?;
|
||||
calc.push(3.0)?;
|
||||
assert!(matches!(
|
||||
calc.push(3.0).unwrap_err(),
|
||||
StackCalcError::StackOverflow
|
||||
));
|
||||
assert_eq!(calc.add()?, Decimal::try_from(5.0)?);
|
||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
||||
assert!(matches!(
|
||||
calc.add().unwrap_err(),
|
||||
StackCalcError::StackUnderflow
|
||||
));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ impl Error for DecimalError {}
|
||||
impl Display for DecimalError {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
DecimalError::ExponentOverflow => f.write_str("Exponent overflow"),
|
||||
DecimalError::NotANumber => f.write_str("Not a number"),
|
||||
DecimalError::ExponentOverflow => f.write_str("exponent overflow"),
|
||||
DecimalError::NotANumber => f.write_str("not a number"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user