Skip to main content

semantic_memory/
storage.rs

1//! Storage path management for the memory directory convention.
2//!
3//! A memory store lives in a directory containing:
4//! - `memory.db` — SQLite database (content, metadata, FTS5, f32 embeddings)
5//! - `memory.hnsw.graph` — HNSW graph topology (when `hnsw` feature enabled)
6//! - `memory.hnsw.data` — HNSW vector data (when `hnsw` feature enabled)
7
8use std::path::{Path, PathBuf};
9
10/// Resolved file paths for all storage files within a memory directory.
11#[derive(Debug, Clone)]
12pub struct StoragePaths {
13    /// The base directory containing all storage files.
14    pub base_dir: PathBuf,
15    /// Path to the SQLite database file.
16    pub sqlite_path: PathBuf,
17    /// Directory for HNSW files (same as base_dir, hnsw_rs writes basename.hnsw.graph + basename.hnsw.data).
18    pub hnsw_dir: PathBuf,
19    /// Base name for HNSW files (e.g., "memory" → memory.hnsw.graph + memory.hnsw.data).
20    pub hnsw_basename: String,
21}
22
23impl StoragePaths {
24    /// Create storage paths from a base directory.
25    ///
26    /// Given `/path/to/memory`, resolves:
27    /// - `/path/to/memory/memory.db`
28    /// - `/path/to/memory/memory.hnsw.graph`
29    /// - `/path/to/memory/memory.hnsw.data`
30    pub fn new(base_dir: impl AsRef<Path>) -> Self {
31        let base_dir = base_dir.as_ref().to_path_buf();
32        Self {
33            sqlite_path: base_dir.join("memory.db"),
34            hnsw_dir: base_dir.clone(),
35            hnsw_basename: "memory".to_string(),
36            base_dir,
37        }
38    }
39
40    /// Path to the HNSW graph file.
41    pub fn hnsw_graph_path(&self) -> PathBuf {
42        self.base_dir
43            .join(format!("{}.hnsw.graph", self.hnsw_basename))
44    }
45
46    /// Path to the HNSW data file.
47    pub fn hnsw_data_path(&self) -> PathBuf {
48        self.base_dir
49            .join(format!("{}.hnsw.data", self.hnsw_basename))
50    }
51
52    /// Whether both HNSW sidecar files exist on disk.
53    pub fn hnsw_files_exist(&self) -> bool {
54        self.hnsw_graph_path().exists() && self.hnsw_data_path().exists()
55    }
56}