use lru::LruCache;
use parking_lot::Mutex;
use std::num::NonZeroUsize;
const SHARD_COUNT: usize = 64;
#[derive(Clone, Debug)]
pub struct SecretFragment {
pub prefix: String,
pub var_name: String,
pub value: String,
pub line: usize,
pub path: Option<String>,
}
pub struct FragmentCache {
shards: [Mutex<LruCache<String, Vec<SecretFragment>>>; SHARD_COUNT],
}
impl FragmentCache {
pub fn new(capacity: usize) -> Self {
let per_shard = (capacity / SHARD_COUNT).max(1);
let nz = NonZeroUsize::new(per_shard).unwrap_or(NonZeroUsize::MIN);
Self {
shards: std::array::from_fn(|_| Mutex::new(LruCache::new(nz))),
}
}
pub fn record_and_reassemble(&self, fragment: SecretFragment) -> Vec<String> {
let shard_idx = shard_index(&fragment.prefix);
let mut lock = self.shards[shard_idx].lock();
let prefix = fragment.prefix.clone();
let cluster = lock.get_or_insert_mut(prefix, Vec::new);
if !cluster.iter().any(|f| {
f.path == fragment.path && f.line == fragment.line && f.value == fragment.value
}) {
cluster.push(fragment);
}
if cluster.len() >= 2 {
let parts: Vec<_> = cluster.iter().map(|f| f.value.clone()).collect();
vec![parts.join("")]
} else {
Vec::new()
}
}
}
fn shard_index(key: &str) -> usize {
key.bytes()
.fold(0usize, |h, b| h.wrapping_mul(31).wrapping_add(b as usize))
% SHARD_COUNT
}
use std::sync::OnceLock;
pub static GLOBAL_FRAGMENT_CACHE: OnceLock<FragmentCache> = OnceLock::new();
pub fn get_fragment_cache() -> &'static FragmentCache {
GLOBAL_FRAGMENT_CACHE.get_or_init(|| FragmentCache::new(1000))
}