yao 0.1.4

a fast, tiny, extensiable workflow engine
Documentation
use crate::{sch::Task, ActError, ActResult, Context, Step, TaskState};
use regex::Regex;

#[derive(Debug, Default, Clone)]
pub enum Matcher {
    #[default]
    Empty,
    One,
    Any,
    All,
    Ord(Option<String>),
    Some(String),
    Error,
}

impl Matcher {
    pub fn capture(expr: &str) -> Matcher {
        let mut ret = Matcher::Empty;
        if expr.starts_with("one") {
            ret = Matcher::One;
        } else if expr.starts_with("any") {
            ret = Matcher::Any;
        } else if expr.starts_with("some") {
            let re = Regex::new(r"some\((.*)\)$").unwrap();
            let caps = re.captures(&expr);

            if let Some(caps) = caps {
                let value = caps.get(1).map_or("", |m| m.as_str());
                ret = Matcher::Some(value.to_string());
            } else {
                ret = Matcher::Error;
            }
        } else if expr.starts_with("all") {
            ret = Matcher::All;
        } else if expr.starts_with("ord") {
            ret = Matcher::Ord(None);

            let re = Regex::new(r"ord\((.*)\)$").unwrap();
            let caps = re.captures(&expr);

            if let Some(caps) = caps {
                let value = caps.get(1).map_or("", |m| m.as_str());
                ret = Matcher::Ord(Some(value.to_string()));
            }
        }

        ret
    }

    pub fn is_pass(&self, step: &Step, ctx: &Context) -> ActResult<bool> {
        match self {
            Matcher::Empty | Matcher::Error => {
                Err(ActError::SubjectError("matcher is empty".to_string()))
            }
            Matcher::One => {
                if let Some(act) = step.acts().get(0) {
                    return Ok(act.state() == TaskState::Success);
                }

                Ok(false)
            }
            Matcher::Any => {
                let mut ret = false;
                step.acts().iter().for_each(|act| {
                    let state = act.state();
                    if state == TaskState::Success {
                        ret = true;
                    } else {
                        act.set_state(&TaskState::Skip);
                    }
                });

                Ok(ret)
            }
            Matcher::All => {
                let ret = step
                    .acts()
                    .iter()
                    .all(|act| act.state() == TaskState::Success);

                Ok(ret)
            }
            Matcher::Ord(_) => {
                let ord = step.ord() + 1;
                let len = step.candidates().len();
                let ret = ord == len;
                if !ret {
                    if let Some(act) = step.candidates().get(ord) {
                        act.set_state(&TaskState::WaitingEvent);
                        step.set_ord(ord);
                        step.push_act(&act);

                        let task = Task::Act(act.id(), act.clone());
                        ctx.proc.tree.push_act(&task, &act.step_task_id);
                        ctx.send_message(&act.owner, &task);
                    }
                }

                Ok(ret)
            }
            Matcher::Some(rule) => match ctx.proc.scher.some(&rule, step, ctx) {
                Ok(ret) => {
                    if ret {
                        step.acts().iter().for_each(|act| {
                            let state = act.state();
                            if state != TaskState::Success {
                                act.set_state(&TaskState::Skip);
                            }
                        });
                    }

                    Ok(ret)
                }

                Err(err) => Err(err),
            },
        }
    }
}