logisheets_controller 0.6.0

the core of LogiSheets
Documentation
use crate::calc_engine::calculator::math::{gcd::multi_gcd, lcm::multi_lcm};
use crate::calc_engine::{
    calculator::calc_vertex::{CalcValue, CalcVertex, Value},
    connector::Connector,
};
use logisheets_parser::ast;

pub fn calc_gcd<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, multi_gcd)
}

pub fn calc_lcm<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, multi_lcm)
}

fn calc<C, F>(args: Vec<CalcVertex>, fetcher: &mut C, func: F) -> CalcVertex
where
    C: Connector,
    F: Fn(&[u32]) -> u32,
{
    let mut args_iter = args.into_iter();
    let nums = Vec::<u32>::new();
    let r = args_iter.try_fold(nums, |mut prev, arg| {
        let value = fetcher.get_calc_value(arg);
        let n = get_num_from_calc_value(value)?;
        prev.extend(n);
        Ok(prev)
    });
    match r {
        Ok(r) => {
            let gcd = func(&r);
            CalcVertex::from_number(gcd as f64)
        }
        Err(e) => CalcVertex::from_error(e),
    }
}

fn get_num_from_calc_value(value: CalcValue) -> Result<Vec<u32>, ast::Error> {
    match value {
        CalcValue::Scalar(n) => {
            let n = get_num_from_value(n);
            match n {
                Ok(n) => Ok(vec![n]),
                Err(e) => Err(e),
            }
        }
        CalcValue::Range(range) => {
            range
                .into_iter()
                .try_fold(Vec::<u32>::new(), |mut prev, arg| {
                    let n = get_num_from_value(arg);
                    match n {
                        Ok(n) => {
                            prev.push(n);
                            Ok(prev)
                        }
                        Err(e) => Err(e),
                    }
                })
        }
        CalcValue::Cube(cube) => cube
            .into_iter()
            .try_fold(Vec::<u32>::new(), |mut prev, arg| {
                let n = get_num_from_value(arg);
                match n {
                    Ok(n) => {
                        prev.push(n);
                        Ok(prev)
                    }
                    Err(e) => Err(e),
                }
            }),
        CalcValue::Union(values) => {
            values
                .into_iter()
                .try_fold(Vec::<u32>::new(), |mut prev, v| {
                    let nums = get_num_from_calc_value(*v)?;
                    prev.extend(nums);
                    Ok(prev)
                })
        }
    }
}

fn get_num_from_value(value: Value) -> Result<u32, ast::Error> {
    match value {
        Value::Blank => Ok(0),
        Value::Number(f) => Ok(f.floor() as u32),
        Value::Text(_) => Err(ast::Error::Value),
        Value::Boolean(b) => {
            if b {
                Ok(1)
            } else {
                Ok(0)
            }
        }
        Value::Error(e) => Err(e),
    }
}