array-mumu 0.2.0-rc.5

Array tools plugin for the Mumu ecosystem
Documentation
// src/collect.rs

use mumu::parser::interpreter::Interpreter;
use mumu::parser::types::{IteratorKind, Value};

pub fn array_collect_bridge(_interp: &mut Interpreter, mut args: Vec<Value>) -> Result<Value, String> {
    if args.len() != 1 {
        return Err(format!("array:collect expects exactly 1 argument, got {}", args.len()));
    }

    let v = args.remove(0);
    match v {
        // Already arrays: return as-is to preserve type
        Value::IntArray(xs)    => Ok(Value::IntArray(xs)),
        Value::FloatArray(xs)  => Ok(Value::FloatArray(xs)),
        Value::StrArray(xs)    => Ok(Value::StrArray(xs)),
        Value::BoolArray(xs)   => Ok(Value::BoolArray(xs)),
        Value::MixedArray(xs)  => Ok(Value::MixedArray(xs)),

        // Collect from an Iterator
        Value::Iterator(handle) => {
            match &handle.kind {
                // Core iterator yields consecutive ints
                IteratorKind::Core(state_arc) => {
                    let mut guard = state_arc
                        .lock()
                        .map_err(|_| "IteratorState lock error".to_string())?;
                    let mut out: Vec<i32> = Vec::new();
                    while !guard.done && guard.current < guard.end {
                        let next = guard.current;
                        guard.current += 1;
                        if guard.current >= guard.end {
                            guard.done = true;
                        }
                        out.push(next);
                    }
                    Ok(Value::IntArray(out))
                }

                // Plugin iterator can yield any Value — homogenize if possible
                IteratorKind::Plugin(plugin_arc) => {
                    let mut plugin = plugin_arc
                        .lock()
                        .map_err(|_| "Plugin Iterator lock error".to_string())?;
                    let mut items: Vec<Value> = Vec::new();
                    loop {
                        match plugin.next_value() {
                            Ok(val) => items.push(val),
                            Err(e) if e == "NO_MORE_DATA" => break,
                            Err(e) => return Err(format!("array:collect => {}", e)),
                        }
                    }

                    // Try to downcast to a concrete array type
                    if items.iter().all(|v| matches!(v, Value::Int(_))) {
                        Ok(Value::IntArray(
                            items
                                .into_iter()
                                .map(|v| if let Value::Int(i) = v { i } else { unreachable!() })
                                .collect(),
                        ))
                    } else if items.iter().all(|v| matches!(v, Value::Float(_))) {
                        Ok(Value::FloatArray(
                            items
                                .into_iter()
                                .map(|v| if let Value::Float(f) = v { f } else { unreachable!() })
                                .collect(),
                        ))
                    } else if items.iter().all(|v| matches!(v, Value::SingleString(_))) {
                        Ok(Value::StrArray(
                            items
                                .into_iter()
                                .map(|v| if let Value::SingleString(s) = v { s } else { unreachable!() })
                                .collect(),
                        ))
                    } else if items.iter().all(|v| matches!(v, Value::Bool(_))) {
                        Ok(Value::BoolArray(
                            items
                                .into_iter()
                                .map(|v| if let Value::Bool(b) = v { b } else { unreachable!() })
                                .collect(),
                        ))
                    } else {
                        Ok(Value::MixedArray(items))
                    }
                }
            }
        }

        other => Err(format!("array:collect => unsupported input: {:?}", other)),
    }
}