use std::collections::HashMap;
use patricia_tree::GenericPatriciaMap;
use tree_sitter::Point;
pub type PackageId = usize;
pub type FileId = usize;
pub type TypeId = usize;
#[derive(Debug)]
pub struct Type {
pub name: String,
pub declarations: Vec<Declaration>, }
#[derive(Debug)]
pub struct Package {
name: String,
path_prefix: String,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Kind {
Struct,
Enum,
Class,
Protocol,
Extension,
}
#[derive(Debug)]
pub struct Declaration {
pub kind: Kind,
pub point: Point,
file: FileId,
dependencies: Vec<(TypeId, Point)>,
}
impl Declaration {
pub fn dependencies(&self) -> HashMap<TypeId, Vec<Point>> {
let mut deps = HashMap::new();
for (id, point) in &self.dependencies {
deps.entry(*id).or_insert(vec![]).push(*point)
}
deps
}
}
#[derive(Debug, Default)]
pub struct Index {
packages: Vec<Package>,
files: Vec<String>,
types: Vec<Type>,
file_ids: HashMap<String, FileId>,
package_ids: HashMap<String, PackageId>,
type_ids: HashMap<String, TypeId>,
packages_by_path: GenericPatriciaMap<String, PackageId>,
}
impl Index {
pub fn new() -> Self {
Self {
packages: vec![],
files: vec![],
types: vec![],
package_ids: HashMap::new(),
type_ids: HashMap::new(),
packages_by_path: GenericPatriciaMap::new(),
file_ids: HashMap::new(),
}
}
pub fn type_id(&self, name: &str) -> Option<TypeId> {
self.type_ids.get(name).map(|id| *id)
}
pub fn get_type(&self, type_id: TypeId) -> Option<&Type> {
self.types.get(type_id)
}
pub fn file_path(&self, declaration: &Declaration) -> Option<String> {
self.files.get(declaration.file).map(|p| p.clone())
}
pub fn add_package(&mut self, name: &str, path_prefix: &str) {
let name = name.to_string();
let path_prefix = path_prefix.to_string();
let package = Package {
name: name.to_string(),
path_prefix: path_prefix.clone(),
};
self.packages.push(package);
let package_id = self.packages.len() - 1;
self.package_ids.insert(name.to_string(), package_id);
self.packages_by_path.insert(path_prefix, package_id);
}
pub fn add_declaration(
&mut self,
name: &str,
kind: Kind,
file: &str,
point: Point,
references: &[(&str, &Point)],
) -> TypeId {
let file_id = *self.file_ids.entry(file.to_string()).or_insert_with(|| {
self.files.push(file.to_string());
self.files.len() - 1
});
let dependencies: Vec<_> = references
.iter()
.map(|(type_name, &ref_point)| {
let type_id = self.add_reference(type_name);
(type_id, ref_point)
})
.collect();
let declaration = Declaration {
kind,
point,
file: file_id,
dependencies,
};
match self.type_ids.get(name) {
Some(&type_id) => {
self.types[type_id].declarations.push(declaration);
type_id
}
None => {
let t = Type {
name: name.to_string(),
declarations: vec![declaration],
};
self.types.push(t);
self.types.len() - 1
}
}
}
pub fn add_reference(&mut self, name: &str) -> TypeId {
match self.type_ids.get(name) {
Some(&type_id) => type_id,
None => {
let t = Type {
name: name.to_string(),
declarations: vec![],
};
self.types.push(t);
let type_id = self.types.len() - 1;
self.type_ids.insert(name.to_string(), type_id);
type_id
}
}
}
}