1use std::fmt;
4use std::cmp::Ordering;
5
6use regex::Regex;
7use serde;
8
9use std::marker::PhantomData;
10
11use versionpart::VersionPart;
12
13static VERSION_REGEX_STRING : &str = r"(?P<v>[1234567890\*]+)";
14
15#[derive(Hash)]
16pub struct Version {
17 parts : Vec<VersionPart>
18}
19
20impl PartialEq for Version {
21 fn eq(&self, other: &Version) -> bool {
22 let depth : usize = Version::get_shared_depth(&self, other);
27
28 for i in 0 .. depth {
29 if self.parts[i].is_wildcard() || other.parts[i].is_wildcard() { return true; }
32
33 if self.parts[i] != other.parts[i] { return false}
36 }
37
38 return true;
40 }
41}
42
43impl Eq for Version { }
44
45
46impl std::cmp::Ord for Version {
47 fn cmp(&self, other : &Version) -> Ordering {
48 let depth : usize = Version::get_shared_depth(&self, other);
49
50 for i in 0 .. depth {
53 if self.parts[i] != other.parts[i] {
56 return self.parts[i].cmp(&other.parts[i]);
59 }
60 }
61
62 Ordering::Equal
64 }
65}
66
67impl PartialOrd for Version {
68 fn partial_cmp(&self, other : &Version) -> Option<Ordering> {
69 Some(self.cmp(other))
70 }
71}
72
73impl fmt::Debug for Version {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 write!(f, "Version ({})",self.to_string())
77 }
78}
79
80impl fmt::Display for Version {
81 fn fmt(&self,f:&mut fmt::Formatter) -> fmt::Result {
82 write!(f, "Version ({})",self.to_string())
84 }
85}
86
87
88impl Version {
89
90 fn get_shared_depth(v1 : &Version, v2 : &Version) -> usize {
91 if v1.parts.len() <= v2.parts.len() {
95 return v1.parts.len()
96 } else {
97 return v2.parts.len();
98 }
99 }
100
101 pub fn new(numbers : &[u8]) -> Version {
103 let mut parts : Vec<VersionPart> = Vec::new();
106
107 for i in 0 .. numbers.len() {
108 parts.push(VersionPart::Number(numbers[i]));
109 }
110
111 Version { parts : parts }
112 }
113
114 pub fn new_wildcard() -> Version {
115 Version { parts : vec!(VersionPart::Wildcard("*".to_string())) }
118 }
119
120 pub fn from_str(version : &str) -> Option<Version> {
121 let re = Regex::new(VERSION_REGEX_STRING).unwrap();
124 let mut parts : Vec<VersionPart> = Vec::new();
125
126 for caps in re.captures_iter(version) {
127 match caps["v"].parse::<u8>() {
129 Err(_) => {
130 parts.push(VersionPart::Wildcard(caps["v"].to_string()));
132
133 return Some(Version{
135 parts : parts
136 });
137 },
138 Ok(number) => {
139 parts.push(VersionPart::Number(number));
141 }
142 }
143 }
144
145 if parts.len() > 0 {
146 Some(Version{
147 parts : parts
148 })
149 } else {
150 None
151 }
152 }
153
154 pub fn clone(&self) -> Version {
155 Version::from_str(&self.to_string()).unwrap()
157 }
158
159 pub fn from_latest_vec(list : &Vec<String>) -> Option<Version> {
160 let mut list_of_versions : Vec<Version> = Vec::new();
164 let mut selected = 0;
165
166 for l in list {
167 if let Some(ver) = Version::from_str(l) {
168 if !ver.has_wildcards() {
169 list_of_versions.push(ver);
170 }
171 }
172 }
173
174 if list_of_versions.len() <= 0 { return None; }
175
176 for cc in 1..list_of_versions.len() {
177 if list_of_versions[cc] > list_of_versions[selected] { selected = cc; }
178 }
179
180 Some(list_of_versions.remove(selected))
181 }
182
183 pub fn latest_compatible<'a>(&self,list : &'a Vec<String>) -> Option<&'a str> {
184 let mut latest = 0;
185 for i in 1..list.len() {
186 if let Some(ver) = Version::from_str(&list[i]){
187 if ver.is_compatible_with(&self) {
188 let ver_latest = Version::from_str(&list[latest]).unwrap();
189 if ver_latest < ver {
190 latest = i;
191 }
192 }
193 }
194 }
195
196 if list.len() > 0 { Some(&list[latest]) } else { None }
197 }
198
199 pub fn latest_compatible_version<'a>(&self,list : &'a Vec<Version>) -> Option<&'a Version> {
200 let mut latest = 0;
201 for i in 1..list.len() {
202 if list[i].is_compatible_with(&self) {
203 if &list[latest] < &list[i] {
204 latest = i;
205 }
206 }
207 }
208
209 if list.len() > 0 { Some(&list[latest]) } else { None }
210 }
211
212 pub fn has_wildcards(&self) -> bool {
214 for i in 0 .. self.parts.len() {
217 if self.parts[i].is_wildcard() { return true; }
218 }
219
220 false
221 }
222 pub fn is_number(&self) -> bool {
223 for i in 0 .. self.parts.len() {
226 if !self.parts[i].is_number() { return false; }
227 }
228
229 true
230 }
231
232 pub fn is_wildcard(&self) -> bool {
233 for i in 0 .. self.parts.len() {
236 if self.parts[i].is_number() { return false; }
237 }
238
239 true
240 }
241
242 pub fn is_compatible_with(&self,other : &Version) -> bool {
243 if self.has_wildcards() { return false; }
250 if other.is_wildcard() { return true; }
251
252 if self == other { return true; }
254
255 let depth : usize = Version::get_shared_depth(&self, other);
256
257 for i in 0 .. depth {
258 if let VersionPart::Number(n) = self.parts[i] {
259 match other.parts[i] {
260 VersionPart::Number(on) => { if on != n { return false; } },
261 VersionPart::Wildcard(_) => { return true; }
262 }
263 }
264 }
265
266 false
267 }
268
269 pub fn to_string(&self) -> String {
271 let mut rendered_string : String = String::new();
274
275 for i in 0 .. self.parts.len() - 1 {
276 rendered_string += &format!("{}.",self.parts[i]);
277 }
278 rendered_string += &format!("{}", self.parts[self.parts.len()-1]);
279
280 return rendered_string;
281 }
282
283 pub fn to_string_serializer(&self) -> String {
284 let mut rendered_string : String = String::new();
287
288 for i in 0 .. self.parts.len() - 1 {
289 rendered_string += &format!("{}_",self.parts[i]);
290 }
291 rendered_string += &format!("{}", self.parts[self.parts.len()-1]);
292
293 return rendered_string;
294 }
295
296}
297
298impl serde::Serialize for Version {
299 fn serialize<S>(&self,serializer : S) -> Result<S::Ok, S::Error> where S : serde::Serializer {
300 serializer.serialize_str(&self.to_string_serializer())
301 }
302}
303
304impl <'de> serde::Deserialize<'de> for Version {
305 fn deserialize<D>(deserializer : D) -> Result<Version, D::Error> where D : serde::Deserializer<'de> {
306 deserializer.deserialize_str(VersionVisitor::new())
307 }
308}
309
310struct VersionVisitor {
311 marker: PhantomData<fn() -> Version>
312}
313
314impl VersionVisitor {
315 fn new() -> Self {
316 VersionVisitor {
317 marker : PhantomData
318 }
319 }
320}
321
322impl <'de>serde::de::Visitor<'de> for VersionVisitor {
323 type Value = Version;
324
325 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
326 formatter.write_str("version")
327 }
328
329 fn visit_str<A>(self, string:&str) -> Result<Self::Value, A> {
330 if let Some(version) = Version::from_str(string) { Ok(version) }
331 else { Ok(Version::from_str("0.0.0").unwrap()) }
332 }
333}
334
335
336#[cfg(test)]
340mod tests {
341 use super::*;
342
343 #[test]
344 fn comparisons() {
345 use super::Version as V;
346
347 assert!(V::new(&[1,2,3]) == V::from_str("1.2.3").unwrap());
348 assert!(V::new(&[1,2,3]) < V::new(&[2,3]));
349 assert!(V::new(&[1,2,3]) <= V::new(&[1,2,4]));
350 assert!(V::new(&[233]) > V::new(&[2,3]));
351 assert!(V::new(&[22,3,56,8]) >= V::new(&[22,3,56]));
352
353 }
358
359 #[test]
360 fn sorting() {
361 let mut vector = vec![
362 super::Version::new(&[1,4,5]),
363 super::Version::new(&[1,0,5]),
364 super::Version::new(&[0,4,5]),
365 super::Version::new(&[0,9,5]),
366 super::Version::new(&[3,0,5])
367 ];
368
369 vector.sort();
370
371 assert_eq!(vector[0],super::Version::new(&[0,4,5]));
372 assert_eq!(vector[4],super::Version::new(&[3,0,5]));
373 assert_eq!(vector[3],super::Version::new(&[1,4,5]));
374 }
375
376 #[test]
377 fn version_is_compatible_with() {
378 assert!(super::Version::from_str("0.1.0").unwrap().is_compatible_with(&super::Version::from_str("0.*.*").unwrap()));
380 assert!(super::Version::from_str("4.1.0").unwrap().is_compatible_with(&super::Version::from_str("4.*.*").unwrap()));
381 assert!(!super::Version::from_str("1.2.0").unwrap().is_compatible_with(&super::Version::from_str("1.1.*").unwrap()));
382 assert!(!super::Version::from_str("11.1.*").unwrap().is_compatible_with(&super::Version::from_str("11.1.4").unwrap()));
383 assert!(super::Version::from_str("1.1").unwrap().is_compatible_with(&super::Version::from_str("1.1.0").unwrap()));
384 assert!(!super::Version::from_str("2.1.0.2.43").unwrap().is_compatible_with(&super::Version::from_str("2.1.1").unwrap()));
385 assert!(!super::Version::from_str("1.1.*").unwrap().is_compatible_with(&super::Version::from_str("1.*.*").unwrap()));
386 assert!(super::Version::from_str("21.11.0").unwrap().is_compatible_with(&super::Version::from_str("*").unwrap()));
387 assert_eq!(false,super::Version::from_str("21.11.0").unwrap().is_compatible_with(&super::Version::from_str("12.*").unwrap()));
389 assert_eq!(false,super::Version::from_str("12.0").unwrap().is_compatible_with(&super::Version::from_str("12.1.2").unwrap()));
390 assert_eq!(false,super::Version::from_str("21.11").unwrap().is_compatible_with(&super::Version::from_str("12").unwrap()));
391 assert_eq!(false,super::Version::from_str("21.*").unwrap().is_compatible_with(&super::Version::from_str("22.12").unwrap()));
392 }
393
394 #[test]
395 fn version_comparisons() {
396 assert!(super::Version::from_str("1.1.0").unwrap() > super::Version::from_str("1.0.0").unwrap());
397 assert!(super::Version::from_str("1.2.0").unwrap() < super::Version::from_str("1.3.1").unwrap());
398 assert!(super::Version::from_str("2.3.2").unwrap() > super::Version::from_str("1.4.8").unwrap());
399 assert!(super::Version::from_str("1.10.2").unwrap() > super::Version::from_str("1.4.22").unwrap());
400 }
401
402 #[test]
403 fn latest_compatible() {
404 let versions : Vec<String> = vec![
405 "1.0.1".to_string(),
406 "1.0.2".to_string(),
407 "1.1.0".to_string(),
408 "1.0.0".to_string()
409 ];
410
411 let version = Version::from_str("1.*.*").unwrap();
412
413 assert_eq!(version.latest_compatible(&versions).unwrap().to_string(),"1.1.0".to_string());
414 }
415
416 #[test]
417 fn latest_compatible_version() {
418 let versions : Vec<Version> = vec![
419 Version::from_str("1.0.0").unwrap(),
420 Version::from_str("1.0.1").unwrap(),
421 Version::from_str("1.0.2").unwrap(),
422 Version::from_str("1.1.0").unwrap()
423 ];
424
425 let version = Version::from_str("1.*.*").unwrap();
426
427 assert_eq!(version.latest_compatible_version(&versions).unwrap().to_string(),"1.1.0".to_string());
428 assert_eq!(Version::new(&[1]).latest_compatible_version(&versions).unwrap().to_string(),"1.1.0".to_string());
429 }
430
431 #[test]
432 fn versionpart_is_number() {
433 let vp = super::VersionPart::Number(12);
434 let vp2 = super::VersionPart::Wildcard("*".to_string());
435 assert!(vp.is_number());
436 assert!(!vp2.is_number());
437 }
438
439 #[test]
440 fn versionpart_is_wildcard() {
441 let vp = super::VersionPart::Number(12);
442 let vp2 = super::VersionPart::Wildcard("*".to_string());
443 assert!(!vp.is_wildcard());
444 assert!(vp2.is_wildcard());
445 }
446
447 #[test]
448 fn versionpart_equals() {
449 let vp = super::VersionPart::Number(14);
450 let vp2 = super::VersionPart::Number(65);
451 let vp3 = super::VersionPart::Wildcard("*".to_string());
452 assert!(vp == super::VersionPart::Number(14));
453 assert!(vp2 == super::VersionPart::Number(65));
454 assert!(vp2 != vp);
455 assert!(vp != vp3);
456 }
457
458 #[test]
459 fn version_from_string() {
460 let ver1 : super::Version = super::Version::from_str("1.0.0").unwrap();
461 assert_eq!(super::Version::new(&[1,0,0]),ver1);
462 }
463
464 #[test]
465 fn serde() {
466 use serde_test::{Token, assert_tokens};
467
468 let version = super::Version::from_str("0.1.2").unwrap();
469 assert_tokens(&version,&[Token::Str("0_1_2")]);
470
471 }
472
473
474}