use crate::graph::{Edge, EdgeKey, FileFacts, Symbol};
use crate::symbol::SymbolId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ScopeSnapshotToken([u8; 32]);
impl ScopeSnapshotToken {
pub const fn new(bytes: [u8; 32]) -> Self {
Self(bytes)
}
pub const fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
#[derive(Debug)]
pub enum FileChange<'a> {
Upsert(&'a FileFacts),
Remove(&'a str),
}
#[derive(Debug)]
pub struct ScopeGraphDelta {
pub base_snapshot: ScopeSnapshotToken,
pub snapshot: ScopeSnapshotToken,
pub removed_symbols: Vec<SymbolId>,
pub upserted_symbols: Vec<Symbol>,
pub removed_edges: Vec<EdgeKey>,
pub upserted_edges: Vec<Edge>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn snapshot_token_exposes_its_exact_bytes_and_compares_by_value() {
let bytes = [42; 32];
let token = ScopeSnapshotToken::new(bytes);
assert_eq!(token.as_bytes(), &bytes);
assert_eq!(token, ScopeSnapshotToken::new(bytes));
assert_ne!(token, ScopeSnapshotToken::new([43; 32]));
}
#[test]
fn public_delta_values_construct_without_mutation_state() {
let facts = FileFacts {
file: "src/lib.rs".into(),
lang: "rust".into(),
symbols: Vec::new(),
references: Vec::new(),
scopes: Vec::new(),
bindings: Vec::new(),
ffi_exports: Vec::new(),
};
let change = FileChange::Upsert(&facts);
let removed = FileChange::Remove("src/old.rs");
let base_snapshot = ScopeSnapshotToken::new([1; 32]);
let snapshot = ScopeSnapshotToken::new([2; 32]);
let delta = ScopeGraphDelta {
base_snapshot,
snapshot,
removed_symbols: Vec::new(),
upserted_symbols: Vec::new(),
removed_edges: Vec::new(),
upserted_edges: Vec::new(),
};
assert!(matches!(change, FileChange::Upsert(file) if file.file == "src/lib.rs"));
assert!(matches!(removed, FileChange::Remove("src/old.rs")));
assert_eq!(delta.base_snapshot, base_snapshot);
assert_eq!(delta.snapshot, snapshot);
assert!(delta.removed_symbols.is_empty());
assert!(delta.upserted_symbols.is_empty());
assert!(delta.removed_edges.is_empty());
assert!(delta.upserted_edges.is_empty());
}
}