use std::path::Path;
use tree_sitter::{InputEdit, Tree};
use super::edge::CodeEdge;
use super::error::GraphResult;
use super::node::Language;
use super::unified::build::staging::StagingGraph;
use super::unified::concurrent::GraphSnapshot;
pub trait GraphBuilder: Send + Sync {
fn build_graph(
&self,
tree: &Tree,
content: &[u8],
file: &Path,
staging: &mut StagingGraph,
) -> GraphResult<()>;
fn language(&self) -> Language;
fn update_graph(
&self,
tree: &Tree,
content: &[u8],
file: &Path,
edit: &InputEdit,
staging: &mut StagingGraph,
) -> GraphResult<()> {
let _ = edit;
self.build_graph(tree, content, file, staging)
}
fn detect_cross_language_edges(&self, _snapshot: &GraphSnapshot) -> GraphResult<Vec<CodeEdge>> {
Ok(Vec::new())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
use std::sync::{
Arc,
atomic::{AtomicUsize, Ordering},
};
use tree_sitter::{InputEdit, Parser, Point};
use crate::graph::node::Language;
struct TestBuilder {
language: Language,
build_calls: Arc<AtomicUsize>,
}
impl TestBuilder {
fn new(language: Language, build_calls: Arc<AtomicUsize>) -> Self {
Self {
language,
build_calls,
}
}
}
impl GraphBuilder for TestBuilder {
fn build_graph(
&self,
_tree: &Tree,
_content: &[u8],
_file: &Path,
_staging: &mut StagingGraph,
) -> GraphResult<()> {
self.build_calls.fetch_add(1, Ordering::SeqCst);
Ok(())
}
fn language(&self) -> Language {
self.language
}
}
fn parse_rust_tree(source: &str) -> Tree {
let mut parser = Parser::new();
let language = tree_sitter_rust::LANGUAGE;
parser
.set_language(&language.into())
.expect("set Rust language");
parser.parse(source, None).expect("parse rust source")
}
fn dummy_edit() -> InputEdit {
InputEdit {
start_byte: 0,
old_end_byte: 0,
new_end_byte: 0,
start_position: Point { row: 0, column: 0 },
old_end_position: Point { row: 0, column: 0 },
new_end_position: Point { row: 0, column: 0 },
}
}
#[test]
fn test_update_graph_defaults_to_build_graph() {
let build_calls = Arc::new(AtomicUsize::new(0));
let builder = TestBuilder::new(Language::Rust, Arc::clone(&build_calls));
let tree = parse_rust_tree("fn main() {}");
let mut staging = StagingGraph::new();
let file = PathBuf::from("src/main.rs");
builder
.update_graph(
&tree,
"fn main() {}".as_bytes(),
&file,
&dummy_edit(),
&mut staging,
)
.expect("update_graph");
assert_eq!(build_calls.load(Ordering::SeqCst), 1);
}
#[test]
fn test_default_cross_language_edges_is_empty() {
use crate::graph::unified::concurrent::CodeGraph;
let build_calls = Arc::new(AtomicUsize::new(0));
let builder = TestBuilder::new(Language::Rust, build_calls);
let graph = CodeGraph::new();
let snapshot = graph.snapshot();
let edges = builder
.detect_cross_language_edges(&snapshot)
.expect("default detect");
assert!(edges.is_empty());
}
}