1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//! Semantic Version.

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SemVer {
	/// Major
	pub major: i32,
	/// Minor
	pub minor: i32,
	/// Patch
	pub patch: i32,
	/// extra_field is the anotation like `-alpha`
	pub extra_field: String // TODO this needs a better name
}

impl SemVer {
	/// Creates a new [`SemVer`] with initialized values.
	///
	/// Use `dafault()` for a 0.1.0 initialized.
	pub fn new(major: i32, minor: i32, patch: i32, extra_field: String) -> Self {
		Self {
			major,
			minor,
			patch,
			extra_field,
		}
	}
	
	/// Creates a new [`SemVer`] from a [`String`] like `1.12.2-alpha`
	pub fn from_string(string: String) -> Result<Self, &'static str> {
		let string: Vec<&str> = string.split('-').collect();
		let ver: Vec<&str> = string[0].split('.').collect();
		if ver.len() != 3 || string.len() > 2 {
			return Err("invalid version length")
		}
		Ok(Self{
			major: match ver[0].parse() {
				Ok(v) => v,
				Err(..) => return Err("invalid major")
			},
			minor: match ver[1].parse() {
				Ok(v) => v,
				Err(..) => return Err("invalid minor")
			},
			patch: match ver[2].parse() {
				Ok(v) => v,
				Err(..) => return Err("invalid patch")
			},
			extra_field: if string.len() > 1 {
				string[1].to_owned()
			} else {
				"".to_owned()
			}
		})
	}
	
	/// Converts itself into a [`String`] like `89.4.6-beta`
	pub fn to_string(&self) -> String {
		let tmp = [
			&self.major.to_string(), ".",
			&self.minor.to_string(), ".",
			&self.patch.to_string()
		].concat();
		if !self.extra_field.is_empty() {
			return [
				&tmp, "-",
				&self.extra_field
			].concat();
		}
		tmp
	}
	
	/// Returns the difference as a [`SemVer`] of itself agains other [`SemVer`].
	pub fn difference(&self, other: &Self) -> Self {
		Self{
			major: self.major - other.major,
			minor: self.minor - other.minor,
			patch: self.patch - other.patch,
			extra_field: "".to_owned()
		}
	}
}

impl Default for SemVer {
	/// Creates a new [`SemVer`] initialized with `0.1.0`
	fn default() -> Self {
		Self {
			major: 0,
			minor: 1,
			patch: 0,
			extra_field: "".to_owned()
		}
	}
}