2using System.Collections.Generic;
3using System.Collections.Immutable;
15 internal readonly
struct ModuleVersion : IComparable<ModuleVersion>
18 public static bool operator ==(ModuleVersion x, ModuleVersion y) => x.Equals(y);
20 public static bool operator !=(ModuleVersion x, ModuleVersion y) => x.Equals(y) ==
false;
22 public static bool operator <(ModuleVersion x, ModuleVersion y) => Compare(x, y) < 0;
24 public static bool operator >(ModuleVersion x, ModuleVersion y) => Compare(x, y) > 0;
26 public static bool operator <=(ModuleVersion x, ModuleVersion y) => Compare(x, y) <= 0;
28 public static bool operator >=(ModuleVersion x, ModuleVersion y) => Compare(x, y) >= 0;
30 public static int Compare(ModuleVersion x, ModuleVersion y) => x.CompareTo(y);
37 public static bool TryParse(
string value, out ModuleVersion parsed)
39 return TryParse(value.AsSpan(), out parsed);
47 public static bool TryParse(ReadOnlySpan<char> value, out ModuleVersion parsed)
49 return TryParse(value, out parsed, out _);
58 public static bool TryParse(ReadOnlySpan<char> value, out ModuleVersion parsed, out
string? error)
66 error =
"Empty version string";
72 if (!(c >=
'0' && c <=
'9'))
74 error = $
"{value}: Version string does not start with a number";
78 var sequence = ImmutableArray.CreateBuilder<ModuleVersionComponent>(3);
79 var pre = ImmutableArray.CreateBuilder<ModuleVersionComponent>(0);
80 var build = ImmutableArray.CreateBuilder<ModuleVersionComponent>(0);
82 i = TakeNumber(value, i, sequence);
92 if (c ==
'-' || c ==
'+')
97 if (c >=
'0' && c <=
'9')
98 i = TakeNumber(value, i, sequence);
100 i = TakeString(value, i, sequence);
103 if (c ==
'-' && i >= n)
105 error = $
"{value}: Empty pre-release";
112 if (c ==
'.' || c ==
'-')
123 if (c >=
'0' && c <=
'9')
124 i = TakeNumber(value, i, pre);
126 i = TakeString(value, i, pre);
129 if (c ==
'+' && i >= n)
131 error = $
"{value}: Empty pre-release";
138 if (c ==
'.' || c ==
'-' || c ==
'+')
143 if (c >=
'0' && c <=
'9')
144 i = TakeNumber(value, i, build);
146 i = TakeString(value, i, build);
149 parsed =
new ModuleVersion(value.ToString(), sequence.DrainToImmutable(), pre.DrainToImmutable(), build.DrainToImmutable());
159 public static ModuleVersion Parse(ReadOnlySpan<char> version)
161 if (TryParse(version, out var parsed, out var error))
164 throw new ArgumentException(error, nameof(version));
173 public static ModuleVersion Parse(
string version)
176 throw new ArgumentNullException(nameof(version));
178 return Parse(version.AsSpan());
188 static int TakeNumber(ReadOnlySpan<char> s,
int i, ImmutableArray<ModuleVersionComponent>.Builder list)
196 if (c >=
'0' && c <=
'9')
198 d = d * 10 + (c -
'0');
205 list.Add(
new ModuleVersionComponent(d));
216 static int TakeString(ReadOnlySpan<char> s,
int i, ImmutableArray<ModuleVersionComponent>.Builder list)
223 if (c !=
'.' && c !=
'-' && c !=
'+' && !(c >=
'0' && c <=
'9'))
229 AddModuleVersionComponent(list, s.Slice(b, i - b).ToString());
238 [MethodImpl(MethodImplOptions.NoInlining)]
239 static void AddModuleVersionComponent(ImmutableArray<ModuleVersionComponent>.Builder builder,
string value)
241 builder.Add(
new ModuleVersionComponent(value));
244 readonly
string _rawValue;
245 readonly ImmutableArray<ModuleVersionComponent> _sequence;
246 readonly ImmutableArray<ModuleVersionComponent> _pre;
247 readonly ImmutableArray<ModuleVersionComponent> _build;
256 public ModuleVersion(
string rawValue, ImmutableArray<ModuleVersionComponent> sequence, ImmutableArray<ModuleVersionComponent> pre, ImmutableArray<ModuleVersionComponent> build)
258 _rawValue = rawValue ??
throw new ArgumentNullException(nameof(rawValue));
259 _sequence = sequence;
267 public readonly
bool IsValid => _sequence.IsDefaultOrEmpty ==
false;
272 public readonly
string RawValue => _rawValue;
277 public readonly ImmutableArray<ModuleVersionComponent> Sequence => _sequence;
282 public readonly ImmutableArray<ModuleVersionComponent> Pre => _pre;
287 public readonly ImmutableArray<ModuleVersionComponent> Build => _build;
295 readonly
int CompareComponents(ImmutableArray<ModuleVersionComponent> x, ImmutableArray<ModuleVersionComponent> y)
301 public readonly
int CompareTo(ModuleVersion other)
303 if (IsValid && other.IsValid ==
false)
305 if (IsValid ==
false && other.IsValid)
309 int c = CompareComponents(_sequence, other._sequence);
316 if (other._pre.IsEmpty ==
false)
321 if (other._pre.IsEmpty)
326 c = CompareComponents(_pre, other._pre);
331 return CompareComponents(_build, other._build);
335 public readonly
override int GetHashCode()
337 if (IsValid ==
false)
340 var hc =
new HashCode();
342 foreach (var i
in _sequence)
345 foreach (var i
in _pre)
348 foreach (var i
in _build)
351 return hc.ToHashCode();
355 public readonly
override bool Equals(
object? other)
357 return other is ModuleVersion v && Equals(v);
365 public readonly
bool Equals(ModuleVersion other)
368 if (IsValid ==
false && other.IsValid ==
false)
372 if (IsValid && other.IsValid)
373 return _sequence.SequenceEqual(other._sequence) && _pre.SequenceEqual(other._pre) && _build.SequenceEqual(other._build);
379 public readonly
override string? ToString()
Implements an IComparer<T> which lexicographically compares a two lists.
override int Compare(TList? x, TList? y)
static new readonly LexicographicListComparer< T > Default
Returns a default LexicographicListComparer<T> instance.