1use crate as mvutils;
2use mvutils_proc_macro::Savable;
3use std::cmp::Ordering;
4use std::fmt::{Debug, Display, Formatter};
5use std::hash::{Hash, Hasher};
6use std::str::FromStr;
7
8#[derive(Eq, PartialEq, Copy, Clone, Savable)]
9pub struct Version {
10 variant: u16,
11 major: u16,
12 minor: u16,
13 patch: u16,
14}
15
16impl Version {
17 pub fn new(variant: u16, major: u16, minor: u16, patch: u16) -> Self {
18 Version {
19 variant,
20 major,
21 minor,
22 patch,
23 }
24 }
25
26 pub fn parse_vulkan(version: u32) -> Self {
27 Version {
28 variant: (version >> 29) as u16,
29 major: ((version >> 22) & 0x7f) as u16,
30 minor: ((version >> 12) & 0x3FF) as u16,
31 patch: (version & 0xFFF) as u16,
32 }
33 }
34
35 pub fn parse(version: &str) -> Option<Self> {
36 if version.is_empty() {
37 return None;
38 }
39 let digits = if version.starts_with("#version") {
40 version
41 .replace("#version", "")
42 .replace(' ', "")
43 .chars()
44 .map(|c| c as u16 - 48)
45 .collect::<Vec<_>>()
46 } else {
47 let results = version
48 .replace(['v', ' '], "")
49 .split('.')
50 .map(u16::from_str)
51 .collect::<Vec<_>>();
52 if results.iter().any(Result::is_err) {
53 return None;
54 }
55 results.into_iter().map(|e| e.unwrap()).collect::<Vec<_>>()
56 };
57
58 if digits.len() == 1 {
59 Some(Version {
60 variant: 0,
61 major: digits[0],
62 minor: 0,
63 patch: 0,
64 })
65 } else if digits.len() == 2 {
66 Some(Version {
67 variant: 0,
68 major: digits[0],
69 minor: digits[1],
70 patch: 0,
71 })
72 } else if digits.len() == 3 {
73 Some(Version {
74 variant: 0,
75 major: digits[0],
76 minor: digits[1],
77 patch: digits[2],
78 })
79 } else {
80 None
81 }
82 }
83
84 pub fn to_glsl_string(&self) -> String {
85 format!("#version {}{}{}", self.major, self.minor, self.patch)
86 }
87
88 pub fn as_vulkan_version(&self) -> u32 {
89 ((self.variant as u32) << 29 | (self.major as u32) << 22)
90 | ((self.minor as u32) << 12)
91 | (self.patch as u32)
92 }
93
94 pub fn variant(&self) -> u16 {
95 self.variant
96 }
97
98 pub fn major(&self) -> u16 {
99 self.major
100 }
101
102 pub fn minor(&self) -> u16 {
103 self.minor
104 }
105
106 pub fn patch(&self) -> u16 {
107 self.patch
108 }
109
110 pub fn set_variant(&mut self, variant: u16) {
111 self.variant = variant;
112 }
113
114 pub fn set_major(&mut self, major: u16) {
115 self.major = major;
116 }
117
118 pub fn set_minor(&mut self, minor: u16) {
119 self.minor = minor;
120 }
121
122 pub fn set_patch(&mut self, patch: u16) {
123 self.patch = patch;
124 }
125}
126
127impl Default for Version {
128 fn default() -> Self {
129 Version {
130 variant: 0,
131 major: 1,
132 minor: 0,
133 patch: 0,
134 }
135 }
136}
137
138impl Display for Version {
139 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
140 f.write_str(format!("{}.{}.{}", self.major, self.minor, self.patch).as_str())
141 }
142}
143
144impl Debug for Version {
145 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
146 f.write_str(
147 format!(
148 "Version {{ major: {}, minor: {}, patch: {} }}",
149 self.major, self.minor, self.patch
150 )
151 .as_str(),
152 )
153 }
154}
155
156impl Ord for Version {
157 fn cmp(&self, other: &Self) -> Ordering {
158 self.major
159 .cmp(&other.major)
160 .then(self.minor.cmp(&other.minor))
161 .then(self.patch.cmp(&other.patch))
162 }
163}
164
165impl PartialOrd for Version {
166 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
167 Some(self.cmp(other))
168 }
169}
170
171impl Hash for Version {
172 fn hash<H: Hasher>(&self, state: &mut H) {
173 state.write_u16(self.major);
174 state.write_u16(self.minor);
175 state.write_u16(self.patch);
176 }
177}
178
179impl FromStr for Version {
180 type Err = ();
181
182 fn from_str(s: &str) -> Result<Self, Self::Err> {
183 Version::parse(s).ok_or(())
184 }
185}
186
187impl TryFrom<String> for Version {
188 type Error = ();
189
190 fn try_from(value: String) -> Result<Self, Self::Error> {
191 Version::parse(&value).ok_or(())
192 }
193}
194
195impl From<u32> for Version {
196 fn from(value: u32) -> Self {
197 Version::parse_vulkan(value)
198 }
199}
200
201impl From<Version> for u32 {
202 fn from(value: Version) -> Self {
203 value.as_vulkan_version()
204 }
205}