codemem_engine/index/
incremental.rs1use sha2::{Digest, Sha256};
7use std::collections::HashMap;
8
9pub struct ChangeDetector {
11 known_hashes: HashMap<String, String>,
13}
14
15impl ChangeDetector {
16 pub fn new() -> Self {
18 Self {
19 known_hashes: HashMap::new(),
20 }
21 }
22
23 pub fn load_from_storage(&mut self, storage: &dyn codemem_core::StorageBackend) {
28 match storage.load_file_hashes() {
29 Ok(hashes) => {
30 tracing::debug!("Loaded {} known file hashes", hashes.len());
31 self.known_hashes = hashes;
32 }
33 Err(e) => {
34 tracing::warn!("Failed to load file hashes, starting fresh: {e}");
35 }
36 }
37 }
38
39 pub fn save_to_storage(
41 &self,
42 storage: &dyn codemem_core::StorageBackend,
43 ) -> Result<(), codemem_core::CodememError> {
44 storage.save_file_hashes(&self.known_hashes)
45 }
46
47 pub fn check_changed(&self, path: &str, content: &[u8]) -> (bool, String) {
50 let hash = Self::hash_content(content);
51 let changed = self.known_hashes.get(path) != Some(&hash);
52 (changed, hash)
53 }
54
55 pub fn record_hash(&mut self, path: &str, hash: String) {
57 self.known_hashes.insert(path.to_string(), hash);
58 }
59
60 #[cfg(test)]
63 pub fn is_changed(&self, path: &str, content: &[u8]) -> bool {
64 let hash = Self::hash_content(content);
65 self.known_hashes.get(path) != Some(&hash)
66 }
67
68 #[cfg(test)]
70 pub fn update_hash(&mut self, path: &str, content: &[u8]) {
71 let hash = Self::hash_content(content);
72 self.known_hashes.insert(path.to_string(), hash);
73 }
74
75 #[cfg(test)]
77 pub fn remove_hash(&mut self, path: &str) {
78 self.known_hashes.remove(path);
79 }
80
81 #[cfg(test)]
83 pub fn tracked_count(&self) -> usize {
84 self.known_hashes.len()
85 }
86
87 fn hash_content(content: &[u8]) -> String {
89 let mut hasher = Sha256::new();
90 hasher.update(content);
91 format!("{:x}", hasher.finalize())
92 }
93}
94
95impl Default for ChangeDetector {
96 fn default() -> Self {
97 Self::new()
98 }
99}
100
101#[cfg(test)]
102#[path = "tests/incremental_tests.rs"]
103mod tests;