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 num_traits::{PrimInt, Unsigned};
|
||||||
|
|
||||||
use crate::{Decimal, DecimalError};
|
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)]
|
#[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],
|
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 {
|
fn default() -> Self {
|
||||||
RPNCalc {
|
StackCalc {
|
||||||
stack: [Decimal::default(); SS],
|
stack: [Decimal::default(); SS],
|
||||||
cur: 0,
|
index: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const SS: usize, const DS: usize, E: PrimInt + Unsigned> RPNCalc<SS, DS, E> {
|
impl From<DecimalError> for StackCalcError {
|
||||||
pub fn enter(&mut self, val: Decimal<DS, E>) {
|
fn from(val: DecimalError) -> Self {
|
||||||
self.stack[self.cur] = val;
|
StackCalcError::DecimalError(val)
|
||||||
if self.cur == SS - 1 {
|
|
||||||
self.cur = 0;
|
|
||||||
} else {
|
|
||||||
self.cur += 1;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
pub fn pop(&mut self) -> Result<Decimal<DS, E>, StackCalcError> {
|
||||||
self.cur = if self.cur == 0 { SS - 1 } else { self.cur - 1 };
|
if self.index == 0 {
|
||||||
let ret = self.stack[self.cur];
|
return Err(StackCalcError::StackUnderflow);
|
||||||
self.stack[self.cur] = Decimal::default();
|
}
|
||||||
ret
|
self.index -= 1;
|
||||||
|
Ok(self.stack[self.index])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self) -> Result<Decimal<DS, E>, DecimalError> {
|
pub fn add(&mut self) -> Result<Decimal<DS, E>, StackCalcError> {
|
||||||
let a = self.pop();
|
let a = self.pop()?;
|
||||||
let b = self.pop();
|
let b = self.pop()?;
|
||||||
let a = f64::try_from(a)?;
|
let a = f64::try_from(a)?;
|
||||||
let b = f64::try_from(b)?;
|
let b = f64::try_from(b)?;
|
||||||
let res = Decimal::try_from(a + b)?;
|
let res = Decimal::try_from(a + b)?;
|
||||||
self.enter(res);
|
self.push(res)?;
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,20 +86,25 @@ impl<const SS: usize, const DS: usize, E: PrimInt + Unsigned> RPNCalc<SS, DS, E>
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add() -> Result<(), DecimalError> {
|
fn test_add() -> Result<(), StackCalcError> {
|
||||||
let mut calc = RPNCalc::<3, 5>::default();
|
let mut calc = StackCalc::<3, 7>::default();
|
||||||
calc.enter(Decimal::try_from(1337.42)?);
|
calc.push(Decimal::default())?;
|
||||||
|
calc.push(1337.42)?;
|
||||||
assert_eq!(calc.add()?, Decimal::try_from(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)?);
|
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0)?);
|
||||||
calc.enter(Decimal::try_from(2.0)?);
|
calc.push(2.0)?;
|
||||||
calc.enter(Decimal::try_from(3.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(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!(
|
||||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
calc.add().unwrap_err(),
|
||||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
StackCalcError::StackUnderflow
|
||||||
assert_eq!(calc.add()?, Decimal::try_from(1337.42 * 2.0 + 5.0)?);
|
));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ impl Error for DecimalError {}
|
|||||||
impl Display for DecimalError {
|
impl Display for DecimalError {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
DecimalError::ExponentOverflow => f.write_str("Exponent overflow"),
|
DecimalError::ExponentOverflow => f.write_str("exponent overflow"),
|
||||||
DecimalError::NotANumber => f.write_str("Not a number"),
|
DecimalError::NotANumber => f.write_str("not a number"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user