mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-19 00:03:30 +00:00
132 lines
3 KiB
Rust
132 lines
3 KiB
Rust
mod routing;
|
|
|
|
use std::collections::HashMap;
|
|
use std::sync::Arc;
|
|
|
|
use fabro_core::error::{Error as CoreError, Result as CoreResult};
|
|
use fabro_core::graph::{EdgeSelection as CoreEdgeSelection, EdgeSpec, Graph, NodeSpec};
|
|
use fabro_graphviz::graph::types::{Edge as GvEdge, Graph as GvGraph, Node as GvNode};
|
|
|
|
use crate::context::Context;
|
|
use crate::outcome::{BilledModelUsage, Outcome};
|
|
|
|
// ---- WorkflowNode ----
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(crate) struct WorkflowNode(pub Arc<GvNode>);
|
|
|
|
impl WorkflowNode {
|
|
pub(crate) fn inner(&self) -> &GvNode {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl NodeSpec for WorkflowNode {
|
|
fn id(&self) -> &str {
|
|
&self.0.id
|
|
}
|
|
|
|
fn is_terminal(&self) -> bool {
|
|
routing::is_terminal(&self.0)
|
|
}
|
|
|
|
fn max_visits(&self) -> Option<usize> {
|
|
self.0
|
|
.max_visits()
|
|
.map(|v| usize::try_from(v.max(0)).unwrap_or(usize::MAX))
|
|
}
|
|
}
|
|
|
|
// ---- WorkflowEdge ----
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(crate) struct WorkflowEdge(pub Arc<GvEdge>);
|
|
|
|
impl WorkflowEdge {
|
|
pub(crate) fn inner(&self) -> &GvEdge {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl EdgeSpec for WorkflowEdge {
|
|
fn target(&self) -> &str {
|
|
&self.0.to
|
|
}
|
|
|
|
fn label(&self) -> Option<&str> {
|
|
self.0.label()
|
|
}
|
|
|
|
fn is_loop_restart(&self) -> bool {
|
|
self.0.loop_restart()
|
|
}
|
|
}
|
|
|
|
// ---- WorkflowGraph ----
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub(crate) struct WorkflowGraph(pub Arc<GvGraph>);
|
|
|
|
impl WorkflowGraph {
|
|
pub(crate) fn inner(&self) -> &GvGraph {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl Graph for WorkflowGraph {
|
|
type Node = WorkflowNode;
|
|
type Edge = WorkflowEdge;
|
|
type Meta = Option<BilledModelUsage>;
|
|
|
|
fn get_node(&self, id: &str) -> Option<Self::Node> {
|
|
self.0
|
|
.nodes
|
|
.get(id)
|
|
.map(|n| WorkflowNode(Arc::new(n.clone())))
|
|
}
|
|
|
|
fn find_start_node(&self) -> CoreResult<Self::Node> {
|
|
self.0
|
|
.find_start_node()
|
|
.map(|n| WorkflowNode(Arc::new(n.clone())))
|
|
.ok_or(CoreError::NoStartNode)
|
|
}
|
|
|
|
fn outgoing_edges(&self, node_id: &str) -> Vec<Self::Edge> {
|
|
self.0
|
|
.outgoing_edges(node_id)
|
|
.into_iter()
|
|
.map(|e| WorkflowEdge(Arc::new(e.clone())))
|
|
.collect()
|
|
}
|
|
|
|
fn select_edge(
|
|
&self,
|
|
node: &Self::Node,
|
|
outcome: &Outcome,
|
|
context: &Context,
|
|
) -> Option<CoreEdgeSelection<Self>> {
|
|
let selection = routing::select_edge(
|
|
node.inner(),
|
|
outcome,
|
|
context,
|
|
self.inner(),
|
|
node.inner().selection(),
|
|
);
|
|
selection.map(|sel| CoreEdgeSelection {
|
|
edge: WorkflowEdge(Arc::new(sel.edge.clone())),
|
|
reason: sel.reason,
|
|
})
|
|
}
|
|
|
|
fn check_goal_gates(
|
|
&self,
|
|
outcomes: &HashMap<String, Outcome>,
|
|
) -> std::result::Result<(), String> {
|
|
routing::check_goal_gates(self.inner(), outcomes)
|
|
}
|
|
|
|
fn get_retry_target(&self, failed_node_id: &str) -> Option<String> {
|
|
routing::get_retry_target(failed_node_id, self.inner())
|
|
}
|
|
}
|