1use std::{
4 fmt::{Debug, Display, Error as FmtError, Formatter},
5 num::ParseIntError,
6 str::FromStr,
7};
8
9include!(concat!(env!("OUT_DIR"), "/version.rs"));
11
12#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
14pub struct Version {
15 pub major: u32,
17 pub minor: u32,
19 pub patch: u32,
21}
22
23impl Version {
24 pub const V1_0: Version = Version::major_minor(1, 0);
25 pub const V1_1: Version = Version::major_minor(1, 1);
26 pub const V1_2: Version = Version::major_minor(1, 2);
27 pub const V1_3: Version = Version::major_minor(1, 3);
28 pub const V1_4: Version = Version::major_minor(1, 4);
29 pub const V1_5: Version = Version::major_minor(1, 5);
30 pub const V1_6: Version = Version::major_minor(1, 6);
31
32 #[inline]
34 pub const fn major_minor(major: u32, minor: u32) -> Version {
35 Version {
36 major,
37 minor,
38 patch: 0,
39 }
40 }
41}
42
43impl Default for Version {
44 #[inline]
45 fn default() -> Self {
46 Self::V1_0
47 }
48}
49
50impl From<u32> for Version {
51 #[inline]
52 fn from(val: u32) -> Self {
53 Version {
54 major: ash::vk::api_version_major(val),
55 minor: ash::vk::api_version_minor(val),
56 patch: ash::vk::api_version_patch(val),
57 }
58 }
59}
60
61impl TryFrom<Version> for u32 {
62 type Error = ();
63
64 #[inline]
65 fn try_from(val: Version) -> Result<Self, Self::Error> {
66 if val.major <= 0x3ff && val.minor <= 0x3ff && val.patch <= 0xfff {
67 Ok(ash::vk::make_api_version(
68 0, val.major, val.minor, val.patch,
69 ))
70 } else {
71 Err(())
72 }
73 }
74}
75
76impl FromStr for Version {
77 type Err = ParseIntError;
78
79 #[inline]
80 fn from_str(s: &str) -> Result<Self, Self::Err> {
81 let mut iter = s.splitn(3, '.');
82 let major: u32 = iter.next().unwrap().parse()?;
83 let minor: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;
84 let patch: u32 = iter.next().map_or(Ok(0), |n| n.parse())?;
85
86 Ok(Version {
87 major,
88 minor,
89 patch,
90 })
91 }
92}
93
94impl Debug for Version {
95 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
96 write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
97 }
98}
99
100impl Display for Version {
101 #[inline]
102 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
103 Debug::fmt(self, f)
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::Version;
110
111 #[test]
112 fn into_vk_version() {
113 let version = Version {
114 major: 1,
115 minor: 0,
116 patch: 0,
117 };
118 assert_eq!(u32::try_from(version).unwrap(), 0x400000);
119 }
120
121 #[test]
122 fn greater_major() {
123 let v1 = Version {
124 major: 1,
125 minor: 0,
126 patch: 0,
127 };
128 let v2 = Version {
129 major: 2,
130 minor: 0,
131 patch: 0,
132 };
133 assert!(v2 > v1);
134 }
135
136 #[test]
137 fn greater_minor() {
138 let v1 = Version {
139 major: 1,
140 minor: 1,
141 patch: 0,
142 };
143 let v2 = Version {
144 major: 1,
145 minor: 3,
146 patch: 0,
147 };
148 assert!(v2 > v1);
149 }
150
151 #[test]
152 fn greater_patch() {
153 let v1 = Version {
154 major: 1,
155 minor: 0,
156 patch: 4,
157 };
158 let v2 = Version {
159 major: 1,
160 minor: 0,
161 patch: 5,
162 };
163 assert!(v2 > v1);
164 }
165
166 #[test]
167 fn version_parse() {
168 assert!(matches!(
169 "1.1.1".parse::<Version>(),
170 Ok(Version {
171 major: 1,
172 minor: 1,
173 patch: 1,
174 })
175 ));
176 assert!(matches!(
177 "1.1".parse::<Version>(),
178 Ok(Version {
179 major: 1,
180 minor: 1,
181 patch: 0,
182 })
183 ));
184 assert!(matches!(
185 "1".parse::<Version>(),
186 Ok(Version {
187 major: 1,
188 minor: 0,
189 patch: 0,
190 })
191 ));
192
193 assert!("".parse::<Version>().is_err());
194 assert!("1.1.1.1".parse::<Version>().is_err());
195 assert!("foobar".parse::<Version>().is_err());
196 assert!("1.bar".parse::<Version>().is_err());
197 }
198}