logisheets_controller 0.6.0

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

fn calc<C, F>(args: Vec<CalcVertex>, fetcher: &mut C, func: F) -> CalcVertex
where
    C: Connector,
    F: 'static + Fn(f64) -> f64,
{
    if args.len() != 1 {
        return CalcVertex::from_error(ast::Error::Unspecified);
    }
    let arg = args.into_iter().next().unwrap();
    let value = fetcher.get_calc_value(arg);
    let v = match value {
        CalcValue::Scalar(s) => CalcValue::Scalar(call(&s, &func)),
        CalcValue::Range(r) => {
            let vec2d = r.map(move |v| call(v, &func));
            CalcValue::Range(vec2d)
        }
        CalcValue::Cube(_) => CalcValue::Scalar(Value::Error(ast::Error::Ref)),
        CalcValue::Union(u) => {
            if u.len() == 1 {
                let arg = *u.into_iter().next().unwrap();
                let v = vec![CalcVertex::Value(arg)];
                if let CalcVertex::Value(value) = calc(v, fetcher, func) {
                    value
                } else {
                    CalcValue::Scalar(Value::Error(ast::Error::Value))
                }
            } else {
                CalcValue::Scalar(Value::Error(ast::Error::Value))
            }
        }
    };
    CalcVertex::Value(v)
}

fn call<F>(value: &Value, func: &F) -> Value
where
    F: Fn(f64) -> f64,
{
    match value {
        Value::Blank => Value::Number(func(0_f64)),
        Value::Number(n) => Value::Number(func(n.clone())),
        Value::Text(_) => Value::Error(ast::Error::Value),
        Value::Boolean(b) => {
            if *b {
                Value::Number(func(1_f64))
            } else {
                Value::Number(func(0_f64))
            }
        }
        Value::Error(e) => Value::Error(e.clone()),
    }
}

pub fn calc_abs<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.abs())
}

pub fn calc_sin<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.sin())
}

pub fn calc_csc<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| 1. / a.sin())
}

pub fn calc_asin<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.asin())
}

pub fn calc_asinh<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.asinh())
}

pub fn calc_cos<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.cos())
}

pub fn calc_tan<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.tan())
}

pub fn calc_cot<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| 1. / a.tan())
}

pub fn calc_tanh<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.tanh())
}

pub fn calc_coth<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| 1. / a.tanh())
}

pub fn calc_sqrt<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.sqrt())
}

pub fn calc_sqrtpi<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| (std::f64::consts::PI * a).sqrt())
}

pub fn calc_acos<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.acos())
}

pub fn calc_atan<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.atan())
}

pub fn calc_atanh<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.atanh())
}

pub fn calc_acosh<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.acosh())
}

pub fn calc_ln<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.ln())
}

pub fn calc_log10<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.log10())
}

pub fn calc_exp<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    calc(args, fetcher, |a| a.exp())
}

pub fn calc_factdouble<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    use crate::calc_engine::calculator::math::fact::factdouble;
    calc(args, fetcher, |a| factdouble(a.floor() as u64) as f64)
}

pub fn calc_odd<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let func = |n: f64| -> f64 {
        let pos = n >= 0.;
        let c = n.abs().ceil() as u32;
        let u_c = if c % 2 == 0 { c + 1 } else { c };
        if pos {
            u_c as f64
        } else {
            -(u_c as f64)
        }
    };
    calc(args, fetcher, func)
}

pub fn calc_even<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let func = |n: f64| -> f64 {
        let pos = n >= 0.;
        let c = n.abs().ceil() as u32;
        let u_c = if c % 2 == 0 { c } else { c + 1 };
        if pos {
            u_c as f64
        } else {
            -(u_c as f64)
        }
    };
    calc(args, fetcher, func)
}

pub fn calc_sign<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let func = |n: f64| -> f64 {
        if n == 0. {
            0.
        } else if n > 0. {
            1.
        } else {
            -1.
        }
    };
    calc(args, fetcher, func)
}

pub fn calc_radians<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let func = |n: f64| -> f64 { n * std::f64::consts::PI / 180. };
    calc(args, fetcher, func)
}

pub fn calc_degrees<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let func = |n: f64| -> f64 { n * 180. / std::f64::consts::PI };
    calc(args, fetcher, func)
}

pub fn calc_gamma<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let func = |n: f64| -> f64 { statrs::function::gamma::gamma(n) };
    calc(args, fetcher, func)
}

pub fn calc_normsdist<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    use statrs::distribution::{ContinuousCDF, Normal};
    let func = |x: f64| -> f64 {
        let n = Normal::new(0.0, 1.0).unwrap();
        n.cdf(x)
    };
    calc(args, fetcher, func)
}

pub fn calc_gammaln<C>(args: Vec<CalcVertex>, fetcher: &mut C) -> CalcVertex
where
    C: Connector,
{
    let func = |n: f64| -> f64 {
        let g = statrs::function::gamma::gamma(n);
        g.ln()
    };
    calc(args, fetcher, func)
}