use anyhow::{Context, Result};
use super::sectioned::SectionedStorage;
use super::symbol_metadata::SymbolMetadataStore;
#[cfg(test)]
use super::symbol_metadata::SymbolMetadata;
pub struct SymbolMetadataSectionAdapter;
impl SymbolMetadataSectionAdapter {
pub const SECTION_NAME: &'static str = "SYMBOL_METADATA";
pub fn load(storage: &mut SectionedStorage) -> Result<SymbolMetadataStore> {
let bytes = storage
.read_section(Self::SECTION_NAME)
.context("SYMBOL_METADATA section not found or empty")?;
SymbolMetadataStore::from_bytes(&bytes).context("Failed to parse SYMBOL_METADATA section")
}
pub fn save(storage: &mut SectionedStorage, store: &SymbolMetadataStore) -> Result<()> {
let bytes = store.to_bytes();
let required = bytes.len() as u64;
if storage.get_section(Self::SECTION_NAME).is_some() {
let result = storage.write_section(Self::SECTION_NAME, &bytes);
if let Err(e) = result {
if e.to_string().contains("overflow") || e.to_string().contains("capacity") {
let current = storage.get_section(Self::SECTION_NAME).unwrap();
let new_capacity = (current.capacity * 2).max(required * 2);
storage
.resize_section(Self::SECTION_NAME, new_capacity)
.context("Failed to resize SYMBOL_METADATA section")?;
storage.write_section(Self::SECTION_NAME, &bytes)?;
} else {
return Err(e);
}
}
} else {
let section_capacity = (1024 * 1024).max(required * 2);
storage.create_section(Self::SECTION_NAME, section_capacity, 0)?;
storage.write_section(Self::SECTION_NAME, &bytes)?;
}
storage.flush()?;
Ok(())
}
pub fn init(storage: &mut SectionedStorage) -> Result<()> {
let default_capacity = 1024 * 1024; storage.create_section(Self::SECTION_NAME, default_capacity, 0)?;
let empty = SymbolMetadataStore::new();
let bytes = empty.to_bytes();
storage.write_section(Self::SECTION_NAME, &bytes)?;
storage.flush()?;
Ok(())
}
pub fn exists(storage: &SectionedStorage) -> bool {
storage.get_section(Self::SECTION_NAME).is_some()
}
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn test_symbol_metadata_section_roundtrip() {
let temp_dir = tempdir().unwrap();
let db_path = temp_dir.path().join("test_symbols.geo");
let mut storage = SectionedStorage::create(&db_path).unwrap();
SymbolMetadataSectionAdapter::init(&mut storage).unwrap();
let mut store = SymbolMetadataStore::new();
store.add(SymbolMetadata {
symbol_id: 1,
name: "my_func".to_string(),
fqn: "crate::my_func".to_string(),
file_path: "/src/lib.rs".to_string(),
kind: 1,
language: 1,
byte_start: 100,
byte_end: 200,
start_line: 10,
start_col: 0,
end_line: 20,
end_col: 1,
});
SymbolMetadataSectionAdapter::save(&mut storage, &store).unwrap();
drop(storage);
let mut storage = SectionedStorage::open(&db_path).unwrap();
let restored = SymbolMetadataSectionAdapter::load(&mut storage).unwrap();
assert_eq!(restored.symbol_count(), 1);
let meta = restored.get(1).unwrap();
assert_eq!(meta.name, "my_func");
assert_eq!(meta.fqn, "crate::my_func");
assert_eq!(meta.file_path, "/src/lib.rs");
}
#[test]
fn test_symbol_metadata_section_exists() {
let temp_dir = tempdir().unwrap();
let db_path = temp_dir.path().join("test_exists.geo");
let mut storage = SectionedStorage::create(&db_path).unwrap();
assert!(!SymbolMetadataSectionAdapter::exists(&storage));
SymbolMetadataSectionAdapter::init(&mut storage).unwrap();
assert!(SymbolMetadataSectionAdapter::exists(&storage));
}
}