flow-mumu 0.1.4

Stream tranform tools plugin for the Lava language
Documentation
// src/common.rs

use std::sync::{Arc, Mutex};
use mumu::parser::interpreter::Interpreter;
use mumu::parser::types::{FunctionValue, IteratorHandle, IteratorKind, Value};

/// Returns true if a value represents the placeholder `_` used in partials.
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,
    }
}

/// Convert an `Iterator` handle into a zero-arg *transform function* that yields
/// the next item each call (or returns `NO_MORE_DATA` when exhausted).
pub fn iter_to_transform(handle: IteratorHandle) -> Box<FunctionValue> {
    use FunctionValue::RustClosure;

    Box::new(RustClosure(
        "flow:iter->transform".to_string(),
        Arc::new(Mutex::new(move |_interp: &mut Interpreter, _args: Vec<Value>| {
            match &handle.kind {
                IteratorKind::Core(state_arc) => {
                    let mut guard = state_arc
                        .lock()
                        .map_err(|_| "flow/common: iterator lock error".to_string())?;
                    if guard.done || guard.current >= guard.end {
                        guard.done = true;
                        Err("NO_MORE_DATA".to_string())
                    } else {
                        let item = guard.current;
                        guard.current += 1;
                        if guard.current >= guard.end {
                            guard.done = true;
                        }
                        Ok(Value::Int(item))
                    }
                }
                IteratorKind::Plugin(plugin_arc) => {
                    let mut plugin = plugin_arc
                        .lock()
                        .map_err(|_| "flow/common: plugin iterator lock error".to_string())?;
                    match plugin.next_value() {
                        Ok(v) => Ok(v),
                        Err(e) => Err(e),
                    }
                }
            }
        })),
        0,
    ))
}

/// Accept either an `Iterator` *or* an already-constructed transform
/// (`Value::Function`) and return a transform function.
pub fn to_transform(v: Value) -> Result<Box<FunctionValue>, String> {
    match v {
        // A transform is represented as a zero-arg function that yields the next value
        // or returns an error "NO_MORE_DATA" when exhausted.
        Value::Function(fb) => Ok(fb),

        // Core iterator handle — adapt it into a transform function.
        Value::Iterator(h) => Ok(iter_to_transform(h)),

        other => Err(format!(
            "flow/common: expected Iterator or transform Function, got {:?}",
            other
        )),
    }
}

/// A transform that yields the provided value once, then `NO_MORE_DATA`.
pub fn once_transform(v: Value) -> Box<FunctionValue> {
    use FunctionValue::RustClosure;

    let cell = Arc::new(Mutex::new(Some(v)));
    Box::new(RustClosure(
        "flow:once".to_string(),
        Arc::new(Mutex::new(move |_interp: &mut Interpreter, _args: Vec<Value>| {
            let mut guard = cell
                .lock()
                .map_err(|_| "flow/common: once lock error".to_string())?;
            match guard.take() {
                Some(x) => Ok(x),
                None => Err("NO_MORE_DATA".to_string()),
            }
        })),
        0,
    ))
}