Files
Kigi-CLI/crates/codegen/kigi-codebase-graph/src/manager/cache.rs
T
ZacharyZhang-NY a02b555e66 docs(comments): rewrite comments across all crates to the guidelines
Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).

No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.

Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).

Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
2026-07-23 16:55:39 -04:00

93 lines
2.9 KiB
Rust

//! Index caching for fast loading.
//!
//! The on-disk format is a custom binary layout tagged with the magic bytes
//! "SGIX". Caches written by the earlier bincode format are detected and
//! rejected rather than parsed, so the caller rebuilds from source.
use std::path::Path;
use crate::scope_graph::ScopeGraphIndex;
pub const CACHE_FILE_NAME: &str = ".goto_index.bin";
#[derive(Debug)]
pub enum CacheError {
IoError(std::io::Error),
SerializeError(String),
DeserializeError(String),
/// A bincode-era cache was found; the caller is expected to rebuild.
LegacyFormat,
}
impl std::fmt::Display for CacheError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CacheError::IoError(e) => write!(f, "IO error: {}", e),
CacheError::SerializeError(msg) => write!(f, "Serialization error: {}", msg),
CacheError::DeserializeError(msg) => write!(f, "Deserialization error: {}", msg),
CacheError::LegacyFormat => write!(f, "Legacy cache format detected"),
}
}
}
impl std::error::Error for CacheError {}
impl From<std::io::Error> for CacheError {
fn from(e: std::io::Error) -> Self {
CacheError::IoError(e)
}
}
pub type Result<T> = std::result::Result<T, CacheError>;
pub fn get_cache_path(root_path: &Path) -> std::path::PathBuf {
root_path.join(CACHE_FILE_NAME)
}
/// Returns `CacheError::LegacyFormat` for a bincode-format cache, signaling to
/// the caller that a rebuild is needed.
pub fn load_index(cache_path: &Path) -> Result<ScopeGraphIndex> {
if !cache_path.exists() {
return Err(CacheError::IoError(std::io::Error::new(
std::io::ErrorKind::NotFound,
"Cache file not found",
)));
}
match ScopeGraphIndex::load(cache_path) {
Ok(Some(index)) => Ok(index),
// `Ok(None)` is how the loader reports a legacy-format file.
Ok(None) => {
tracing::info!(
cache_path = %cache_path.display(),
"Legacy cache format detected, will rebuild"
);
Err(CacheError::LegacyFormat)
}
Err(e) => Err(CacheError::IoError(e)),
}
}
pub fn save_index(cache_path: &Path, index: &ScopeGraphIndex) -> Result<()> {
index.save(cache_path).map_err(CacheError::IoError)
}
/// Saves on a detached thread: the caller gets no join handle and no result,
/// so a failed write is only visible in the logs.
pub fn save_index_async(cache_path: std::path::PathBuf, index: ScopeGraphIndex) {
std::thread::spawn(move || {
if let Err(e) = save_index(&cache_path, &index) {
tracing::warn!("Failed to save index cache: {}", e);
}
});
}
pub fn cache_exists(cache_path: &Path) -> bool {
cache_path.exists()
}
/// Size of the cache file in bytes, or `None` if it cannot be stat'd.
pub fn cache_size(cache_path: &Path) -> Option<u64> {
std::fs::metadata(cache_path).ok().map(|m| m.len())
}