mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-08-31 05:47:22 +00:00
Remove node, add edge and neigbour methods added to caching graph ft. comments and tests
This commit is contained in:
parent
375f7f45a7
commit
57dfa45d9c
5 changed files with 100 additions and 33 deletions
34
server/Cargo.lock
generated
34
server/Cargo.lock
generated
|
@ -112,8 +112,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
dependencies = [
|
||||
"base64 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -233,8 +233,8 @@ dependencies = [
|
|||
"lsp-types 0.74.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustdt-json_rpc 0.3.0 (git+https://github.com/strager/rustdt-json_rpc?branch=serde-1.0)",
|
||||
"rustdt_util 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -245,8 +245,8 @@ dependencies = [
|
|||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustdt_util 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -269,15 +269,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.108"
|
||||
version = "1.0.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.108"
|
||||
version = "1.0.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -287,12 +287,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.52"
|
||||
version = "1.0.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -366,7 +366,7 @@ dependencies = [
|
|||
"idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -379,8 +379,8 @@ dependencies = [
|
|||
"petgraph 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 1.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rust_lsp 0.6.0 (git+https://github.com/Strum355/RustLSP)",
|
||||
"serde 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
@ -460,9 +460,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum rustdt_util 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7cfffa8a89d8758be2dd5605c5fc62bce055af2491ebf3ce953d4d31512c59fd"
|
||||
"checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
|
||||
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
"checksum serde 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)" = "98b4e9fadb50ff90c1e758e42f13a8e2ab84e1927abb0aa5b95e5ecdb49ea741"
|
||||
"checksum serde_derive 1.0.108 (registry+https://github.com/rust-lang/crates.io-index)" = "6a316eba8a61ba986e87e7e04a74f9feda86298fb454b76232ead4e425976090"
|
||||
"checksum serde_json 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "a7894c8ed05b7a3a279aeb79025fdec1d3158080b75b98a08faf2806bb799edd"
|
||||
"checksum serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c"
|
||||
"checksum serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984"
|
||||
"checksum serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2"
|
||||
"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
|
||||
"checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4"
|
||||
"checksum syn 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "e8e5aa70697bb26ee62214ae3288465ecec0000f05182f039b477001f08f5ae7"
|
||||
|
|
|
@ -6,12 +6,12 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
rust_lsp = { git = "https://github.com/Strum355/RustLSP" }
|
||||
serde_json = "1.0.52"
|
||||
serde = "1.0.107"
|
||||
serde_json = "1.0.53"
|
||||
serde = "1.0.110"
|
||||
walkdir = "2.3.1"
|
||||
petgraph = "0.5.0"
|
||||
petgraph = "0.5.1"
|
||||
lazy_static = "1.4.0"
|
||||
regex = "1.3.7"
|
||||
regex = "1.3.9"
|
||||
chan = "0.1.23"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
@ -1,2 +1,4 @@
|
|||
.PHONY: watchtest
|
||||
|
||||
watchtest:
|
||||
RUST_BACKTRACE=0 cargo watch -x test -i Makefile
|
|
@ -1,10 +1,19 @@
|
|||
use petgraph::stable_graph::StableDiGraph;
|
||||
use petgraph::stable_graph::NodeIndex;
|
||||
use petgraph::stable_graph::EdgeIndex;
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// Wraps a `StableDiGraph` with caching behaviour for node search by maintaining
|
||||
/// an index for node value to node index and a reverse index.
|
||||
/// This allows for O(1) lookup for a value after the initial lookup.
|
||||
pub struct CachedStableGraph {
|
||||
// StableDiGraph is used as it allows for String node values, essential for
|
||||
// generating the GraphViz DOT render.
|
||||
pub graph: StableDiGraph<String, String>,
|
||||
cache: HashMap<String, NodeIndex>,
|
||||
// Maps a node index to its abstracted string representation.
|
||||
// Mainly used as the graph is based on NodeIndex and
|
||||
reverse_index: HashMap<NodeIndex, String>,
|
||||
}
|
||||
|
||||
impl CachedStableGraph {
|
||||
|
@ -12,25 +21,50 @@ impl CachedStableGraph {
|
|||
CachedStableGraph{
|
||||
graph: StableDiGraph::new(),
|
||||
cache: HashMap::new(),
|
||||
reverse_index: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn find_node(&mut self, name: String) -> Option<NodeIndex> {
|
||||
match self.cache.get(&name) {
|
||||
/// Returns the `NodeIndex` for a given graph node with the value of `name`
|
||||
/// and caches the result in the `HashMap`. Complexity is O(1) if the value
|
||||
/// is cached, else O(n) as an exhaustive search must be done.
|
||||
pub fn find_node(&mut self, name: impl Into<String>) -> Option<NodeIndex> {
|
||||
let name_str = name.into();
|
||||
match self.cache.get(&name_str) {
|
||||
Some(n) => Some(*n),
|
||||
None => {
|
||||
let n = self.graph.node_indices().find(|n| self.graph[*n] == name);
|
||||
// If the string is not in cache, O(n) search the graph (i know...) and then cache the NodeIndex
|
||||
// for later
|
||||
let n = self.graph.node_indices().find(|n| self.graph[*n] == name_str);
|
||||
if n.is_some() {
|
||||
self.cache.insert(name, n.unwrap());
|
||||
self.cache.insert(name_str, n.unwrap());
|
||||
}
|
||||
n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_node(&mut self, name: String) -> NodeIndex {
|
||||
let idx = self.graph.add_node(name.clone());
|
||||
self.cache.insert(name, idx);
|
||||
pub fn remove_node(&mut self, name: impl Into<String>) {
|
||||
let idx = self.cache.remove(&name.into());
|
||||
if idx.is_some() {
|
||||
self.graph.remove_node(idx.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_node<S: Into<String>>(&mut self, name: S) -> NodeIndex {
|
||||
let name_str = name.into();
|
||||
let idx = self.graph.add_node(name_str.clone());
|
||||
self.cache.insert(name_str.clone(), idx);
|
||||
self.reverse_index.insert(idx, name_str);
|
||||
idx
|
||||
}
|
||||
|
||||
pub fn add_edge(&mut self, a: NodeIndex, b: NodeIndex) -> EdgeIndex {
|
||||
self.graph.add_edge(a, b, String::from("includes"))
|
||||
}
|
||||
|
||||
/// Returns the filepaths of the neighbors for the given `NodeIndex`
|
||||
pub fn neighbors(&self, node: NodeIndex) -> Vec<String> {
|
||||
self.graph.neighbors(node).map(|n| self.reverse_index.get(&n).unwrap().clone()).collect()
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@ impl io::Write for StdoutNewline {
|
|||
if buf[buf.len()-1] == "}".as_bytes()[0] {
|
||||
#[allow(unused_variables)]
|
||||
let res = self.s.write("\n\n".as_bytes());
|
||||
|
||||
}
|
||||
res
|
||||
}
|
||||
|
@ -42,6 +41,13 @@ fn new_temp_server() -> MinecraftShaderLanguageServer {
|
|||
}
|
||||
}
|
||||
|
||||
fn copy_files(files: &str, dest: &TempDir) {
|
||||
let opts = &fs_extra::dir::CopyOptions::new();
|
||||
let files = fs::read_dir(files).unwrap().map(|e| String::from(e.unwrap().path().as_os_str().to_str().unwrap())).collect::<Vec<String>>();
|
||||
fs_extra::copy_items(&files, dest.path().join("shaders"), opts).unwrap();
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[test]
|
||||
fn test_empty_initialize() {
|
||||
let mut server = new_temp_server();
|
||||
|
@ -84,6 +90,7 @@ fn test_empty_initialize() {
|
|||
//std::thread::sleep(std::time::Duration::from_secs(1));
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
#[test]
|
||||
fn test_01_initialize() {
|
||||
let mut server = new_temp_server();
|
||||
|
@ -91,9 +98,7 @@ fn test_01_initialize() {
|
|||
let tmp_dir = TempDir::new("mcshader").unwrap();
|
||||
fs::create_dir(tmp_dir.path().join("shaders")).unwrap();
|
||||
|
||||
let opts = &fs_extra::dir::CopyOptions::new();
|
||||
let files = fs::read_dir("./testdata/01").unwrap().map(|e| String::from(e.unwrap().path().as_os_str().to_str().unwrap())).collect::<Vec<String>>();
|
||||
fs_extra::copy_items(&files, tmp_dir.path().join("shaders"), opts).unwrap();
|
||||
copy_files("./testdata/01", &tmp_dir);
|
||||
|
||||
let tmp_path = tmp_dir.path().as_os_str().to_str().unwrap();
|
||||
let tmp_uri = format!("{}{}", "file://", tmp_path);
|
||||
|
@ -121,10 +126,36 @@ fn test_01_initialize() {
|
|||
let completable = MethodCompletable::new(ResponseCompletable::new(Some(Id::Number(1)), Box::new(on_response)));
|
||||
server.initialize(initialize_params, completable);
|
||||
|
||||
// Assert there is one edge between two nodes
|
||||
assert_eq!(server.graph.borrow().graph.edge_count(), 1);
|
||||
|
||||
let edge = server.graph.borrow().graph.edge_indices().next().unwrap();
|
||||
let (node1, node2) = server.graph.borrow().graph.edge_endpoints(edge).unwrap();
|
||||
|
||||
// Assert the values of the two nodes in the tree
|
||||
assert_eq!(server.graph.borrow().graph[node1].as_str(), tmp_dir.path().join("shaders").join("final.fsh").as_os_str().to_str().unwrap());
|
||||
assert_eq!(server.graph.borrow().graph[node2].as_str(), tmp_dir.path().join("shaders").join("common.glsl").as_os_str().to_str().unwrap());
|
||||
|
||||
server.endpoint.request_shutdown();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_graph_two_connected_nodes() {
|
||||
let mut graph = graph::CachedStableGraph::new();
|
||||
|
||||
graph.add_node("sample");
|
||||
graph.add_node("banana");
|
||||
let idx1 = graph.find_node("sample").unwrap();
|
||||
let idx2 = graph.find_node("banana").unwrap();
|
||||
graph.add_edge(idx1, idx2);
|
||||
|
||||
let neighbors = graph.neighbors(idx1);
|
||||
assert_eq!(neighbors.len(), 1);
|
||||
assert_eq!(neighbors[0], "banana");
|
||||
|
||||
graph.remove_node("sample");
|
||||
assert_eq!(graph.graph.node_count(), 1);
|
||||
assert!(graph.find_node("sample").is_none());
|
||||
let neighbors = graph.neighbors(idx2);
|
||||
assert_eq!(neighbors.len(), 0);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue