flow-mumu 0.1.4

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

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

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

fn flow_drain_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 {
                drain_finalize(interp, a.clone())
            }
        }
        n => Err(format!("flow:drain => expected 0 or 1 argument, got {}", n)),
    }
}

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

    Value::Function(Box::new(RustClosure(
        "flow:drain-partial".to_string(),
        Arc::new(Mutex::new(move |interp: &mut Interpreter, new_args: Vec<Value>| {
            let mut s = src_opt.clone();
            for a in new_args {
                if s.is_none() {
                    if !is_placeholder(&a) { s = Some(a); }
                    continue;
                }
                return Err("flow:drain => partial => too many arguments".to_string());
            }
            if let Some(v) = s.clone() {
                drain_finalize(interp, v)
            } else {
                Ok(make_partial(s))
            }
        })),
        0,
    )))
}

fn drain_finalize(interp: &mut Interpreter, src: Value) -> Result<Value, String> {
    let tf = to_transform(src)?;
    let mut count: i32 = 0;
    loop {
        match apply_n_ary_function_value(interp, tf.clone(), vec![]) {
            Ok(_v) => {
                count = count.saturating_add(1);
            }
            Err(e) if e == "NO_MORE_DATA" => break,
            Err(e) => return Err(e),
        }
    }
    Ok(Value::Int(count))
}