rush_core 0.1.2

The rules engine is based on the rete algorithm
Documentation
use crate::{Function, FunctionSet, Rush};
use anyhow::anyhow;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::Arc;
use wd_tools::sync::Acl;
use wd_tools::{PFErr, PFOk};

#[derive(Default, Debug)]
pub struct Env {
    envs: Acl<HashMap<String, String>>,
}
impl Env {
    #[allow(dead_code)]
    pub fn add_env_variable<S: Into<String>>(&mut self, key: S, value: S) {
        self.envs.update(|arc| {
            let mut map = HashMap::new();
            for (k, v) in arc.iter() {
                map.insert(k.to_string(), v.to_string());
            }
            map.insert(key.into(), value.into());
            map
        });
    }
    #[allow(dead_code)]
    pub fn add_env_variables<Map: Into<HashMap<String, String>>>(&mut self, mp: Map) {
        self.envs.update(|arc| {
            let mut map = HashMap::new();
            for (k, v) in arc.iter() {
                map.insert(k.to_string(), v.to_string());
            }
            for (k, v) in mp.into() {
                map.insert(k, v);
            }
            map
        });
    }
}
impl From<HashMap<String, String>> for Env {
    fn from(envs: HashMap<String, String>) -> Self {
        let envs = Acl::new(envs);
        Env { envs }
    }
}
impl From<Acl<HashMap<String, String>>> for Env {
    fn from(envs: Acl<HashMap<String, String>>) -> Self {
        Env { envs }
    }
}
impl Rush {
    pub fn set_env<E: Into<Env>>(self, env: E) -> Self {
        self.raw_register_function("env", env.into())
    }
}

impl Function for Env {
    fn call(&self, _fs: Arc<dyn FunctionSet>, args: Vec<Value>) -> anyhow::Result<Value> {
        if args.len() < 1 {
            return anyhow!("must have a args").err();
        }
        if let Value::String(key) = args.get(0).unwrap() {
            if let Some(s) = self.envs.share().get(key) {
                return Value::String(s.to_string()).ok();
            }
        }
        return Value::String(String::new()).ok();
    }
}

pub struct ArrayContain;

impl ArrayContain {
    fn contain(array: &Vec<Value>, des: &Value) -> bool {
        match des {
            Value::Null => {
                for i in array {
                    if i.is_null() {
                        return true;
                    }
                }
            }
            Value::Bool(d) => {
                for i in array {
                    if let Some(s) = i.as_bool() {
                        if &s == d {
                            return true;
                        }
                    }
                }
            }
            Value::Number(n) => {
                if let Some(n) = n.as_i64() {
                    for i in array {
                        if let Some(i) = i.as_i64() {
                            if n == i {
                                return true;
                            }
                        }
                    }
                }
            }
            Value::String(s) => {
                for i in array {
                    if let Some(i) = i.as_str() {
                        if s == i {
                            return true;
                        }
                    }
                }
            }
            Value::Array(ref list) => {
                for i in list {
                    if !Self::contain(array, i) {
                        return false;
                    }
                }
                return true;
            }
            Value::Object(_) => {}
        };
        return false;
    }
}

impl Function for ArrayContain {
    fn call(&self, _fs: Arc<dyn FunctionSet>, mut args: Vec<Value>) -> anyhow::Result<Value> {
        if args.len() < 2 {
            return anyhow!("ArrayContain: must have two args").err();
        }
        let array = if let Value::Array(array) = args.remove(0) {
            array
        } else {
            return anyhow!("ArrayContain: first input must is array").err();
        };
        let des = args.remove(0);
        Ok(Value::Bool(ArrayContain::contain(&array, &des)))
    }
}

pub struct ArraySub;
impl Function for ArraySub {
    fn call(&self, _fs: Arc<dyn FunctionSet>, mut args: Vec<Value>) -> anyhow::Result<Value> {
        if args.len() < 2 {
            return anyhow!("ArrayContain: must have two args").err();
        }
        let la = if let Value::Array(array) = args.remove(0) {
            array
        } else {
            return anyhow!("ArrayContain: first input must is array").err();
        };
        let ra = if let Value::Array(array) = args.remove(0) {
            array
        } else {
            return anyhow!("ArrayContain: second input must is array").err();
        };
        for i in la {
            for j in &ra {
                if &i == j {
                    return Ok(Value::Bool(true));
                }
            }
        }
        return Ok(Value::Bool(false));
    }
}