1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! Toml serialization module
use serde::{Serialize, Deserialize};

use std::io;

use crate::file as inner;

use super::Serialization;

#[derive(Default)]
/// Toml Serializer.
pub struct Toml;

impl<'de, T: Serialize + Deserialize<'de>> Serialization<'de, T> for Toml {
    fn serialize(data: &T) -> Result<Vec<u8>, io::Error> {
        toml::to_vec(data).map_err(|error| io::Error::new(io::ErrorKind::Other, error))
    }

    fn serialize_into(data: &T, writer: &mut inner::Storage) -> Result<(), io::Error> {
        let data = toml::to_vec(data).map_err(|error| io::Error::new(io::ErrorKind::Other, error))?;
        match data.len() {
            0 => Err(super::empty_write_error()),
            _ => writer.put_data(&data)
        }
    }
    fn deserialize(bytes: &'de [u8]) -> Result<T, io::Error> {
        toml::from_slice(bytes).map_err(|error| io::Error::new(io::ErrorKind::Other, error))
    }
}

#[cfg(test)]
mod tests {
    use super::Toml;
    use super::super::{FileView};

    use std::fs;
    use std::collections::HashMap;

    #[test]
    fn should_handle_toml_file_view() {
        const STORAGE_PATH: &'static str = "test_file_view.toml";
        let _ = fs::remove_file(STORAGE_PATH);

        {
            //Try to open non-existing file so that it would write empty
            let result = FileView::<HashMap<String, String>, Toml>::open_or_default(STORAGE_PATH);
            assert!(result.is_err());
        }

        {
            //Try to open non-existing file so that it could use provided default
            let mut default_map = HashMap::new();
            default_map.insert(1.to_string(), "".to_string());
            let storage = FileView::<HashMap<String, String>, Toml>::open_or(STORAGE_PATH, &default_map).expect("Open with provided default data");;
            let data = storage.load().expect("To load data from empty file");
            assert_eq!(data.len(), default_map.len());
            assert_eq!(data.get(&1.to_string()).expect("To find key 1"), "");
        }

        let _ = fs::remove_file(STORAGE_PATH);

        let new_len = {
            //Just open
            let mut storage = FileView::<HashMap<String, String>, Toml>::open(STORAGE_PATH).expect("To create file");
            let mut data = storage.load().expect("To load data from empty file");
            assert_eq!(data.len(), 0);

            data.insert(1.to_string(), "".to_string());
            data.insert(2.to_string(), "two".to_string());

            data.insert(3.to_string(), "".to_string());
            data.insert(4.to_string(), "".to_string());

            data.insert(5.to_string(), "".to_string());
            data.insert(4.to_string(), "four".to_string());

            storage.save_sync(&data).expect("To save modified data");

            data.len()
        };

        {
            //Try to Serialize invalid data.
            let storage = FileView::<HashMap<usize, Option<String>>, Toml>::open(STORAGE_PATH).expect("To load");
            assert!(storage.load().is_err());
        }

        let expected = [
            (1, ""),
            (2, "two"),
            (3, ""),
            (4, "four"),
            (5, "")
        ];

        {
            // Load valid data
            let mut storage = FileView::<HashMap<String, String>, Toml>::open(STORAGE_PATH).expect("To open file");
            let data = storage.load().expect("To load data");

            // We should read saved data
            assert_eq!(data.len(), new_len);
            for (expected_key, expected_val) in expected.iter() {
                let expected_val: &str = expected_val;
                let value: &str = data.get(&expected_key.to_string()).expect("To find key");
                assert_eq!(value, expected_val);
            }

            storage.save_sync(&data).expect("To save data");
            //Check owned load
            let _data = storage.load_owned().expect("To load owned data");
        }

        {
            // Load valid data
            let mut storage = FileView::<HashMap<&str, &str>, Toml>::open(STORAGE_PATH).expect("To open file");

            storage.modify(|data| {
                data
            }).expect("To modify");

            let data = storage.load().expect("To load data");

            // We should read saved data
            assert_eq!(data.len(), new_len);
            for (expected_key, expected_val) in expected.iter() {
                let expected_val: &str = expected_val;
                let value: &str = data.get(&expected_key.to_string().as_ref()).expect("To find key");
                assert_eq!(value, expected_val);
            }
        }

        let _ = fs::remove_file(STORAGE_PATH);
    }

}