1use crate::manifest::FileManifest;
2use crate::metadata::{self, MetadataFormat};
3use anyhow::Result;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::fs;
7use std::path::Path;
8
9#[derive(Serialize, Deserialize, Default, Debug)]
10pub struct Index {
11 pub files: HashMap<String, FileManifest>,
12}
13
14impl Index {
15 pub fn load(path: &Path, _fmt: &MetadataFormat) -> Result<Self> {
16 if !path.exists() {
17 return Ok(Self::default());
18 }
19 let content = fs::read(path)?;
20 metadata::deserialize(&content)
21 }
22
23 pub fn save(&self, path: &Path, fmt: &MetadataFormat) -> Result<()> {
24 let content = metadata::serialize(self, fmt);
25 fs::write(path, content)?;
26 Ok(())
27 }
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33 use tempfile::tempdir;
34
35 fn make_manifest(name: &str) -> FileManifest {
36 FileManifest {
37 name: name.to_string(),
38 size: 100,
39 chunks: vec!["hash1".into()],
40 content_type: None,
41 compression: "none".into(),
42 merkle_root: None,
43 created_by: None,
44 created_at: None,
45 signature: None,
46 }
47 }
48
49 #[test]
50 fn test_index_load_nonexistent() {
51 let dir = tempdir().unwrap();
52 let idx = Index::load(&dir.path().join("index"), &MetadataFormat::Json).unwrap();
53 assert!(idx.files.is_empty());
54 }
55
56 #[test]
57 fn test_index_save_load_json_roundtrip() {
58 let dir = tempdir().unwrap();
59 let path = dir.path().join("index");
60
61 let mut idx = Index::default();
62 idx.files.insert("a.txt".into(), make_manifest("a.txt"));
63 idx.files.insert("b.txt".into(), make_manifest("b.txt"));
64 idx.save(&path, &MetadataFormat::Json).unwrap();
65
66 let loaded = Index::load(&path, &MetadataFormat::Json).unwrap();
67 assert_eq!(loaded.files.len(), 2);
68 assert!(loaded.files.contains_key("a.txt"));
69 assert!(loaded.files.contains_key("b.txt"));
70 }
71
72 #[test]
73 fn test_index_save_load_cbor_roundtrip() {
74 let dir = tempdir().unwrap();
75 let path = dir.path().join("index");
76
77 let mut idx = Index::default();
78 idx.files.insert("c.txt".into(), make_manifest("c.txt"));
79 idx.save(&path, &MetadataFormat::Cbor).unwrap();
80
81 let loaded = Index::load(&path, &MetadataFormat::Cbor).unwrap();
82 assert_eq!(loaded.files.len(), 1);
83 assert!(loaded.files.contains_key("c.txt"));
84
85 let loaded_auto = Index::load(&path, &MetadataFormat::Json).unwrap();
87 assert_eq!(loaded_auto.files.len(), 1);
88 }
89
90 #[test]
91 fn test_index_overwrite() {
92 let dir = tempdir().unwrap();
93 let path = dir.path().join("index");
94
95 let mut idx = Index::default();
96 idx.files.insert("x.txt".into(), make_manifest("x.txt"));
97 idx.save(&path, &MetadataFormat::Json).unwrap();
98
99 let mut idx2 = Index::default();
100 idx2.files.insert("y.txt".into(), make_manifest("y.txt"));
101 idx2.save(&path, &MetadataFormat::Json).unwrap();
102
103 let loaded = Index::load(&path, &MetadataFormat::Json).unwrap();
104 assert_eq!(loaded.files.len(), 1);
105 assert!(loaded.files.contains_key("y.txt"));
106 }
107}