flow-mumu 0.1.4

Stream tranform tools plugin for the Lava language
Documentation
use std::sync::{Arc, Mutex};
use mumu::parser::interpreter::{Interpreter, DynamicFnInfo};
use mumu::parser::types::{Value, FunctionValue};
use crate::common::{is_placeholder, once_transform};

pub fn register_flow_of(interp: &mut Interpreter) {
    let f = Arc::new(Mutex::new(flow_of_bridge));
    let info = DynamicFnInfo::new(f, true);
    interp.register_dynamic_function_ex("flow:of", info);

    interp.set_variable(
        "flow:of",
        Value::Function(Box::new(FunctionValue::Named("flow:of".to_string())))
    );
}

fn flow_of_bridge(_interp: &mut Interpreter, args: Vec<Value>) -> Result<Value, String> {
    match args.len() {
        0 => Ok(make_partial(None)),
        1 => {
            let a = &args[0];
            if is_placeholder(a) {
                Ok(make_partial(None))
            } else {
                // Emit a single value as a zero-arg transform function.
                Ok(Value::Function(once_transform(a.clone())))
            }
        }
        n => Err(format!("flow:of => expected 0 or 1 argument, got {}", n)),
    }
}

fn make_partial(val_opt: Option<Value>) -> Value {
    use mumu::parser::types::FunctionValue::RustClosure;

    Value::Function(Box::new(RustClosure(
        "flow:of-partial".to_string(),
        Arc::new(Mutex::new(move |_interp: &mut Interpreter, new_args: Vec<Value>| {
            let mut v = val_opt.clone();
            for a in new_args {
                if v.is_none() {
                    if is_placeholder(&a) {
                        // remain None
                    } else {
                        v = Some(a);
                    }
                    continue;
                }
                return Err("flow:of => partial => too many arguments".to_string());
            }
            if let Some(x) = v.clone() {
                Ok(Value::Function(once_transform(x)))
            } else {
                Ok(make_partial(v))
            }
        })),
        0,
    )))
}