save_load_traits/
impl_for_hashmap.rs1crate::ix!();
3
4#[async_trait]
15impl<K, V> SaveToFile for HashMap<K, V>
16where
17 K: Serialize + DeserializeOwned + Eq + Hash + Send + Sync + 'static,
18 V: Serialize + DeserializeOwned + Send + Sync + 'static,
19{
20 type Error = SaveLoadError;
21
22 async fn save_to_file(
23 &self,
24 filename: impl AsRef<Path> + Send
25 ) -> Result<(), Self::Error> {
26 let json_data = serde_json::to_string_pretty(&self)
27 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
28
29 let mut file = File::create(filename).await?;
30 file.write_all(json_data.as_bytes()).await?;
31 Ok(())
32 }
33}
34
35#[async_trait]
36impl<K, V> LoadFromFile for HashMap<K, V>
37where
38 K: Serialize + DeserializeOwned + Eq + Hash + Send + Sync + 'static,
39 V: Serialize + DeserializeOwned + Send + Sync + 'static,
40{
41 type Error = SaveLoadError;
42
43 async fn load_from_file(filename: impl AsRef<Path> + Send)
44 -> Result<Self, Self::Error>
45 {
46 let mut file = File::open(filename).await?;
47 let mut buf = Vec::new();
48 file.read_to_end(&mut buf).await?;
49 let map: HashMap<K, V> =
50 serde_json::from_slice(&buf)
51 .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?;
52 Ok(map)
53 }
54}
55
56#[cfg(test)]
59mod test_hashmap_save_load {
60 use super::*;
61 use tokio::fs;
62 use traced_test::traced_test;
63 use std::collections::HashMap;
64 use std::path::PathBuf;
65
66 #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
67 struct FakeLeaf {
68 label: String,
69 id: u32,
70 }
71
72 #[traced_test]
73 async fn test_save_load_hashmap_basic() {
74 let mut my_map: HashMap<String, FakeLeaf> = HashMap::new();
75 my_map.insert(
76 "Alpha".to_string(),
77 FakeLeaf { label: "AlphaLeaf".into(), id: 1 }
78 );
79 my_map.insert(
80 "Beta".to_string(),
81 FakeLeaf { label: "BetaLeaf".into(), id: 2 }
82 );
83
84 let tmpfile = PathBuf::from("test_hashmap.json");
85 my_map.save_to_file(&tmpfile).await.expect("save failed");
86
87 let loaded_map = HashMap::<String, FakeLeaf>::load_from_file(&tmpfile)
88 .await
89 .expect("load failed");
90 assert_eq!(loaded_map, my_map, "Roundtrip mismatch for HashMap<String, FakeLeaf>");
91
92 fs::remove_file(&tmpfile).await.ok();
93 }
94
95 #[traced_test]
96 async fn test_load_non_existent_map() {
97 let path = PathBuf::from("unlikely_map_123.json");
98 let result = HashMap::<String, FakeLeaf>::load_from_file(&path).await;
99 assert!(result.is_err(), "Should error on non-existent file");
100 }
101
102 #[traced_test]
103 async fn test_load_malformed_map_json() {
104 let tmpfile = PathBuf::from("test_malformed.json");
105 fs::write(&tmpfile, b"NOT VALID JSON").await.expect("write fail");
106 let result = HashMap::<String, FakeLeaf>::load_from_file(&tmpfile).await;
107 assert!(result.is_err(), "Should error on malformed JSON");
108 fs::remove_file(&tmpfile).await.ok();
109 }
110}