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))
}