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
use anyhow::{anyhow, Result};
use bincode::{Decode, Encode};
use serde::{Deserialize, Serialize};

use rucksack_lib::util;

use crate::records;

#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Encode, Decode)]
pub struct VersionedDB {
    bytes: Vec<u8>,
    version: String,
}

pub fn deserialise(bytes: Vec<u8>) -> Result<VersionedDB> {
    log::debug!("Creating versioned DB from previously serialised versioned DB ...");
    let versioned: VersionedDB;
    match bincode::decode_from_slice(bytes.as_ref(), util::bincode_cfg()) {
        Ok((result, _len)) => {
            versioned = result;
            log::trace!("deserialised versioned DB bytes: {:?}", versioned);
            Ok(versioned)
        }
        Err(e) => {
            let msg = format!("couldn't deserialise versioned database file: {e:?}");
            log::error!("{}", msg);
            Err(anyhow!(msg))
        }
    }
}

pub fn from_bytes(bytes: Vec<u8>) -> VersionedDB {
    log::debug!("Initialising versioned DB with encoded hashmap ...");
    new(bytes, records::version().to_string())
}

pub fn new(bytes: Vec<u8>, version: String) -> VersionedDB {
    VersionedDB { bytes, version }
}

impl VersionedDB {
    pub fn bytes(&self) -> Vec<u8> {
        self.bytes.clone()
    }

    pub fn hash(&self) -> u32 {
        crc32fast::hash(self.bytes.as_ref())
    }

    pub fn serialise(&self) -> Result<Vec<u8>> {
        log::debug!("Serialising versioned DB ...");
        match bincode::encode_to_vec(self, util::bincode_cfg()) {
            Ok(bytes) => Ok(bytes),
            Err(e) => {
                let msg = format!("couldn't serialise versioned database ({e})");
                log::error!("{}", msg);
                Err(anyhow!("{}", msg))
            }
        }
    }

    pub fn version(&self) -> versions::SemVer {
        versions::SemVer::new(self.version.as_str()).unwrap()
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn db_bytes() {
        let vsn_db = super::new(vec![2, 4, 16], "1.2.3".to_string());
        assert!(vsn_db.version() > versions::SemVer::new("0.3.0").unwrap());
        assert_eq!(vsn_db.hash(), 2233391132);
        assert_eq!(vsn_db.version(), versions::SemVer::new("1.2.3").unwrap());
        assert!(vsn_db.version() < versions::SemVer::new("2.3.0").unwrap());
        let encoded = vsn_db.serialise().unwrap();
        let expected = vec![
            3, 0, 0, 0, 0, 0, 0, 0, 2, 4, 16, 5, 0, 0, 0, 0, 0, 0, 0, 49, 46, 50, 46, 51,
        ];
        assert_eq!(encoded, expected);
    }
}