mumu-string 0.1.0

String functions and tools plugin for the Lava language
Documentation
use mumu::parser::types::Value;

pub fn is_placeholder(v: &Value) -> bool {
    match v {
        Value::Placeholder => true,
        Value::SingleString(s) if s == "_" => true,
        Value::StrArray(ss) if ss.len() == 1 && ss[0] == "_" => true,
        _ => false,
    }
}

use mumu::parser::types::FunctionValue::RustClosure;
use std::sync::{Arc, Mutex};

pub fn make_one_arg_partial(
    finalize_fn: fn(Vec<Value>) -> Result<Value, String>,
    known_opt: Option<Value>
) -> Value {
    let closure = move |_interp: &mut mumu::parser::interpreter::Interpreter, new_args: Vec<Value>| {
        let mut current_known = known_opt.clone();
        for arg in new_args {
            if current_known.is_none() {
                if is_placeholder(&arg) {} else { current_known = Some(arg); }
                continue;
            }
            return Err("string => partial => too many arguments".to_string());
        }
        if let Some(real_val) = current_known {
            finalize_fn(vec![real_val])
        } else {
            Ok(make_one_arg_partial(finalize_fn, current_known))
        }
    };
    Value::Function(Box::new(RustClosure(
        "string-1arg-partial".to_string(),
        Arc::new(Mutex::new(closure)),
        0,
    )))
}

pub fn make_two_arg_partial(
    finalize_fn: fn(Vec<Value>) -> Result<Value, String>,
    a_opt: Option<Value>,
    b_opt: Option<Value>,
) -> Value {
    let closure = move |_interp: &mut mumu::parser::interpreter::Interpreter, new_args: Vec<Value>| {
        let mut aa = a_opt.clone();
        let mut bb = b_opt.clone();
        for arg in new_args {
            if aa.is_none() {
                if is_placeholder(&arg) {} else { aa = Some(arg); }
                continue;
            }
            if bb.is_none() {
                if is_placeholder(&arg) {} else { bb = Some(arg); }
                continue;
            }
            return Err("string => partial => too many arguments".to_string());
        }
        if aa.is_some() && bb.is_some() {
            finalize_fn(vec![aa.as_ref().unwrap().clone(), bb.as_ref().unwrap().clone()])
        } else {
            Ok(make_two_arg_partial(finalize_fn, aa, bb))
        }
    };
    Value::Function(Box::new(RustClosure(
        "string-2arg-partial".to_string(),
        Arc::new(Mutex::new(closure)),
        0,
    )))
}

pub fn make_three_arg_partial(
    finalize_fn: fn(Vec<Value>) -> Result<Value, String>,
    a_opt: Option<Value>,
    b_opt: Option<Value>,
    c_opt: Option<Value>,
) -> Value {
    let closure = move |_interp: &mut mumu::parser::interpreter::Interpreter, new_args: Vec<Value>| {
        let mut aa = a_opt.clone();
        let mut bb = b_opt.clone();
        let mut cc = c_opt.clone();
        for arg in new_args {
            if aa.is_none() {
                if is_placeholder(&arg) {} else { aa = Some(arg); }
                continue;
            }
            if bb.is_none() {
                if is_placeholder(&arg) {} else { bb = Some(arg); }
                continue;
            }
            if cc.is_none() {
                if is_placeholder(&arg) {} else { cc = Some(arg); }
                continue;
            }
            return Err("string => partial => too many arguments".to_string());
        }
        if aa.is_some() && bb.is_some() && cc.is_some() {
            finalize_fn(vec![
                aa.as_ref().unwrap().clone(),
                bb.as_ref().unwrap().clone(),
                cc.as_ref().unwrap().clone(),
            ])
        } else {
            Ok(make_three_arg_partial(finalize_fn, aa, bb, cc))
        }
    };
    Value::Function(Box::new(RustClosure(
        "string-3arg-partial".to_string(),
        Arc::new(Mutex::new(closure)),
        0,
    )))
}