use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use crate::types::*;
use crate::schema::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Guard {
pub ref_: String, pub args: HashMap<String, Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphElement {
pub id: String, #[serde(skip_serializing_if = "Option::is_none")]
pub type_: Option<Label>,
#[serde(skip_serializing_if = "Option::is_none")]
pub props: Option<Properties>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EdgeDef {
pub id: String,
pub src: String,
pub dst: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub type_: Option<Label>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphPattern {
pub nodes: Vec<GraphElement>,
pub edges: Vec<EdgeDef>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Nac {
pub nodes: Vec<GraphElement>,
pub edges: Vec<EdgeDef>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RuleIR {
pub name: String,
pub types: HashMap<String, Vec<Label>>, pub lhs: GraphPattern, pub context: GraphPattern, pub rhs: GraphPattern, pub nacs: Vec<Nac>, pub guards: Vec<Guard>, }
#[derive(Debug, Clone)]
pub struct Match {
pub mapping: HashMap<String, VertexId>, pub score: f64, }
pub type Matches = Vec<Match>;
impl RuleIR {
pub fn to_rule_dpo(&self) -> kotoba_core::types::Result<RuleDPO> {
let l = self.graph_pattern_to_instance(&self.lhs)?;
let k = self.graph_pattern_to_instance(&self.context)?;
let r = self.graph_pattern_to_instance(&self.rhs)?;
let nacs = self.nacs.iter()
.map(|nac| self.nac_to_dpo_nac(nac))
.collect::<Result<Vec<_>>>()?;
let m_l = self.generate_morphism(&l, &k)?;
let m_r = self.generate_morphism(&r, &k)?;
Ok(RuleDPO {
id: Id::new(&self.name)?,
l,
k,
r,
m_l,
m_r,
nacs,
app_cond: None, effects: None, })
}
fn graph_pattern_to_instance(&self, pattern: &GraphPattern) -> kotoba_core::types::Result<GraphInstance> {
use crate::cid::*;
let mut nodes = Vec::new();
let mut edges = Vec::new();
for node_elem in &pattern.nodes {
let node = Node {
cid: Cid::new(&format!("node_{}", node_elem.id)), labels: node_elem.type_.as_ref().map(|t| vec![t.clone()]).unwrap_or_default(),
r#type: node_elem.type_.clone().unwrap_or_else(|| "Node".to_string()),
ports: vec![], attrs: node_elem.props.clone().map(|props| {
props.into_iter().map(|(k, v)| (k, serde_json::to_value(v).unwrap())).collect()
}),
component_ref: None,
};
nodes.push(node);
}
for edge_def in &pattern.edges {
let edge = Edge {
cid: Cid::new(&format!("edge_{}", edge_def.id)), label: edge_def.type_.clone(),
r#type: edge_def.type_.clone().unwrap_or_else(|| "EDGE".to_string()),
src: edge_def.src.clone(),
tgt: edge_def.dst.clone(),
attrs: None,
};
edges.push(edge);
}
let graph_core = GraphCore {
nodes,
edges,
boundary: None, attrs: None,
};
Ok(GraphInstance {
core: graph_core,
kind: GraphKind::Instance,
cid: Cid::new(&format!("graph_{}", uuid::Uuid::new_v4())), typing: None,
})
}
fn nac_to_dpo_nac(&self, nac: &Nac) -> kotoba_core::types::Result<Nac> {
let graph = self.graph_pattern_to_instance(&GraphPattern {
nodes: nac.nodes.clone(),
edges: nac.edges.clone(),
})?;
let node_map: HashMap<String, String> = nac.nodes.iter()
.map(|node| (format!("nac_node_{}", node.id), format!("host_node_{}", node.id)))
.collect();
let edge_map: HashMap<String, String> = nac.edges.iter()
.map(|edge| (format!("nac_edge_{}", edge.id), format!("host_edge_{}", edge.id)))
.collect();
let morphism_from_l = Morphisms {
node_map,
edge_map,
port_map: HashMap::new(),
};
Ok(Nac {
id: Id::new(&format!("nac_{}", uuid::Uuid::new_v4()))?,
graph,
morphism_from_l,
})
}
fn generate_morphism(&self, from: &GraphInstance, to: &GraphInstance) -> kotoba_core::types::Result<Morphisms> {
let mut node_map = HashMap::new();
let mut edge_map = HashMap::new();
for from_node in &from.core.nodes {
for to_node in &to.core.nodes {
if from_node.r#type == to_node.r#type {
node_map.insert(from_node.cid.as_str().to_string(), to_node.cid.as_str().to_string());
break;
}
}
}
for from_edge in &from.core.edges {
for to_edge in &to.core.edges {
if from_edge.r#type == to_edge.r#type {
edge_map.insert(from_edge.cid.as_str().to_string(), to_edge.cid.as_str().to_string());
break;
}
}
}
Ok(Morphisms {
node_map,
edge_map,
port_map: HashMap::new(),
})
}
}