safecoin_version/
lib.rs

1#![cfg_attr(RUSTC_WITH_SPECIALIZATION, feature(min_specialization))]
2
3extern crate serde_derive;
4use {
5    serde_derive::{Deserialize, Serialize},
6    solana_sdk::sanitize::Sanitize,
7    std::{convert::TryInto, fmt},
8};
9#[macro_use]
10extern crate safecoin_frozen_abi_macro;
11
12// Older version structure used earlier 1.3.x releases
13#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, AbiExample)]
14pub struct LegacyVersion {
15    major: u16,
16    minor: u16,
17    patch: u16,
18    commit: Option<u32>, // first 4 bytes of the sha1 commit hash
19}
20
21impl Sanitize for LegacyVersion {}
22
23#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, AbiExample)]
24pub struct Version {
25    pub major: u16,
26    pub minor: u16,
27    pub patch: u16,
28    pub commit: Option<u32>, // first 4 bytes of the sha1 commit hash
29    pub feature_set: u32,    // first 4 bytes of the FeatureSet identifier
30}
31
32impl Version {
33    pub fn as_semver_version(&self) -> semver::Version {
34        semver::Version::new(self.major as u64, self.minor as u64, self.patch as u64)
35    }
36}
37
38impl From<LegacyVersion> for Version {
39    fn from(legacy_version: LegacyVersion) -> Self {
40        Self {
41            major: legacy_version.major,
42            minor: legacy_version.minor,
43            patch: legacy_version.patch,
44            commit: legacy_version.commit,
45            feature_set: 0,
46        }
47    }
48}
49
50fn compute_commit(sha1: Option<&'static str>) -> Option<u32> {
51    let sha1 = sha1?;
52    if sha1.len() < 8 {
53        None
54    } else {
55        u32::from_str_radix(&sha1[..8], 16).ok()
56    }
57}
58
59impl Default for Version {
60    fn default() -> Self {
61        let feature_set = u32::from_le_bytes(
62            solana_sdk::feature_set::ID.as_ref()[..4]
63                .try_into()
64                .unwrap(),
65        );
66        Self {
67            major: env!("CARGO_PKG_VERSION_MAJOR").parse().unwrap(),
68            minor: env!("CARGO_PKG_VERSION_MINOR").parse().unwrap(),
69            patch: env!("CARGO_PKG_VERSION_PATCH").parse().unwrap(),
70            commit: compute_commit(option_env!("CI_COMMIT")),
71            feature_set,
72        }
73    }
74}
75
76impl fmt::Display for Version {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(f, "{}.{}.{}", self.major, self.minor, self.patch,)
79    }
80}
81
82impl fmt::Debug for Version {
83    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84        write!(
85            f,
86            "{}.{}.{} (src:{}; feat:{})",
87            self.major,
88            self.minor,
89            self.patch,
90            match self.commit {
91                None => "devbuild".to_string(),
92                Some(commit) => format!("{:08x}", commit),
93            },
94            self.feature_set,
95        )
96    }
97}
98
99impl Sanitize for Version {}
100
101#[macro_export]
102macro_rules! semver {
103    () => {
104        &*format!("{}", $crate::Version::default())
105    };
106}
107
108#[macro_export]
109macro_rules! version {
110    () => {
111        &*format!("{:?}", $crate::Version::default())
112    };
113}
114
115#[cfg(test)]
116mod test {
117    use super::*;
118
119    #[test]
120    fn test_compute_commit() {
121        assert_eq!(compute_commit(None), None);
122        assert_eq!(compute_commit(Some("1234567890")), Some(0x1234_5678));
123        assert_eq!(compute_commit(Some("HEAD")), None);
124        assert_eq!(compute_commit(Some("garbagein")), None);
125    }
126}