array-mumu 0.2.0-rc.5

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

pub fn array_take_while_bridge(
    interp: &mut Interpreter,
    args: Vec<Value>,
) -> Result<Value, String> {
    match args.len() {
        0 => Ok(make_two_arg_partial(
            do_take_while,
            None,
            None,
            "array-transform-take_while-partial",
        )),
        1 => {
            if is_placeholder(&args[0]) {
                Ok(make_two_arg_partial(
                    do_take_while,
                    None,
                    None,
                    "array-transform-take_while-partial",
                ))
            } else {
                Ok(make_two_arg_partial(
                    do_take_while,
                    Some(args[0].clone()),
                    None,
                    "array-transform-take_while-partial",
                ))
            }
        }
        2 => {
            let a1_pl = is_placeholder(&args[0]);
            let a2_pl = is_placeholder(&args[1]);
            if !a1_pl && !a2_pl {
                do_take_while(interp, args[0].clone(), args[1].clone())
            } else {
                Ok(make_two_arg_partial(
                    do_take_while,
                    if a1_pl { None } else { Some(args[0].clone()) },
                    if a2_pl { None } else { Some(args[1].clone()) },
                    "array-transform-take_while-partial",
                ))
            }
        }
        _ => Err("array:take_while expects 2 arguments (fn, array)".to_string()),
    }
}

fn do_take_while(interp: &mut Interpreter, pred: Value, arr: Value) -> Result<Value, String> {
    let pred_fn = match pred {
        Value::Function(fb) => fb,
        _ => return Err("array:take_while => first argument must be a function".to_string()),
    };

    match arr {
        Value::IntArray(xs) => {
            let mut out: Vec<i32> = Vec::new();
            for v in xs {
                let keep = apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::Int(v)])?;
                match keep {
                    Value::Bool(true) => out.push(v),
                    _ => break,
                }
            }
            Ok(Value::IntArray(out))
        }
        Value::FloatArray(xs) => {
            let mut out: Vec<f64> = Vec::new();
            for v in xs {
                let keep = apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::Float(v)])?;
                match keep {
                    Value::Bool(true) => out.push(v),
                    _ => break,
                }
            }
            Ok(Value::FloatArray(out))
        }
        Value::StrArray(xs) => {
            let mut out: Vec<String> = Vec::new();
            for s in xs {
                let keep = apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::SingleString(s.clone())])?;
                match keep {
                    Value::Bool(true) => out.push(s),
                    _ => break,
                }
            }
            Ok(Value::StrArray(out))
        }
        Value::BoolArray(xs) => {
            let mut out: Vec<bool> = Vec::new();
            for b in xs {
                let keep = apply_n_ary_function_value(interp, pred_fn.clone(), vec![Value::Bool(b)])?;
                match keep {
                    Value::Bool(true) => out.push(b),
                    _ => break,
                }
            }
            Ok(Value::BoolArray(out))
        }
        Value::MixedArray(xs) => {
            let mut out = Vec::new();
            for v in xs {
                let keep = apply_n_ary_function_value(interp, pred_fn.clone(), vec![v.clone()])?;
                match keep {
                    Value::Bool(true) => out.push(v),
                    _ => break,
                }
            }
            Ok(Value::MixedArray(out))
        }
        other => Err(format!("array:take_while => second argument must be array, got {:?}", other)),
    }
}