array-mumu 0.2.0-rc.5

Array tools plugin for the Mumu ecosystem
Documentation
use mumu::parser::types::{Value, FunctionValue};
use mumu::parser::interpreter::Interpreter;
use std::sync::{Arc, Mutex};

pub fn is_placeholder(val: &Value) -> bool {
    matches!(val, Value::Placeholder)
        || matches!(val, Value::SingleString(s) if s == "_")
        || matches!(val, Value::StrArray(ss) if ss.len() == 1 && ss[0] == "_")
}

pub fn make_two_arg_partial(
    finalize: fn(&mut Interpreter, Value, Value) -> Result<Value, String>,
    a_opt: Option<Value>,
    b_opt: Option<Value>,
    label: &'static str,
) -> Value {
    let closure = move |interp: &mut Interpreter, new_args: Vec<Value>| {
        let mut a = a_opt.clone();
        let mut b = b_opt.clone();
        for arg in new_args {
            if a.is_none() {
                if !is_placeholder(&arg) { a = Some(arg); }
                continue;
            }
            if b.is_none() {
                if !is_placeholder(&arg) { b = Some(arg); }
                continue;
            }
            return Err("Too many arguments for partial function".to_string());
        }
        if let (Some(aa), Some(bb)) = (a.clone(), b.clone()) {
            finalize(interp, aa, bb)
        } else {
            Ok(make_two_arg_partial(finalize, a, b, label))
        }
    };
    Value::Function(Box::new(FunctionValue::RustClosure(
        label.to_string(),
        Arc::new(Mutex::new(closure)),
        0,
    )))
}

pub fn make_three_arg_partial(
    finalize: fn(&mut Interpreter, Value, Value, Value) -> Result<Value, String>,
    a_opt: Option<Value>,
    b_opt: Option<Value>,
    c_opt: Option<Value>,
    label: &'static str,
) -> Value {
    let closure = move |interp: &mut Interpreter, new_args: Vec<Value>| {
        let mut a = a_opt.clone();
        let mut b = b_opt.clone();
        let mut c = c_opt.clone();
        for arg in new_args {
            if a.is_none() {
                if !is_placeholder(&arg) { a = Some(arg); }
                continue;
            }
            if b.is_none() {
                if !is_placeholder(&arg) { b = Some(arg); }
                continue;
            }
            if c.is_none() {
                if !is_placeholder(&arg) { c = Some(arg); }
                continue;
            }
            return Err("Too many arguments for partial function".to_string());
        }
        if let (Some(aa), Some(bb), Some(cc)) = (a.clone(), b.clone(), c.clone()) {
            finalize(interp, aa, bb, cc)
        } else {
            Ok(make_three_arg_partial(finalize, a, b, c, label))
        }
    };
    Value::Function(Box::new(FunctionValue::RustClosure(
        label.to_string(),
        Arc::new(Mutex::new(closure)),
        0,
    )))
}