Skip to main content

sift_core/index/
meta.rs

1use std::path::{Path, PathBuf};
2
3use serde::{Deserialize, Serialize};
4
5use super::{CorpusKind, IndexError, IndexKind};
6
7const META_FILE: &str = "meta.json";
8const STORE_VERSION: u32 = 1;
9
10/// Persistent corpus configuration for an index store.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct StoreMeta {
13    pub version: u32,
14    pub root: PathBuf,
15    pub corpus_kind: CorpusKind,
16    pub follow_links: bool,
17    #[serde(default)]
18    pub indexes: Vec<IndexKind>,
19}
20
21impl StoreMeta {
22    /// Create a new `StoreMeta` with the current store version.
23    #[must_use]
24    pub const fn new(
25        root: PathBuf,
26        corpus_kind: CorpusKind,
27        follow_links: bool,
28        indexes: Vec<IndexKind>,
29    ) -> Self {
30        Self {
31            version: STORE_VERSION,
32            root,
33            corpus_kind,
34            follow_links,
35            indexes,
36        }
37    }
38
39    /// Path to `meta.json` within `dir`.
40    #[must_use]
41    pub fn path(dir: &Path) -> PathBuf {
42        dir.join(META_FILE)
43    }
44
45    /// Read from `dir/meta.json`.
46    ///
47    /// # Errors
48    ///
49    /// Returns an error if the file is missing or malformed.
50    pub fn read(dir: &Path) -> crate::Result<Self> {
51        let meta_path = Self::path(dir);
52        let raw = std::fs::read_to_string(&meta_path)?;
53        serde_json::from_str(&raw).map_err(|e| {
54            crate::Error::Index(IndexError::InvalidManifest {
55                path: meta_path,
56                source: e,
57            })
58        })
59    }
60
61    /// Write to `dir/meta.json`.
62    ///
63    /// # Errors
64    ///
65    /// Returns an error if serialization or writing fails.
66    pub fn write(&self, dir: &Path) -> crate::Result<()> {
67        let meta_path = Self::path(dir);
68        let json = serde_json::to_vec_pretty(self).map_err(|e| {
69            crate::Error::Index(IndexError::InvalidManifest {
70                path: meta_path.clone(),
71                source: e,
72            })
73        })?;
74        std::fs::write(&meta_path, json)?;
75        Ok(())
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82    use tempfile::TempDir;
83
84    #[test]
85    fn read_write_roundtrip() {
86        let tmp = TempDir::new().expect("create temp dir");
87
88        let meta = StoreMeta::new(
89            PathBuf::from("/some/root"),
90            CorpusKind::Directory,
91            true,
92            vec![IndexKind::Trigram],
93        );
94        meta.write(tmp.path()).expect("write meta");
95
96        let loaded = StoreMeta::read(tmp.path()).expect("read meta");
97        assert_eq!(loaded.version, meta.version);
98        assert_eq!(loaded.root, meta.root);
99        assert_eq!(loaded.corpus_kind, meta.corpus_kind);
100        assert_eq!(loaded.follow_links, meta.follow_links);
101        assert_eq!(loaded.indexes, meta.indexes);
102    }
103
104    #[test]
105    fn path_returns_meta_json() {
106        let p = StoreMeta::path(Path::new("/foo/bar"));
107        assert_eq!(p, PathBuf::from("/foo/bar/meta.json"));
108    }
109}