- df-ai: context 历史中毒三档自愈 sanitize_messages(AC3)+anthropic_compat tool_use_id None 跳过(AC1/AC2)+删 router/stream 死码
- df-core: events 加 select_type+decisions 多选审批契约(F-260615-01)
- df-execute: shell run_command 工具复用(F-260615-05)
- df-nodes: human_node 多选校验+2 端到端测(F-01)+取消跳 set_failed(B-03b-R1/R2/R8)
- df-workflow: executor/dag/state cancel 闭环(B-06/07/03a/b)+provider approve options(R-PD-5)
- df-storage: find_path_conflict 抽公共(R-PD-11)+COLS 常量断言
- df-ideas: 删 IdeaPromoter/PromotionPolicy 死码(R-PD-14)
- src-tauri/commands/ai: secret keyring 迁移(FR-S1/R-PD-4)+GeneratingGuard RAII+disarm(B-09/26)+newConversation 软复位(B-10)+stream 心跳/stop select/空回复判错(B-02/04/05/15)+run_command(F-05)+mask audit(AR-3)
- src-tauri/commands/{project,task,workflow,mod,lib,state}: task detail IPC(F-02)+approve decisions+task list 联动(B-29)
- Cargo.lock+Cargo.toml 依赖同步
138 lines
4.1 KiB
Rust
138 lines
4.1 KiB
Rust
//! DAG(有向无环图)定义与拓扑排序
|
||
|
||
use std::collections::{HashMap, HashSet, VecDeque};
|
||
|
||
use df_core::error::Result;
|
||
use df_core::types::NodeId;
|
||
|
||
use crate::node::Node;
|
||
|
||
/// 图的边:从 source 到 target
|
||
#[derive(Debug, Clone)]
|
||
pub struct Edge {
|
||
pub source: NodeId,
|
||
pub target: NodeId,
|
||
/// 边的条件表达式(可选)
|
||
pub condition: Option<String>,
|
||
}
|
||
|
||
/// DAG 结构
|
||
pub struct Dag {
|
||
/// 节点集合
|
||
pub nodes: HashMap<NodeId, Box<dyn Node>>,
|
||
/// 边集合
|
||
pub edges: Vec<Edge>,
|
||
}
|
||
|
||
impl Dag {
|
||
/// 创建空 DAG
|
||
pub fn new() -> Self {
|
||
Self {
|
||
nodes: HashMap::new(),
|
||
edges: Vec::new(),
|
||
}
|
||
}
|
||
|
||
/// 添加节点
|
||
pub fn add_node(&mut self, id: NodeId, node: Box<dyn Node>) {
|
||
self.nodes.insert(id, node);
|
||
}
|
||
|
||
/// 添加边
|
||
pub fn add_edge(&mut self, source: NodeId, target: NodeId) {
|
||
self.edges.push(Edge {
|
||
source,
|
||
target,
|
||
condition: None,
|
||
});
|
||
}
|
||
|
||
/// 添加带条件的边
|
||
pub fn add_edge_with_condition(
|
||
&mut self,
|
||
source: NodeId,
|
||
target: NodeId,
|
||
condition: String,
|
||
) {
|
||
self.edges.push(Edge {
|
||
source,
|
||
target,
|
||
condition: Some(condition),
|
||
});
|
||
}
|
||
|
||
/// 拓扑排序 — 返回按执行顺序排列的节点 ID 层级
|
||
///
|
||
/// 返回 Vec<Vec<NodeId>>,每层内的节点可以并行执行。
|
||
///
|
||
/// 复杂度:O(V+E)。一次性遍历边构建邻接索引(出边表)与入度表,
|
||
/// BFS 分层只走索引查询(每条边仅被访问一次),不再为每个节点全表扫描边集合。
|
||
pub fn topological_layers(&self) -> Result<Vec<Vec<NodeId>>> {
|
||
let node_ids: HashSet<NodeId> = self.nodes.keys().cloned().collect();
|
||
let mut in_degree: HashMap<NodeId, usize> = HashMap::new();
|
||
// 邻接出边表:source → 直接后继列表(仅含两端均在 nodes 内的有效边)
|
||
let mut adjacency_out: HashMap<NodeId, Vec<NodeId>> = HashMap::new();
|
||
|
||
// 初始化入度(确保每个节点都有表项,便于后续 O(1) 修改)
|
||
for id in &node_ids {
|
||
in_degree.insert(id.clone(), 0);
|
||
}
|
||
// 单次 O(E) 遍历:同时构建入度表与出边表
|
||
for edge in &self.edges {
|
||
// 仅收录两端均为已注册节点的边,跳过野节点
|
||
if node_ids.contains(&edge.source) && node_ids.contains(&edge.target) {
|
||
*in_degree.get_mut(&edge.target).unwrap() += 1;
|
||
adjacency_out
|
||
.entry(edge.source.clone())
|
||
.or_default()
|
||
.push(edge.target.clone());
|
||
}
|
||
}
|
||
|
||
// BFS 分层
|
||
let mut layers = Vec::new();
|
||
let mut queue: VecDeque<NodeId> = in_degree
|
||
.iter()
|
||
.filter(|(_, °)| deg == 0)
|
||
.map(|(id, _)| id.clone())
|
||
.collect();
|
||
|
||
let mut processed = 0usize;
|
||
while !queue.is_empty() {
|
||
let mut layer: Vec<NodeId> = Vec::new();
|
||
let layer_size = queue.len();
|
||
for _ in 0..layer_size {
|
||
if let Some(id) = queue.pop_front() {
|
||
layer.push(id.clone());
|
||
// 出边已索引,O(出度) 遍历而非 O(E) 全表扫描
|
||
if let Some(succs) = adjacency_out.get(&id) {
|
||
for succ in succs {
|
||
let deg = in_degree.get_mut(succ).unwrap();
|
||
*deg -= 1;
|
||
if *deg == 0 {
|
||
queue.push_back(succ.clone());
|
||
}
|
||
}
|
||
}
|
||
processed += 1;
|
||
}
|
||
}
|
||
layers.push(layer);
|
||
}
|
||
|
||
if processed != node_ids.len() {
|
||
return Err(df_core::error::Error::Workflow(
|
||
"DAG 中存在环,无法进行拓扑排序".to_string(),
|
||
));
|
||
}
|
||
|
||
Ok(layers)
|
||
}
|
||
}
|
||
|
||
impl Default for Dag {
|
||
fn default() -> Self {
|
||
Self::new()
|
||
}
|
||
}
|