mirror of
https://github.com/gorules/zen.git
synced 2026-10-04 08:02:28 +00:00
fix: no early cutoff between documents in the same sub-decision cycle
Inside a decision-call cycle a recorded signature depends on which member was cut off as recursive, so comparing it could skip a dependent (seen when undoing an edit in a 3-graph cycle).
This commit is contained in:
@@ -7,6 +7,7 @@ use crate::workspace::reads::ReadView;
|
||||
impl Db {
|
||||
pub(crate) fn walk(&self, changed: &[Arc<str>]) -> Vec<Arc<str>> {
|
||||
let frozen = self.frozen_views();
|
||||
let cycles = self.document_dependencies().signature_cycles();
|
||||
self.document_dependencies()
|
||||
.affected(changed, |user, dependency, kind| {
|
||||
let recorded = frozen
|
||||
@@ -20,8 +21,13 @@ impl Db {
|
||||
| (DependencyKind::Signature, ReadView::Signature(_))
|
||||
)
|
||||
});
|
||||
let cyclic = kind == DependencyKind::Signature
|
||||
&& cycles
|
||||
.get(user)
|
||||
.is_some_and(|component| cycles.get(dependency) == Some(component));
|
||||
match (kind, recorded) {
|
||||
(DependencyKind::Import, _) | (_, None) => true,
|
||||
_ if cyclic => true,
|
||||
(_, Some(view)) => {
|
||||
self.graph_stack.borrow_mut().push(user.clone());
|
||||
let holds = self.view_holds(dependency, view);
|
||||
|
||||
@@ -2,6 +2,8 @@ use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ahash::{HashMap, HashSet};
|
||||
use petgraph::algo::tarjan_scc;
|
||||
use petgraph::graph::{DiGraph, NodeIndex};
|
||||
use zen_types::decision::DecisionNodeKind;
|
||||
|
||||
use crate::model::DecisionContent;
|
||||
@@ -94,6 +96,38 @@ impl DependencyIndex {
|
||||
out
|
||||
}
|
||||
|
||||
pub fn signature_cycles(&self) -> HashMap<Arc<str>, usize> {
|
||||
let mut graph: DiGraph<Arc<str>, ()> = DiGraph::new();
|
||||
let mut nodes: HashMap<Arc<str>, NodeIndex> = HashMap::default();
|
||||
let mut node = |graph: &mut DiGraph<Arc<str>, ()>, path: &Arc<str>| {
|
||||
*nodes
|
||||
.entry(path.clone())
|
||||
.or_insert_with(|| graph.add_node(path.clone()))
|
||||
};
|
||||
for (user, uses) in &self.uses {
|
||||
for (dependency, kind) in uses {
|
||||
if *kind == DependencyKind::Signature {
|
||||
let from = node(&mut graph, user);
|
||||
let to = node(&mut graph, dependency);
|
||||
graph.add_edge(from, to, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut out: HashMap<Arc<str>, usize> = HashMap::default();
|
||||
for (id, component) in tarjan_scc(&graph).into_iter().enumerate() {
|
||||
let cyclic = component.len() > 1
|
||||
|| component
|
||||
.first()
|
||||
.is_some_and(|&n| graph.contains_edge(n, n));
|
||||
if cyclic {
|
||||
for n in component {
|
||||
out.insert(graph[n].clone(), id);
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
fn declared(content: &DecisionContent) -> Vec<Dependency> {
|
||||
let mut out: Vec<Dependency> = Vec::new();
|
||||
let mut push = |path: &Arc<str>, kind: DependencyKind| {
|
||||
|
||||
Reference in New Issue
Block a user