zuzu-rust 0.3.0

Rust implementation of ZuzuScript
Documentation
use std::collections::HashMap;

use super::super::{Runtime, Value};
use crate::error::{Result, ZuzuRustError};

pub(super) fn exports() -> HashMap<String, Value> {
    HashMap::from([
        ("Task".to_owned(), Value::builtin_class("Task".to_owned())),
        (
            "Channel".to_owned(),
            Value::builtin_class("Channel".to_owned()),
        ),
        (
            "CancellationToken".to_owned(),
            Value::builtin_class("CancellationToken".to_owned()),
        ),
        (
            "CancellationSource".to_owned(),
            Value::builtin_class("CancellationSource".to_owned()),
        ),
        (
            "resolved".to_owned(),
            Value::native_function("task.resolved".to_owned()),
        ),
        (
            "failed".to_owned(),
            Value::native_function("task.failed".to_owned()),
        ),
        (
            "sleep".to_owned(),
            Value::native_function("task.sleep".to_owned()),
        ),
        (
            "yield".to_owned(),
            Value::native_function("task.yield".to_owned()),
        ),
        (
            "all".to_owned(),
            Value::native_function("task.all".to_owned()),
        ),
        (
            "race".to_owned(),
            Value::native_function("task.race".to_owned()),
        ),
        (
            "timeout".to_owned(),
            Value::native_function("task.timeout".to_owned()),
        ),
    ])
}

pub(super) fn call(runtime: &Runtime, name: &str, args: &[Value]) -> Option<Result<Value>> {
    let result = match name {
        "task.resolved" => Ok(runtime.task_resolved(args.first().cloned().unwrap_or(Value::Null))),
        "task.failed" => Ok(runtime.task_rejected(
            args.first()
                .cloned()
                .unwrap_or_else(|| Value::String("Task failed".to_owned()))
                .render(),
        )),
        "task.sleep" => Ok(runtime.task_sleep(
            args.first()
                .map(|value| value.to_number().unwrap_or(0.0))
                .unwrap_or(0.0),
        )),
        "task.yield" => Ok(runtime.task_yield()),
        "task.all" => {
            let tasks = match args.first() {
                Some(Value::Array(items)) => items.clone(),
                Some(_) => {
                    return Some(Err(ZuzuRustError::runtime(
                        "TypeException: task combinator expects Array",
                    )))
                }
                None => Vec::new(),
            };
            if tasks.iter().any(|task| !matches!(task, Value::Task(_))) {
                return Some(Err(ZuzuRustError::runtime("all expects only Task values")));
            }
            Ok(runtime.task_all(tasks))
        }
        "task.race" => {
            let tasks = match args.first() {
                Some(Value::Array(items)) => items.clone(),
                Some(_) => {
                    return Some(Err(ZuzuRustError::runtime(
                        "TypeException: task combinator expects Array",
                    )))
                }
                None => Vec::new(),
            };
            if tasks.is_empty() {
                return Some(Err(ZuzuRustError::runtime(
                    "race expects at least one task",
                )));
            }
            if tasks.iter().any(|task| !matches!(task, Value::Task(_))) {
                return Some(Err(ZuzuRustError::runtime("race expects only Task values")));
            }
            Ok(runtime.task_race(tasks))
        }
        "task.timeout" => {
            if args.len() != 2 {
                Err(ZuzuRustError::runtime("timeout() expects seconds and task"))
            } else if !matches!(args[1], Value::Task(_)) {
                Err(ZuzuRustError::runtime("timeout expects a Task"))
            } else {
                Ok(runtime.task_timeout(args[0].to_number().unwrap_or(0.0), args[1].clone()))
            }
        }
        _ => return None,
    };
    Some(result)
}