saito_core/core/process/
version.rs

1use crate::core::util::serialize::Serialize;
2use log::warn;
3use std::cmp::Ordering;
4use std::io::{Error, ErrorKind};
5
6const VERSION_SIZE: u8 = 4;
7
8pub fn read_pkg_version() -> Version {
9    let v = env!("CARGO_PKG_VERSION");
10
11    let tokens: Vec<&str> = v.split('.').collect();
12    if tokens.len() != 3 {
13        return Default::default();
14    }
15
16    let major = tokens[0].parse();
17    let minor = tokens[1].parse();
18    let patch = tokens[2].parse();
19
20    if major.is_err() || minor.is_err() || patch.is_err() {
21        return Default::default();
22    }
23
24    Version::new(major.unwrap(), minor.unwrap(), patch.unwrap())
25}
26
27#[derive(Debug, Default, Clone, Copy)]
28pub struct Version {
29    pub major: u8,
30    pub minor: u8,
31    pub patch: u16,
32}
33
34impl Version {
35    pub fn is_set(&self) -> bool {
36        !(self.major == 0 && self.minor == 0 && self.patch == 0)
37    }
38
39    pub fn new(major: u8, minor: u8, patch: u16) -> Self {
40        Version {
41            major,
42            minor,
43            patch,
44        }
45    }
46
47    /// Same minor version nodes should be able to work without any issues
48    ///
49    /// # Arguments
50    ///
51    /// * `version`:
52    ///
53    /// returns: bool
54    ///
55    /// # Examples
56    ///
57    /// ```
58    ///
59    /// ```
60    pub fn is_same_minor_version(&self, version: &Version) -> bool {
61        self.is_set() && self.major == version.major && self.minor == version.minor
62    }
63}
64
65impl Serialize<Self> for Version {
66    fn serialize(&self) -> Vec<u8> {
67        let mut v = [self.major, self.minor].to_vec();
68        v.append(&mut self.patch.to_be_bytes().to_vec());
69        v
70    }
71
72    fn deserialize(buffer: &Vec<u8>) -> Result<Self, Error> {
73        if buffer.len() < VERSION_SIZE as usize {
74            warn!(
75                "buffer size : {:?} cannot be parsed as a version",
76                buffer.len()
77            );
78            return Err(Error::from(ErrorKind::InvalidData));
79        }
80        let ver = Version {
81            major: *buffer.get(0).ok_or(Error::from(ErrorKind::InvalidInput))?,
82            minor: *buffer.get(1).ok_or(Error::from(ErrorKind::InvalidInput))?,
83            patch: u16::from_be_bytes([
84                *buffer.get(2).ok_or(Error::from(ErrorKind::InvalidInput))?,
85                *buffer.get(3).ok_or(Error::from(ErrorKind::InvalidInput))?,
86            ]),
87        };
88
89        Ok(ver)
90    }
91}
92
93impl Eq for Version {}
94
95impl PartialEq<Self> for Version {
96    fn eq(&self, other: &Self) -> bool {
97        self.major == other.major && self.minor == other.minor && self.patch == other.patch
98    }
99}
100
101impl PartialOrd<Self> for Version {
102    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
103        if self.major < other.major {
104            return Some(Ordering::Less);
105        } else if self.major > other.major {
106            return Some(Ordering::Greater);
107        }
108        if self.minor < other.minor {
109            return Some(Ordering::Less);
110        } else if self.minor > other.minor {
111            return Some(Ordering::Greater);
112        }
113
114        self.patch.partial_cmp(&other.patch)
115    }
116}
117
118impl Ord for Version {
119    fn cmp(&self, other: &Self) -> Ordering {
120        self.partial_cmp(other).unwrap()
121    }
122}
123
124#[cfg(test)]
125mod tests {
126    use crate::core::process::version::{Version, VERSION_SIZE};
127    use crate::core::util::serialize::Serialize;
128
129    #[test]
130    fn test_version_serialization() {
131        let version = Version {
132            major: 2,
133            minor: 45,
134            patch: 1243,
135        };
136        let buffer = version.serialize();
137        assert_eq!(buffer.len(), VERSION_SIZE as usize);
138        let version2 = Version::deserialize(&buffer)
139            .expect("can't deserialize given buffer to version object");
140
141        assert_eq!(version, version2);
142    }
143    #[test]
144    fn test_version_compare() {
145        assert!(
146            Version {
147                major: 10,
148                minor: 20,
149                patch: 30,
150            } < Version {
151                major: 10,
152                minor: 30,
153                patch: 20,
154            }
155        );
156        assert!(
157            Version {
158                major: 10,
159                minor: 20,
160                patch: 30,
161            } > Version {
162                major: 10,
163                minor: 10,
164                patch: 30,
165            }
166        );
167        assert!(
168            Version {
169                major: 10,
170                minor: 20,
171                patch: 30,
172            } < Version {
173                major: 10,
174                minor: 20,
175                patch: 40,
176            }
177        );
178
179        assert!(Version::new(0, 1, 7).is_same_minor_version(&Version::new(0, 1, 10)));
180        assert!(Version::new(0, 1, 7).is_same_minor_version(&Version::new(0, 1, 7)));
181        assert!(!Version::new(0, 1, 7).is_same_minor_version(&Version::new(0, 2, 7)));
182        assert!(!Version::new(0, 1, 7).is_same_minor_version(&Version::new(1, 1, 7)));
183        assert!(!Version::new(0, 1, 7).is_same_minor_version(&Version::new(1, 0, 7)));
184        assert!(!Version::new(0, 1, 7).is_same_minor_version(&Version::new(1, 0, 1)));
185        assert!(!Version::new(0, 0, 0).is_same_minor_version(&Version::new(1, 0, 1)));
186        assert!(!Version::new(0, 1, 7).is_same_minor_version(&Version::new(0, 0, 0)));
187        assert!(!Version::new(0, 0, 0).is_same_minor_version(&Version::new(0, 0, 0)));
188    }
189}