hypertune 0.6.2

Hypertune SDK for type safe configuration
Documentation
use anyhow::anyhow;
use anyhow::Result;
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::expression::Expression;
use crate::expression::FloatExpression;
use crate::expression::IntExpression;

#[derive(Deserialize, Serialize, Eq, PartialEq, Debug, Clone)]
pub enum ArithmeticOperator {
    #[serde(rename = "+")]
    Plus,

    #[serde(rename = "-")]
    Minus,

    #[serde(rename = "*")]
    Multiply,

    #[serde(rename = "/")]
    Divide,

    #[serde(rename = "POW")]
    Exponent,

    #[serde(rename = "MOD")]
    Modulo,
}

impl ArithmeticOperator {
    pub fn evaluate(&self, a: &Value, b: &Value) -> Result<Expression> {
        match self.evaluate_as_f64(a, b) {
            Ok(value) => {
                if value.is_finite() {
                    if value.floor() == value.ceil() {
                        Ok(Expression::Int(IntExpression::transient(value as i64)))
                    } else {
                        Ok(Expression::Float(FloatExpression::transient(value)))
                    }
                } else {
                    Err(anyhow!(
                        "Result of arithmetic operator does not fit into an f64"
                    ))
                }
            }
            Err(error) => Err(error),
        }
    }

    fn evaluate_as_f64(&self, a: &Value, b: &Value) -> Result<f64> {
        match (a, b) {
            (Value::Number(a), Value::Number(b)) => match (a.as_f64(), b.as_f64()) {
                (Some(a), Some(b)) => match self {
                    ArithmeticOperator::Plus => Ok(a + b),
                    ArithmeticOperator::Minus => Ok(a - b),
                    ArithmeticOperator::Multiply => Ok(a * b),
                    ArithmeticOperator::Divide => Ok(a / b),
                    ArithmeticOperator::Exponent => Ok(f64::powf(a, b)),
                    ArithmeticOperator::Modulo => Ok(a % b),
                },
                (_, _) => Err(anyhow!(
                    "One of a or b does not fit into an f64 - a: {}, b: {}",
                    a,
                    b
                )),
            },
            (_, _) => Err(anyhow!(
                "Evaluated operands of arithmetic expression are not both numbers"
            )),
        }
    }
}