zuzu-rust 0.6.0

Rust implementation of ZuzuScript
Documentation
use crate::{Result, ZuzuRustError};

use super::super::{Runtime, Value};
use super::common::{
    collection_product, collection_sum, expect_function, make_iterator, require_arity, stored_arg,
    unique_values, CollectionTarget,
};

impl Runtime {
    pub(in crate::runtime) fn call_bag_method(
        &self,
        values: &mut Vec<Value>,
        name: &str,
        args: &[Value],
    ) -> Result<Value> {
        match name {
            "add" | "push" => {
                values.extend(args.iter().cloned().map(Value::into_shared_if_composite));
                Ok(Value::Bag(values.clone()))
            }
            "add_weak" | "push_weak" => {
                values.extend(args.iter().map(|value| stored_arg(value, true)));
                Ok(Value::Bag(values.clone()))
            }
            "copy" => {
                require_arity(name, args, 0)?;
                Ok(Value::Bag(values.clone()))
            }
            "remove" => {
                require_arity(name, args, 1)?;
                values.retain(|value| !value.strict_eq(&args[0]));
                Ok(Value::Bag(values.clone()))
            }
            "remove_first" => {
                require_arity(name, args, 1)?;
                let mut removed = false;
                values.retain(|value| {
                    if !removed && value.strict_eq(&args[0]) {
                        removed = true;
                        false
                    } else {
                        true
                    }
                });
                Ok(Value::Bag(values.clone()))
            }
            "length" => {
                require_arity(name, args, 0)?;
                Ok(Value::Number(values.len() as f64))
            }
            "count" => {
                if args.is_empty() {
                    return Ok(Value::Number(values.len() as f64));
                }
                require_arity(name, args, 1)?;
                Ok(Value::Number(
                    values
                        .iter()
                        .filter(|value| value.strict_eq(&args[0]))
                        .count() as f64,
                ))
            }
            "empty" | "is_empty" => {
                require_arity(name, args, 0)?;
                Ok(Value::Boolean(values.is_empty()))
            }
            "clear" => {
                require_arity(name, args, 0)?;
                values.clear();
                Ok(Value::Bag(values.clone()))
            }
            "contains" => {
                require_arity(name, args, 1)?;
                Ok(Value::Boolean(
                    values.iter().any(|value| value.strict_eq(&args[0])),
                ))
            }
            "to_Array" => {
                require_arity(name, args, 0)?;
                Ok(Value::Array(values.clone()))
            }
            "to_Set" | "uniq" => {
                require_arity(name, args, 0)?;
                Ok(Value::Set(unique_values(values)))
            }
            "to_Iterator" => {
                require_arity(name, args, 0)?;
                Ok(make_iterator(values.clone()))
            }
            "sum" => {
                require_arity(name, args, 0)?;
                Ok(Value::Number(collection_sum(values)?))
            }
            "product" => {
                require_arity(name, args, 0)?;
                Ok(Value::Number(collection_product(values)?))
            }
            "sort" => {
                let mut out = values.clone();
                self.call_array_method(&mut out, "sort", args)
            }
            "sortstr" => {
                let mut out = values.clone();
                self.call_array_method(&mut out, "sortstr", args)
            }
            "sortnum" => {
                let mut out = values.clone();
                self.call_array_method(&mut out, "sortnum", args)
            }
            "map" => self.map_values(values, args, "map", CollectionTarget::Bag),
            "grep" => self.filter_values(values, args, "grep", CollectionTarget::Bag),
            "any" => self.any_values(values, args),
            "all" => self.all_values(values, args),
            "first" => self.first_value(values, args),
            "remove_if" => {
                require_arity(name, args, 1)?;
                let pred =
                    expect_function(&args[0], "Collection method expects a function callback")?;
                values.retain(|value| {
                    !self
                        .predicate_callback(&pred, value.clone())
                        .unwrap_or(false)
                });
                Ok(Value::Bag(values.clone()))
            }
            "for_each_value" => {
                require_arity(name, args, 1)?;
                let func =
                    expect_function(&args[0], "Collection method expects a function callback")?;
                for value in values.iter().cloned() {
                    let _ = self.call_function(&func, vec![value], Vec::new())?;
                }
                Ok(Value::Bag(values.clone()))
            }
            other => Err(ZuzuRustError::thrown(format!(
                "unsupported Bag method '{}'",
                other
            ))),
        }
    }
}