use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LsifGraph {
pub id: String,
pub protocol_version: String,
pub vertices: Vec<Vertex>,
pub edges: Vec<Edge>,
}
impl LsifGraph {
pub fn new() -> Self {
Self {
id: "lsif".to_string(),
protocol_version: "0.6.0".to_string(),
vertices: Vec::new(),
edges: Vec::new(),
}
}
pub fn add_vertex(&mut self, vertex: Vertex) {
self.vertices.push(vertex);
}
pub fn add_edge(&mut self, edge: Edge) {
self.edges.push(edge);
}
}
impl Default for LsifGraph {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum Vertex {
Package {
id: String,
label: String,
data: PackageData,
},
Document {
id: String,
label: String,
uri: String,
language_id: String,
},
Symbol {
id: String,
label: String,
kind: SymbolKind,
},
ResultSet { id: String, label: String },
Range {
id: String,
label: String,
range: [u32; 4], },
Moniker {
id: String,
label: String,
data: MonikerData,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PackageData {
pub name: String,
pub version: String,
pub manager: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MonikerData {
pub kind: MonikerKind,
pub identifier: String,
pub package: PackageData,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MonikerKind {
Import,
Export,
Local,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum SymbolKind {
Module,
Namespace,
Package,
Class,
Method,
Property,
Field,
Constructor,
Enum,
Interface,
Function,
Variable,
Constant,
String,
Number,
Boolean,
Array,
Object,
Key,
Null,
EnumMember,
Struct,
Event,
Operator,
TypeParameter,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum Edge {
Contains {
id: String,
label: String,
out_v: String,
in_vs: Vec<String>,
},
Moniker {
id: String,
label: String,
out_v: String,
in_v: String,
},
NextMoniker {
id: String,
label: String,
out_v: String,
in_v: String,
},
Item {
id: String,
label: String,
out_v: String,
in_vs: Vec<String>,
document: String,
},
TextDocument {
id: String,
label: String,
out_v: String,
in_v: String,
},
}
pub fn generate_lsif_id(prefix: &str, counter: &mut u32) -> String {
let id = format!("{}{}", prefix, counter);
*counter += 1;
id
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lsif_graph_creation() {
let graph = LsifGraph::new();
assert_eq!(graph.protocol_version, "0.6.0");
assert!(graph.vertices.is_empty());
assert!(graph.edges.is_empty());
}
#[test]
fn test_vertex_serialization() {
let vertex = Vertex::Package {
id: "p1".to_string(),
label: "package".to_string(),
data: PackageData {
name: "serde".to_string(),
version: "1.0.195".to_string(),
manager: "cargo".to_string(),
},
};
let json = serde_json::to_string(&vertex).unwrap();
assert!(json.contains("\"type\":\"package\""));
assert!(json.contains("\"name\":\"serde\""));
}
#[test]
fn test_edge_serialization() {
let edge = Edge::Contains {
id: "e1".to_string(),
label: "contains".to_string(),
out_v: "p1".to_string(),
in_vs: vec!["d1".to_string()],
};
let json = serde_json::to_string(&edge).unwrap();
assert!(json.contains("\"type\":\"contains\""));
assert!(json.contains("\"out_v\":\"p1\""));
}
}