1use crate::trace::hasher::canonical_hash;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::fs;
7use std::path::{Path, PathBuf};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct CacheEntry {
11 pub key: String,
12 pub tool_id: String,
13 pub version: String,
14 pub policy_hash: String,
15 pub inputs_hash: String,
16 pub outputs: serde_json::Value,
17}
18
19pub struct CacheStore {
20 cache_dir: PathBuf,
21 memory: HashMap<String, CacheEntry>,
22}
23
24impl CacheStore {
25 pub fn new(base_dir: &Path) -> Self {
26 let cache_dir = base_dir.join("cache");
27 fs::create_dir_all(&cache_dir).ok();
28 Self {
29 cache_dir,
30 memory: HashMap::new(),
31 }
32 }
33
34 pub fn get(&self, key: &str) -> Option<&CacheEntry> {
35 self.memory.get(key)
36 }
37
38 pub fn put(&mut self, entry: CacheEntry) {
39 let path = self
40 .cache_dir
41 .join(format!("{}.json", &entry.key[7..71.min(entry.key.len())]));
42 if let Ok(json) = serde_json::to_string_pretty(&entry) {
43 fs::write(&path, json).ok();
44 }
45 self.memory.insert(entry.key.clone(), entry);
46 }
47
48 pub fn lookup(
49 &self,
50 tool_id: &str,
51 version: &str,
52 policy_hash: &str,
53 args: &serde_json::Value,
54 ) -> Option<&CacheEntry> {
55 let args_hash = canonical_hash(args);
56 let key = crate::trace::hasher::cache_key(tool_id, version, policy_hash, &args_hash);
57 self.get(&key)
58 }
59}