1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use serde::de::Visitor;
use serde::{Deserialize, Serialize};

use crate::commands::execution::{ConditionExecution, ConditionResult};
use crate::context::PicoContext;
use crate::rules::PicoRules;
use crate::runtime::PicoRuntime;

use regex::Regex;

/*
 * existance or not of variables in the context
 */

#[derive(Serialize, Debug)]
#[serde(untagged)]
pub enum VarExistence {
    SingleVar(String),
    ManyVar(Vec<String>),
}

#[derive(Debug)]
struct VarExistsVisitor;
impl<'de> Visitor<'de> for VarExistsVisitor {
    type Value = VarExistence;

    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        error!("varexistvistior: expecting {:?}", self);
        formatter.write_str("string or array of strings")
    }

    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
    where
        E: serde::de::Error,
    {
        info!("Checking value: {}", value);
        let re: Regex = Regex::new("^[a-z]+$").unwrap();
        if re.is_match(value) {
            return Ok(VarExistence::SingleVar(value.to_string()));
        }

        //error!("exists must be lower case");
        //Err(E::custom("llll"))
        Ok(VarExistence::SingleVar(value.to_string()))
    }

    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
    where
        E: serde::de::StdError,
    {
        Ok(VarExistence::SingleVar(value.to_string()))
    }

    fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    where
        A: serde::de::SeqAccess<'de>,
    {
        let mut arr = Vec::with_capacity(seq.size_hint().unwrap_or(0));
        while let Some(item) = seq.next_element()? {
            arr.push(item);
        }

        info!("VarExistVisitor - seq {:?}", arr);
        Ok(VarExistence::ManyVar(arr))
    }
}

impl<'de> Deserialize<'de> for VarExistence {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        deserializer.deserialize_any(VarExistsVisitor)
    }
}

/// Checks for the existence of a variable
#[derive(Serialize, Deserialize, Debug)]
pub struct VarExistsCondition {
    exists: VarExistence,
}

impl ConditionExecution for VarExistsCondition {
    fn run_with_context(
        &self,
        pico_rules: &PicoRules,
        _runtime: &mut PicoRuntime,
        ctx: &mut PicoContext,
    ) -> ConditionResult {
        match &self.exists {
            VarExistence::SingleVar(s) => {
                if let Some(_v) = ctx.get_value(s) {
                    return Ok(true);
                }
            }
            VarExistence::ManyVar(vs) => {
                for v in vs {
                    match ctx.get_value(v) {
                        None => return Ok(false),
                        Some(_) => {}
                    }
                }
                // not yet exited early, all vars existed
                return Ok(true);
            }
        }

        Ok(false)
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct VarMissingCondition {
    missing: String,
}
impl ConditionExecution for VarMissingCondition {
    fn run_with_context(
        &self,
        _pico_rules: &PicoRules,
        _runtime: &mut PicoRuntime,
        ctx: &mut PicoContext,
    ) -> ConditionResult {
        match ctx.get_value(&self.missing) {
            Some(_v) => Ok(false),
            None => Ok(true),
        }
    }
}