logisheets_controller 0.6.0

the core of LogiSheets
Documentation
use super::{CalcValue, CalcVertex, Value};
use crate::calc_engine::connector::Connector;
use logisheets_parser::ast;

pub fn calc<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let sum_result = args
        .into_iter()
        .map(|arg| fetcher.get_calc_value(arg))
        .try_fold(0_f64, |sum, v| match sum_calc_value(v) {
            Ok(n) => Ok(sum + n),
            Err(e) => Err(e),
        });
    match sum_result {
        Ok(num) => CalcVertex::from_number(num),
        Err(e) => CalcVertex::from_error(e),
    }
}

pub fn calc_sumsq<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let sum_result = args
        .into_iter()
        .map(|arg| fetcher.get_calc_value(arg))
        .try_fold(0_f64, |sum, v| match sum_calc_value(v) {
            Ok(n) => Ok(sum + n.powi(2)),
            Err(e) => Err(e),
        });
    match sum_result {
        Ok(num) => CalcVertex::from_number(num),
        Err(e) => CalcVertex::from_error(e),
    }
}

fn sum_calc_value(value: CalcValue) -> Result<f64, ast::Error> {
    match value {
        CalcValue::Scalar(s) => match s {
            Value::Number(f) => Ok(f),
            Value::Error(e) => Err(e),
            _ => Ok(0_f64),
        },
        CalcValue::Range(r) => {
            let result = r.into_iter().try_fold(0_f64, |s, e| match e {
                Value::Number(n) => Ok(s + n),
                Value::Error(e) => Err(e),
                _ => Ok(s),
            })?;
            Ok(result)
        }
        CalcValue::Cube(c) => {
            let result = c.into_iter().try_fold(0_f64, |s, e| match e {
                Value::Number(n) => Ok(s + n),
                Value::Error(e) => Err(e),
                _ => Ok(s),
            })?;
            Ok(result)
        }
        CalcValue::Union(values) => values.into_iter().map(|v| sum_calc_value(*v)).try_fold(
            0_f64,
            |prev, this| match this {
                Ok(n) => Ok(prev + n),
                Err(e) => Err(e),
            },
        ),
    }
}

#[cfg(test)]
mod tests {
    use super::super::utils::tests_utils::TestFetcher;
    use super::{CalcValue, CalcVertex, Value};
    use logisheets_base::matrix_value::MatrixValue;
    use logisheets_parser::ast;

    #[test]
    fn sum_test() {
        let args = vec![
            CalcVertex::from_bool(true),
            CalcVertex::from_bool(false),
            CalcVertex::from_number(-1_f64),
            CalcVertex::from_string(String::from("text")),
            CalcVertex::Value(CalcValue::Range(MatrixValue::from(vec![
                vec![Value::Text(String::from("1"))],
                vec![Value::Number(1_f64)],
            ]))),
        ];
        let mut fetcher = TestFetcher {};
        let result = super::calc(args, &mut fetcher);
        if let CalcVertex::Value(CalcValue::Scalar(Value::Number(f))) = result {
            assert!((f - 0.0).abs() < 1e-10)
        } else {
            panic!()
        }
    }

    #[test]
    fn sum_error() {
        let args = vec![
            CalcVertex::from_error(ast::Error::Name),
            CalcVertex::from_bool(false),
            CalcVertex::from_number(100_f64),
        ];
        let mut fetcher = TestFetcher {};
        let result = super::calc(args, &mut fetcher);
        assert!(matches!(
            result,
            CalcVertex::Value(CalcValue::Scalar(Value::Error(ast::Error::Name)))
        ))
    }
}