Skip to main content

keynesis_network/
version.rs

1use std::{
2    convert::TryFrom,
3    fmt::{self, Formatter},
4    num::ParseIntError,
5    str::FromStr,
6};
7
8/// protocol version number
9///
10/// technically this is limited to 8 bytes. However it is easy to imagine
11/// than more than 256 version numbers are a bit overkill.
12///
13///
14/// Versions will be listed here overtime. However when performing the
15/// handshake, this function will use [`Version::CURRENT`] and will check
16/// how the remote's version match the [`Version::MIN`] and [`Version::MAX`].
17/// See [`is_supported`].
18///
19/// [`is_supported`]: Version::is_supported
20#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
21pub struct Version(u8);
22
23impl Version {
24    /// the encoded size of the [`Version`].
25    ///
26    /// ```
27    /// # use keynesis_network::Version;
28    /// assert_eq!(Version::SIZE, 1)
29    /// ```
30    pub const SIZE: usize = std::mem::size_of::<u8>();
31
32    /// version 1:
33    ///
34    /// Support syncing passports between the nodes
35    pub const V1: Self = Self(0x01);
36
37    /// get the minimal supported version supported by this implementation
38    pub const MIN: Self = Self::V1;
39
40    /// get the current version implemented by this implementation
41    pub const CURRENT: Self = Self::V1;
42
43    /// get the maximal supported version supported by this implementation
44    pub const MAX: Self = Self::CURRENT;
45
46    /// returns if the version is currently supported or not
47    ///
48    /// This is similar as to testing the given version against
49    /// the increasing order:
50    ///
51    /// ```
52    /// # use keynesis_network::Version;
53    /// assert!(
54    ///   Version::CURRENT.is_supported() ==
55    ///   (Version::CURRENT >= Version::MIN && Version::CURRENT <= Version::MAX)
56    /// );
57    /// ```
58    #[inline]
59    pub fn is_supported(self) -> bool {
60        Self::MIN <= self && self <= Self::MAX
61    }
62
63    #[inline]
64    pub(crate) const fn from_u8(version: u8) -> Self {
65        Self(version)
66    }
67
68    #[inline]
69    pub(crate) const fn to_u8(self) -> u8 {
70        self.0
71    }
72}
73
74impl Default for Version {
75    fn default() -> Self {
76        Self::CURRENT
77    }
78}
79
80impl fmt::Display for Version {
81    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
82        self.0.fmt(f)
83    }
84}
85
86impl From<Version> for String {
87    fn from(version: Version) -> Self {
88        version.to_string()
89    }
90}
91
92impl FromStr for Version {
93    type Err = ParseIntError;
94    fn from_str(s: &str) -> Result<Self, Self::Err> {
95        u8::from_str(s).map(Self)
96    }
97}
98
99impl<'a> TryFrom<&'a str> for Version {
100    type Error = ParseIntError;
101    fn try_from(value: &'a str) -> Result<Self, Self::Error> {
102        value.parse()
103    }
104}
105
106impl TryFrom<String> for Version {
107    type Error = ParseIntError;
108    fn try_from(value: String) -> Result<Self, Self::Error> {
109        value.parse()
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    /// simple test to check the current version is marked _supported_
118    #[test]
119    fn current_version_is_supported() {
120        assert!(Version::CURRENT.is_supported())
121    }
122
123    #[test]
124    fn parse_current_version() {
125        let current = Version::CURRENT.0.to_string();
126
127        let version = Version::try_from(current.as_str()).unwrap();
128
129        assert_eq!(version, Version::CURRENT)
130    }
131}