mmap_storage/serializer/
json.rs

1//! Json serialization module
2use serde::{Serialize, Deserialize};
3
4use std::io;
5
6use crate::file as inner;
7
8use super::Serialization;
9
10#[derive(Default)]
11/// Json Serializer.
12///
13/// Uses pretty format for serialization.
14///
15/// Note that empty data writes `{}` into file
16pub struct Json;
17
18impl<'de, T: Serialize + Deserialize<'de>> Serialization<'de, T> for Json {
19    fn serialize(data: &T) -> Result<Vec<u8>, io::Error> {
20        serde_json::to_vec_pretty(data).map_err(|error| io::Error::new(io::ErrorKind::Other, error))
21    }
22    fn serialize_into(data: &T, writer: &mut inner::Storage) -> Result<(), io::Error> {
23        writer.resize(0)?;
24        let buffer = io::BufWriter::new(writer);
25        serde_json::to_writer_pretty(buffer, data).map_err(|error| io::Error::new(io::ErrorKind::Other, error))
26    }
27    fn deserialize(bytes: &'de [u8]) -> Result<T, io::Error> {
28        serde_json::from_slice(bytes).map_err(|error| io::Error::new(io::ErrorKind::Other, error))
29    }
30}
31
32#[cfg(test)]
33mod tests {
34    use super::Json;
35    use super::super::{FileView};
36
37    use std::fs;
38    use std::collections::HashMap;
39
40    #[test]
41    fn should_handle_json_file_view() {
42        const STORAGE_PATH: &'static str = "test_file_view.json";
43        let _ = fs::remove_file(STORAGE_PATH);
44
45        {
46            //Try to just open non-existing data
47            let storage = FileView::<HashMap<String, String>, Json>::open(STORAGE_PATH).expect("To create file");
48            let result = storage.load();
49            //We cannot load from dummy bytes
50            assert!(result.is_err());
51        }
52
53        let _ = fs::remove_file(STORAGE_PATH);
54
55        {
56            //Try to open non-existing file so that it could use provided default
57            let mut default_map = HashMap::new();
58            default_map.insert(1.to_string(), "".to_string());
59            let storage = FileView::<HashMap<String, String>, Json>::open_or(STORAGE_PATH, &default_map).expect("Open with provided default data");;
60            let data = storage.load().expect("To load data from empty file");
61            assert_eq!(data.len(), default_map.len());
62            assert_eq!(data.get(&1.to_string()).expect("To find key 1"), "");
63        }
64
65        let _ = fs::remove_file(STORAGE_PATH);
66
67        let new_len = {
68            //Try to open non-existing file so that it would write {}
69            let mut storage = FileView::<HashMap<String, String>, Json>::open_or_default(STORAGE_PATH).expect("To open empty file");
70            let mut data = storage.load().expect("To load data from empty file");
71            assert_eq!(data.len(), 0);
72
73            data.insert(1.to_string(), "".to_string());
74            data.insert(2.to_string(), "two".to_string());
75
76            data.insert(3.to_string(), "".to_string());
77            data.insert(4.to_string(), "".to_string());
78
79            data.insert(5.to_string(), "".to_string());
80            data.insert(4.to_string(), "four".to_string());
81
82            storage.save_sync(&data).expect("To save modified data");
83
84            data.len()
85        };
86
87        let expected = [
88            (1, ""),
89            (2, "two"),
90            (3, ""),
91            (4, "four"),
92            (5, "")
93        ];
94
95        {
96            //Json should be able to load with usize instead of String
97            let mut default_data = HashMap::new();
98            default_data.insert(1, "one".to_string());
99            let storage = FileView::<HashMap<usize, String>, Json>::open_or(STORAGE_PATH, &default_data).expect("To load json");
100            let data = storage.load().expect("To load json data");
101
102            assert_eq!(data.len(), new_len);
103            for (expected_key, expected_val) in expected.iter() {
104                let expected_val: &str = expected_val;
105                let value: &str = data.get(&expected_key).expect("To find key");
106                assert_eq!(value, expected_val);
107            }
108        }
109
110        {
111            // Load valid data
112            let mut storage = FileView::<HashMap<String, String>, Json>::open(STORAGE_PATH).expect("To open file");
113            let data = storage.load().expect("To load data");
114
115            // We should read saved data
116            assert_eq!(data.len(), new_len);
117            for (expected_key, expected_val) in expected.iter() {
118                let expected_val: &str = expected_val;
119                let value: &str = data.get(&expected_key.to_string()).expect("To find key");
120                assert_eq!(value, expected_val);
121            }
122
123            storage.save_sync(&data).expect("To save data");
124            //Check owned load
125            let _data = storage.load_owned().expect("To load owned data");
126        }
127
128        {
129            // Load valid data
130            let mut storage = FileView::<HashMap<&str, &str>, Json>::open(STORAGE_PATH).expect("To open file");
131
132            storage.modify(|data| {
133                data
134            }).expect("To modify");
135
136            let data = storage.load().expect("To load data");
137            // We should read saved data
138            assert_eq!(data.len(), new_len);
139            for (expected_key, expected_val) in expected.iter() {
140                let expected_val: &str = expected_val;
141                let value: &str = data.get(&expected_key.to_string().as_ref()).expect("To find key");
142                assert_eq!(value, expected_val);
143            }
144        }
145
146        let _ = fs::remove_file(STORAGE_PATH);
147    }
148
149}