1use std::collections::HashMap;
2use hd_cas::ContentHash;
3
4pub struct PathMap {
6 path_to_hash: HashMap<String, ContentHash>,
7 hash_to_path: HashMap<ContentHash, String>,
8}
9
10impl PathMap {
11 pub fn new() -> Self {
12 PathMap {
13 path_to_hash: HashMap::new(),
14 hash_to_path: HashMap::new(),
15 }
16 }
17
18 pub fn insert(&mut self, path: &str, hash: ContentHash) {
19 if let Some(old_hash) = self.path_to_hash.remove(path) {
21 self.hash_to_path.remove(&old_hash);
22 }
23 self.path_to_hash.insert(path.to_string(), hash);
24 self.hash_to_path.insert(hash, path.to_string());
25 }
26
27 pub fn get_hash(&self, path: &str) -> Option<&ContentHash> {
28 self.path_to_hash.get(path)
29 }
30
31 pub fn get_path(&self, hash: &ContentHash) -> Option<&str> {
32 self.hash_to_path.get(hash).map(|s| s.as_str())
33 }
34
35 pub fn remove(&mut self, path: &str) {
36 if let Some(hash) = self.path_to_hash.remove(path) {
37 self.hash_to_path.remove(&hash);
38 }
39 }
40
41 pub fn all_paths(&self) -> Vec<&str> {
42 self.path_to_hash.keys().map(|s| s.as_str()).collect()
43 }
44}
45
46impl Default for PathMap {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use hd_cas::ContentHash;
56
57 #[test]
58 fn insert_and_lookup_by_path() {
59 let mut map = PathMap::new();
60 let hash = ContentHash::from_bytes(b"file1");
61 map.insert("src/main.rs", hash);
62 assert_eq!(map.get_hash("src/main.rs"), Some(&hash));
63 }
64
65 #[test]
66 fn insert_and_lookup_by_hash() {
67 let mut map = PathMap::new();
68 let hash = ContentHash::from_bytes(b"file1");
69 map.insert("src/main.rs", hash);
70 assert_eq!(map.get_path(&hash), Some("src/main.rs"));
71 }
72
73 #[test]
74 fn update_replaces_mapping() {
75 let mut map = PathMap::new();
76 let h1 = ContentHash::from_bytes(b"v1");
77 let h2 = ContentHash::from_bytes(b"v2");
78 map.insert("file.rs", h1);
79 map.insert("file.rs", h2);
80 assert_eq!(map.get_hash("file.rs"), Some(&h2));
81 assert!(map.get_path(&h1).is_none()); }
83
84 #[test]
85 fn remove_by_path() {
86 let mut map = PathMap::new();
87 let hash = ContentHash::from_bytes(b"data");
88 map.insert("file.rs", hash);
89 map.remove("file.rs");
90 assert!(map.get_hash("file.rs").is_none());
91 assert!(map.get_path(&hash).is_none());
92 }
93
94 #[test]
95 fn all_paths() {
96 let mut map = PathMap::new();
97 map.insert("a.rs", ContentHash::from_bytes(b"a"));
98 map.insert("b.rs", ContentHash::from_bytes(b"b"));
99 let paths = map.all_paths();
100 assert_eq!(paths.len(), 2);
101 }
102}