A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3using System.Text.RegularExpressions; 4 5namespace Unity.VisualScripting 6{ 7 public struct SemanticVersion : IComparable<SemanticVersion> 8 { 9 [Serialize] 10 public readonly int major; 11 12 [Serialize] 13 public readonly int minor; 14 15 [Serialize] 16 public readonly int patch; 17 18 [Serialize] 19 public readonly string label; 20 21 [Serialize] 22 public readonly int increment; 23 24 public SemanticVersion(int major, int minor, int patch, string label, int increment) 25 { 26 this.major = major; 27 this.minor = minor; 28 this.patch = patch; 29 this.label = label; 30 this.increment = increment; 31 } 32 33 public SemanticVersion(string semVerString) 34 { 35 this = Parse(semVerString); 36 } 37 38 public SemanticLabel semanticLabel 39 { 40 get 41 { 42 if (StringUtility.IsNullOrWhiteSpace(label)) 43 { 44 return SemanticLabel.Unspecified; 45 } 46 47 switch (label.Filter(whitespace: false, punctuation: false, symbols: false).ToLower()) 48 { 49 case "pre": 50 return SemanticLabel.Pre; 51 52 case "a": 53 case "alpha": 54 return SemanticLabel.Alpha; 55 56 case "b": 57 case "beta": 58 return SemanticLabel.Beta; 59 60 case "rc": 61 case "releasecandidate": 62 return SemanticLabel.ReleaseCandidate; 63 64 case "f": 65 case "final": 66 case "hotfix": 67 case "fix": 68 return SemanticLabel.Final; 69 70 default: 71 return SemanticLabel.Unspecified; 72 } 73 } 74 } 75 76 public override string ToString() 77 { 78 if (semanticLabel == SemanticLabel.Unspecified) 79 { 80 return $"{major}.{minor}.{patch}"; 81 } 82 else 83 { 84 return $"{major}.{minor}.{patch}{label}{increment}"; 85 } 86 } 87 88 public static implicit operator SemanticVersion(string s) 89 { 90 return Parse(s); 91 } 92 93 public static SemanticVersion Parse(string s) 94 { 95 SemanticVersion result; 96 97 if (!TryParse(s, out result)) 98 { 99 throw new ArgumentException("s"); 100 } 101 102 return result; 103 } 104 105 public static bool TryParse(string s, out SemanticVersion result) 106 { 107 result = default(SemanticVersion); 108 109 if (s == null) 110 { 111 throw new ArgumentNullException(nameof(s)); 112 } 113 114 var regex = new Regex(@"(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:(?<label>[a-zA-Z\s\-_\.]+)(?<increment>\d+))?", RegexOptions.IgnoreCase | RegexOptions.Singleline); 115 var match = regex.Match(s); 116 117 if (!match.Success) 118 { 119 return false; 120 } 121 122 int major, minor, patch, increment = 0; 123 string label = null; 124 125 major = int.Parse(match.Groups["major"].Value); 126 minor = int.Parse(match.Groups["minor"].Value); 127 patch = int.Parse(match.Groups["patch"].Value); 128 129 if (match.Groups["label"].Success) 130 { 131 label = match.Groups["label"].Value; 132 } 133 134 if (match.Groups["increment"].Success) 135 { 136 increment = int.Parse(match.Groups["increment"].Value); 137 } 138 139 result = new SemanticVersion(major, minor, patch, label, increment); 140 141 return true; 142 } 143 144 // Final > _(Nothing)_ > Release Candidate > Beta > Alpha > Pre 145 private static readonly Dictionary<SemanticLabel, int> LabelComparisonMap = new Dictionary<SemanticLabel, int>() 146 { 147 { SemanticLabel.Final, 6 }, 148 { SemanticLabel.Unspecified, 5 }, 149 { SemanticLabel.ReleaseCandidate, 4 }, 150 { SemanticLabel.Beta, 3 }, 151 { SemanticLabel.Alpha, 2 }, 152 { SemanticLabel.Pre, 1 }, 153 }; 154 155 public int CompareTo(SemanticVersion other) 156 { 157 var majorComparison = major.CompareTo(other.major); 158 159 if (majorComparison != 0) 160 { 161 return majorComparison; 162 } 163 164 var minorComparison = minor.CompareTo(other.minor); 165 166 if (minorComparison != 0) 167 { 168 return minorComparison; 169 } 170 171 var patchComparison = patch.CompareTo(other.patch); 172 173 if (patchComparison != 0) 174 { 175 return patchComparison; 176 } 177 178 // Final > _(Nothing)_ > Release Candidate > Beta > Alpha > Pre 179 var ours = LabelComparisonMap[this.semanticLabel]; 180 var others = LabelComparisonMap[other.semanticLabel]; 181 var labelComparison = ours.CompareTo(others); 182 183 if (labelComparison != 0) 184 { 185 return labelComparison; 186 } 187 188 var incrementComparison = increment.CompareTo(other.increment); 189 190 if (incrementComparison != 0) 191 { 192 return incrementComparison; 193 } 194 195 return 0; 196 } 197 198 public override bool Equals(object obj) 199 { 200 if (!(obj is SemanticVersion)) 201 { 202 return false; 203 } 204 205 var other = (SemanticVersion)obj; 206 207 return 208 other.major == major && 209 other.minor == minor && 210 other.patch == patch && 211 other.semanticLabel == semanticLabel && 212 other.increment == increment; 213 } 214 215 public override int GetHashCode() 216 { 217 return HashUtility.GetHashCode(major, minor, patch); 218 } 219 220 public static bool operator ==(SemanticVersion a, SemanticVersion b) 221 { 222 return a.Equals(b); 223 } 224 225 public static bool operator !=(SemanticVersion a, SemanticVersion b) 226 { 227 return !(a == b); 228 } 229 230 public static bool operator <(SemanticVersion a, SemanticVersion b) 231 { 232 return a.CompareTo(b) < 0; 233 } 234 235 public static bool operator >(SemanticVersion a, SemanticVersion b) 236 { 237 return a.CompareTo(b) > 0; 238 } 239 240 public static bool operator <=(SemanticVersion a, SemanticVersion b) 241 { 242 return a.CompareTo(b) <= 0; 243 } 244 245 public static bool operator >=(SemanticVersion a, SemanticVersion b) 246 { 247 return a.CompareTo(b) >= 0; 248 } 249 250 public bool IsUnset() 251 { 252 return Equals(new SemanticVersion(0, 0, 0, null, 0)); 253 } 254 } 255}