mumu-array 0.1.2

Array tools plugin for the MuMu/Lava language
Documentation
use mumu::parser::types::{FunctionValue, Value};
use mumu::parser::interpreter::{Interpreter, 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: Value,
    arr_val: Value,
) -> Result<Value, String> {
    let pred_fn = match pred_fn {
        Value::Function(f) => f,
        other => return Err(format!("array:partition => first argument must be a function, got {:?}", other)),
    };
    let items = match arr_val {
        Value::IntArray(xs) => xs.iter().map(|&x| Value::Int(x)).collect(),
        Value::FloatArray(xs) => xs.iter().map(|&x| Value::Float(x)).collect(),
        Value::StrArray(xs) => xs.iter().map(|x| Value::SingleString(x.clone())).collect(),
        Value::BoolArray(xs) => xs.iter().map(|&x| Value::Bool(x)).collect(),
        Value::MixedArray(xs) => xs,
        other => return Err(format!("array:partition => unsupported array type: {:?}", other)),
    };
    let mut yes = Vec::new();
    let mut no = Vec::new();
    for v in items {
        let res = apply_n_ary_function_value(interp, pred_fn.clone(), vec![v.clone()]);
        match res {
            Ok(Value::Bool(true)) => yes.push(v),
            Ok(Value::Bool(false)) => no.push(v),
            _ => no.push(v),
        }
    }
    Ok(Value::MixedArray(vec![Value::MixedArray(yes), Value::MixedArray(no)]))
}