chord-flow 0.1.21

async parallel case executor
Documentation
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
use std::sync::Arc;

use handlebars::Handlebars;

use chord_core::action::{Arg, Chord};
use chord_core::action::{Context, Id};
use chord_core::action::{Creator, Error};
use chord_core::case::CaseId;
use chord_core::flow::Flow;
use chord_core::step::StepId;
use chord_core::value::{Map, Value};

use crate::{App, flow};
use crate::model::app::RenderContext;

#[derive(Clone)]
pub struct StepIdStruct {
    step: String,
    case_id: Arc<dyn CaseId>,
}

impl StepId for StepIdStruct {
    fn step(&self) -> &str {
        self.step.as_str()
    }

    fn case_id(&self) -> &dyn CaseId {
        self.case_id.as_ref()
    }
}

impl Display for StepIdStruct {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        f.write_str(format!("{}-{}", self.case_id, self.step).as_str())
    }
}


#[derive(Clone)]
pub struct ActionIdStruct {
    aid: String,
    step_id: StepIdStruct,
}

impl Id for ActionIdStruct {
    fn clone(&self) -> Box<dyn Id> {
        let id = Clone::clone(self);
        Box::new(id)
    }
}

impl Display for ActionIdStruct {
    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
        f.write_str(format!("{}-{}", self.step_id, self.aid).as_str())
    }
}


pub struct ChordStruct {
    creator_map: Arc<HashMap<String, Box<dyn Creator>>>,
    app: Arc<dyn App>,
}

impl ChordStruct {
    pub fn new(app: Arc<dyn App>) -> ChordStruct {
        ChordStruct {
            creator_map: app.get_creator_map().clone(),
            app,
        }
    }

    fn render(handlebars: &Handlebars, context: &dyn Context, raw: &Value) -> Result<Value, Error> {
        let mut val = raw.clone();
        let rc = RenderContext::wraps(context.data())?;
        flow::render_value(handlebars, &rc, &mut val)?;
        Ok(val)
    }
}

impl Chord for ChordStruct {
    fn creator(&self, action: &str) -> Option<&dyn Creator> {
        let creator_op = self.creator_map.get(action);
        creator_op.map(|a| a.as_ref())
    }

    fn render(&self, context: &dyn Context, raw: &Value) -> Result<Value, Error> {
        ChordStruct::render(self.app.get_handlebars(), context, raw)
    }

    fn clone(&self) -> Box<dyn Chord> {
        Box::new(ChordStruct::new(self.app.clone()))
    }
}

pub struct ArgStruct<'a, 'f> {
    app: &'a dyn App,
    flow: &'f Flow,
    context: ContextStruct,
    step_id: StepIdStruct,
    action_id: ActionIdStruct,
}

impl<'a, 'f> ArgStruct<'a, 'f> {
    pub fn new(
        app: &'a dyn App,
        flow: &'f Flow,
        context: RenderContext,
        case_id: Arc<dyn CaseId>,
        step_id: String,
    ) -> ArgStruct<'a, 'f> {
        let context = ContextStruct { ctx: context };

        let step_id = StepIdStruct {
            case_id,
            step: step_id,
        };

        let run_arg = ArgStruct {
            app,
            flow,
            context,
            step_id: step_id.clone(),
            action_id: ActionIdStruct {
                aid: "".to_string(),
                step_id,
            },
        };

        return run_arg;
    }

    pub fn step_id(self: &ArgStruct<'a, 'f>) -> &StepIdStruct {
        return &self.step_id;
    }

    pub fn aid(&mut self, aid: &str) {
        self.action_id = ActionIdStruct {
            aid: aid.to_string(),
            step_id: self.step_id.clone(),
        }
    }

    pub fn context_mut(&mut self) -> &mut dyn Context {
        &mut self.context
    }

    pub fn flow(&self) -> &Flow {
        self.flow
    }
}

impl<'a, 'f> Arg for ArgStruct<'a, 'f> {
    fn id(&self) -> &dyn Id {
        &self.action_id
    }

    fn context(&self) -> &dyn Context {
        &self.context
    }

    fn args_raw(&self) -> &Value {
        self.flow
            .step_action_args(self.step_id().step(), self.action_id.aid.as_str())
    }

    fn args(&self) -> Result<Value, Error> {
        ChordStruct::render(&self.app.get_handlebars(), &self.context, self.args_raw())
    }

    fn context_mut(&mut self) -> &mut dyn Context {
        &mut self.context
    }

    fn args_init(&self) -> Option<&Value> {
        let raw = self.args_raw();
        if let Value::Object(obj) = raw {
            obj.get("__init__")
        } else {
            None
        }
    }
}

#[derive(Clone)]
struct ContextStruct {
    ctx: RenderContext,
}

impl AsRef<RenderContext> for ContextStruct {
    fn as_ref(&self) -> &RenderContext {
        &self.ctx
    }
}

impl Context for ContextStruct {
    fn data(&self) -> &Map {
        self.ctx.data().as_object().unwrap()
    }

    fn data_mut(&mut self) -> &mut Map {
        self.ctx.data_mut().as_object_mut().unwrap()
    }

    fn clone(&self) -> Box<dyn Context> {
        let ctx = Clone::clone(self);
        Box::new(ctx)
    }
}