use std::collections::HashSet;
use jsonapi::model::*;
use super::common::{Document, DocumentList};
pub type XFlowDocument = Document<XFlow>;
jsonapi_model!(XFlowDocument; "xflow");
pub type XFlowDocumentList = DocumentList<XFlow>;
pub type XFlowEdge = (i32, i32);
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct XFlow {
pub requirements: Vec<XFlowRequirement>,
pub variables: XFlowVariables,
pub nodes: Vec<XFlowNode>,
pub edges: Vec<XFlowEdge>,
pub branches: Vec<XFlowBranch>,
}
#[derive(Debug)]
pub enum XFlowError {
NoEntryNode,
NoTerminalNode,
MultipleEntryNodes,
DuplicateNodeIDs,
NodeNotFound,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub enum XFlowValueType {
#[serde(rename = "string")]
String,
#[serde(rename = "number")]
Integer,
#[serde(rename = "boolean")]
Boolean,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
#[serde(untagged)]
pub enum XFlowValue {
String(String),
Integer(i64),
Boolean(bool),
}
impl XFlowValue {
pub fn string_value(&self) -> String {
match *self {
XFlowValue::String(ref s) => s.clone(),
XFlowValue::Integer(ref i) => i.to_string(),
XFlowValue::Boolean(ref b) => {
if *b {
"true".to_owned()
} else {
"false".to_owned()
}
}
}
}
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct XFlowRequirement {
pub xtype: XFlowNodeType,
pub version: i32,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct XFlowVariableDefinition {
pub name: String,
pub vtype: XFlowValueType,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct XFlowVariable {
pub name: String,
pub vtype: XFlowValueType,
pub value: XFlowValue,
}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct XFlowVariables {
pub input: Vec<XFlowVariableDefinition>,
pub local: Vec<XFlowVariable>,
pub output: Vec<XFlowVariableDefinition>,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct XFlowNode {
pub id: i32,
pub nodetype: XFlowNodeType,
pub action: String,
pub label: String,
pub parameters: XFlowNodeParameters,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Hash, Eq)]
pub enum XFlowNodeType {
#[serde(rename = "flow")]
Flow,
#[serde(rename = "flox")]
Flox,
#[serde(rename = "call")]
Call,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum XFlowNodeParameters {
#[serde(rename = "flow")]
Flow(FlowParameters),
#[serde(rename = "flox")]
Flox(FloxParameters),
#[serde(rename = "call")]
Call(CallParameters),
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct FlowParameters {}
impl Default for FlowParameters {
fn default() -> Self {
FlowParameters {}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct FloxParameters {
pub expression: String,
pub returns: XFlowVariableDefinition,
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct CallParameters {}
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
pub struct XFlowBranch {
pub edge: XFlowEdge,
pub xvar: XFlowVariable,
}
impl XFlow {
pub fn get_nodes_by(&self, nodetype: &XFlowNodeType, action: &str) -> Vec<&XFlowNode> {
self.nodes
.iter()
.filter({
|node| node.nodetype == *nodetype && node.action == action
})
.collect()
}
pub fn get_nodes_of_type(&self, nodetype: &XFlowNodeType) -> Vec<&XFlowNode> {
self.nodes
.iter()
.filter({
|node| node.nodetype == *nodetype
})
.collect()
}
pub fn all_variable_names(&self) -> HashSet<String> {
let mut vars = HashSet::<String>::new();
for xvar in &self.variables.input {
vars.insert(xvar.name.clone());
}
for xvar in &self.variables.local {
vars.insert(xvar.name.clone());
}
for xvar in &self.variables.output {
vars.insert(xvar.name.clone());
}
vars
}
pub fn get_in_edges(&self, node: &XFlowNode) -> Vec<&XFlowEdge> {
self.edges
.iter()
.filter({
|edge| edge.1 == node.id
})
.collect()
}
pub fn get_out_edges(&self, node: &XFlowNode) -> Vec<&XFlowEdge> {
self.edges
.iter()
.filter({
|edge| edge.0 == node.id
})
.collect()
}
pub fn get_branches_for(&self, edge: &XFlowEdge) -> Vec<&XFlowBranch> {
self.branches
.iter()
.filter({
|branch| edge.0 == branch.edge.0 && edge.1 == branch.edge.1
})
.collect()
}
pub fn get_out_branches(&self, id: i32) -> Vec<&XFlowBranch> {
self.branches
.iter()
.filter({
|branch| branch.edge.0 == id
})
.collect()
}
pub fn get_entry_node(&self) -> Result<&XFlowNode, XFlowError> {
let res = self.get_nodes_by(&XFlowNodeType::Flow, "start");
match res.len() {
0 => Err(XFlowError::NoEntryNode),
1 => Ok(res[0]),
_ => Err(XFlowError::MultipleEntryNodes),
}
}
pub fn get_terminal_nodes(&self) -> Result<Vec<&XFlowNode>, XFlowError> {
let res = self.get_nodes_by(&XFlowNodeType::Flow, "end");
match res.len() {
0 => Err(XFlowError::NoTerminalNode),
_ => Ok(res),
}
}
pub fn get_node_id(&self, id: i32) -> Option<&XFlowNode> {
let nodes: Vec<&XFlowNode> = self.nodes
.iter()
.filter({
|node| node.id == id
})
.collect();
match nodes.len() {
1 => {
match nodes.first() {
Some(node) => Some(node),
None => None,
}
}
_ => None,
}
}
pub fn get_all_variable_names(&self) -> HashSet<String> {
let mut names = HashSet::<String>::new();
for xvar in &self.variables.local {
if !names.contains(&xvar.name) {
names.insert(xvar.name.clone());
}
}
for xvar in &self.variables.input {
if !names.contains(&xvar.name) {
names.insert(xvar.name.clone());
}
}
for xvar in &self.variables.output {
if !names.contains(&xvar.name) {
names.insert(xvar.name.clone());
}
}
names
}
}
impl Default for XFlow {
fn default() -> Self {
let mut nodes = Vec::<XFlowNode>::new();
nodes.push(XFlowNode {
id: 1,
nodetype: XFlowNodeType::Flow,
action: "start".to_owned(),
label: "Start".to_owned(),
parameters: XFlowNodeParameters::Flow(FlowParameters::default()),
});
nodes.push(XFlowNode {
id: 2,
nodetype: XFlowNodeType::Flow,
action: "end".to_owned(),
label: "End".to_owned(),
parameters: XFlowNodeParameters::Flow(FlowParameters::default()),
});
let mut edges = Vec::<XFlowEdge>::new();
edges.push((1, 2));
let mut requirements = Vec::<XFlowRequirement>::new();
requirements.push(XFlowRequirement {
xtype: XFlowNodeType::Flow,
version: 1,
});
XFlow {
requirements: requirements,
variables: XFlowVariables {
input: Vec::<XFlowVariableDefinition>::new(),
local: Vec::<XFlowVariable>::new(),
output: Vec::<XFlowVariableDefinition>::new(),
},
nodes: nodes,
edges: edges,
branches: Vec::<XFlowBranch>::new(),
}
}
}