array-mumu 0.2.0-rc.5

Array tools plugin for the Mumu ecosystem
Documentation
use mumu::parser::types::Value;
use mumu::parser::interpreter::Interpreter;
use crate::apply::apply_n_ary_function_value;
use super::common::{is_placeholder, make_two_arg_partial};

pub fn array_partition_bridge(interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
    match args.len() {
        2 => {
            let pred_fn = &args[0];
            let arr = &args[1];
            let pred_pl = is_placeholder(pred_fn);
            let arr_pl = is_placeholder(arr);
            if !pred_pl && !arr_pl {
                do_partition(interp, pred_fn.clone(), arr.clone())
            } else {
                Ok(make_two_arg_partial(
                    do_partition,
                    if pred_pl { None } else { Some(pred_fn.clone()) },
                    if arr_pl { None } else { Some(arr.clone()) },
                    "array-transform-partition-partial",
                ))
            }
        }
        1 => Ok(make_two_arg_partial(
            do_partition,
            Some(args[0].clone()),
            None,
            "array-transform-partition-partial",
        )),
        0 => Ok(make_two_arg_partial(
            do_partition,
            None,
            None,
            "array-transform-partition-partial",
        )),
        n => Err(format!(
            "array:partition => expects 2 arguments (fn, array), got {}",
            n
        )),
    }
}

fn do_partition(
    interp: &mut Interpreter,
    pred_fn_val: Value,
    arr_val: Value,
) -> Result<Value, String> {
    let pred_fn = match pred_fn_val {
        Value::Function(f) => f,
        other => {
            return Err(format!(
                "array:partition => first argument must be a function, got {:?}",
                other
            ))
        }
    };

    match arr_val {
        Value::IntArray(xs) => {
            let mut yes: Vec<i32> = Vec::new();
            let mut no: Vec<i32> = Vec::new();
            for v in xs {
                match apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::Int(v)]) {
                    Ok(Value::Bool(true)) => yes.push(v),
                    _ => no.push(v),
                }
            }
            Ok(Value::MixedArray(vec![Value::IntArray(yes), Value::IntArray(no)]))
        }
        Value::FloatArray(xs) => {
            let mut yes: Vec<f64> = Vec::new();
            let mut no: Vec<f64> = Vec::new();
            for v in xs {
                match apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::Float(v)]) {
                    Ok(Value::Bool(true)) => yes.push(v),
                    _ => no.push(v),
                }
            }
            Ok(Value::MixedArray(vec![Value::FloatArray(yes), Value::FloatArray(no)]))
        }
        Value::StrArray(xs) => {
            let mut yes: Vec<String> = Vec::new();
            let mut no: Vec<String> = Vec::new();
            for s in xs {
                match apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::SingleString(s.clone())]) {
                    Ok(Value::Bool(true)) => yes.push(s),
                    _ => no.push(s),
                }
            }
            Ok(Value::MixedArray(vec![Value::StrArray(yes), Value::StrArray(no)]))
        }
        Value::BoolArray(xs) => {
            let mut yes: Vec<bool> = Vec::new();
            let mut no: Vec<bool> = Vec::new();
            for b in xs {
                match apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::Bool(b)]) {
                    Ok(Value::Bool(true)) => yes.push(b),
                    _ => no.push(b),
                }
            }
            Ok(Value::MixedArray(vec![Value::BoolArray(yes), Value::BoolArray(no)]))
        }
        Value::MixedArray(xs) => {
            let mut yes = Vec::new();
            let mut no = Vec::new();
            for v in xs {
                match apply_n_ary_function_value(interp, pred_fn.clone(), vec![v.clone()]) {
                    Ok(Value::Bool(true)) => yes.push(v),
                    _ => no.push(v),
                }
            }
            Ok(Value::MixedArray(vec![Value::MixedArray(yes), Value::MixedArray(no)]))
        }
        other => Err(format!("array:partition => unsupported array type: {:?}", other)),
    }
}