Fixed dfs cycle detection unwinding

This commit is contained in:
Noah Santschi-Cooney 2020-07-28 01:35:30 +01:00
parent 0028e0ac9a
commit 1250c81365
No known key found for this signature in database
GPG key ID: 3B22282472C8AE48
6 changed files with 141 additions and 33 deletions

88
server/Cargo.lock generated
View file

@ -74,6 +74,15 @@ name = "futures"
version = "0.1.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "hamcrest2"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "idna"
version = "0.2.0"
@ -146,6 +155,76 @@ name = "memchr"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-complex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-complex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-rational"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "percent-encoding"
version = "2.1.0"
@ -413,6 +492,7 @@ dependencies = [
"bit-set 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"chan 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)",
"fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hamcrest2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"petgraph 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -477,6 +557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
"checksum hamcrest2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49f837c62de05dc9cc71ff6486cd85de8856a330395ae338a04bfcefe5e91075"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum indexmap 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c398b2b113b55809ceb9ee3e753fcbac793f1956663f3c36549c1346015c2afe"
"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
@ -487,6 +568,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum lsp-types 0.77.0 (git+https://github.com/gluon-lang/lsp-types?branch=master)" = "<none>"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
"checksum num 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36"
"checksum num-bigint 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304"
"checksum num-complex 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95"
"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
"checksum num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f"
"checksum num-rational 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef"
"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
"checksum petgraph 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7"
"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa"

View file

@ -21,4 +21,5 @@ thiserror = "1.0.20"
[dev-dependencies]
tempdir = "0.3.7"
fs_extra = "1.1.0"
fs_extra = "1.1.0"
hamcrest2 = "*"

View file

@ -3,5 +3,8 @@
watchtest:
RUST_BACKTRACE=0 cargo watch -x test -i Makefile
test:
RUST_LIB_BACKTRACE=0 cargo test
build:
cargo build --release

View file

@ -4,7 +4,7 @@ use thiserror::Error;
use crate::graph::CachedStableGraph;
use anyhow::{Result, Context, format_err};
use anyhow::{Result, Error};
use std::fmt::{Debug, Display};
/// Performs a depth-first search with duplicates
@ -23,7 +23,35 @@ impl <'a> Dfs<'a> {
}
}
pub fn next(&mut self) -> Option<Result<NodeIndex>> {
fn reset_path_to_branch(&mut self) {
while let Some(par) = self.cycle.pop() {
if self.graph.graph.edges(par).count() > 0 {
self.cycle.pop();
break;
}
}
}
fn check_for_cycle(&self, children: &[NodeIndex]) -> Result<()> {
for prev in &self.cycle {
for child in children {
if *prev == *child {
return Err(
Error::new(
CycleError::new(&self.cycle, *child, self.graph)
)
);
}
}
}
Ok(())
}
}
impl <'a> Iterator for Dfs<'a> {
type Item = Result<NodeIndex>;
fn next(&mut self) -> Option<Result<NodeIndex>> {
if let Some(node) = self.stack.pop() {
self.cycle.push(node);
@ -48,28 +76,12 @@ impl <'a> Dfs<'a> {
self.stack.push(child);
}
} else {
self.cycle.pop();
self.reset_path_to_branch();
}
return Some(Ok(node));
}
None
}
fn check_for_cycle(&self, children: &[NodeIndex]) -> Result<()> {
for prev in &self.cycle {
for child in children {
if *prev == *child {
return Err(
format_err!("cycle detected")
).with_context(||
CycleError::new(&self.cycle, *child, self.graph)
);
}
}
}
Ok(())
}
}
#[derive(Debug, Error)]

View file

@ -357,11 +357,14 @@ impl MinecraftShaderLanguageServer {
let graph_ref = self.graph.borrow();
let mut dfs = dfs::Dfs::new(&graph_ref, root);
let dfs = dfs::Dfs::new(&graph_ref, root);
//let slice_stack = Vec::new();
let iteration_order: Vec<_> = dfs.collect::<Result<Vec<_>, _>>()?;
while let Some(n) = dfs.next() {
for n in dfs {
if n.is_err() {
return Err(n.err().unwrap());
}

View file

@ -1,9 +1,14 @@
use super::*;
use std::io;
use std::io::Result;
use tempdir::TempDir;
use std::fs;
use hamcrest2::prelude::*;
use tempdir::TempDir;
use petgraph::algo::is_cyclic_directed;
use fs_extra::{dir, copy_items};
use jsonrpc_common::*;
@ -220,12 +225,12 @@ fn test_graph_dfs() {
graph.add_edge(idx4, idx6, 4, 0, 0);
graph.add_edge(idx6, idx7, 4, 0, 0);
let mut dfs = dfs::Dfs::new(&graph, idx0);
let dfs = dfs::Dfs::new(&graph, idx0);
let mut collection = Vec::new();
while let Some(i) = dfs.next() {
assert_eq!(i.is_ok(), true);
for i in dfs {
assert_that!(&i, ok());
collection.push(i.unwrap());
}
@ -237,12 +242,8 @@ fn test_graph_dfs() {
// \ /
// 6 - 7
let expected = vec![idx0, idx1, idx3, idx6, idx7, idx4, idx6, idx7, idx2, idx5, idx4, idx6, idx7];
println!("{:?}\n{:?}", expected, collection);
collection.reverse();
for i in expected {
assert_eq!(i, collection.pop().unwrap());
}
assert_eq!(expected, collection);
assert!(!is_cyclic_directed(&graph.graph));
}
@ -277,7 +278,7 @@ fn test_graph_dfs_cycle() {
for _ in 0..5 {
if let Some(i) = dfs.next() {
assert_eq!(i.is_ok(), true);
assert_that!(&i, ok());
}
}
@ -292,7 +293,7 @@ fn test_graph_dfs_cycle() {
assert!(is_cyclic_directed(&graph.graph));
let next = dfs.next().unwrap();
assert_eq!(next.is_err(), true);
assert_that!(next, err());
}
{