1 module dud.semver.semver;
2 
3 @safe:
4 
5 struct SemVer {
6 @safe:
7 
8 	uint major;
9 	uint minor;
10 	uint patch;
11 
12 	string[] preRelease;
13 	string[] buildIdentifier;
14 
15 	static immutable(SemVer) MinRelease = SemVer(0, 0, 0);
16 	static immutable(SemVer) MaxRelease = SemVer(uint.max, uint.max, uint.max);
17 
18 	bool opEquals(const(SemVer) other) const nothrow pure {
19 		import dud.semver.comparision : compare;
20 		return compare(this, other) == 0;
21 	}
22 
23 	int opCmp(const(SemVer) other) const nothrow pure {
24 		import dud.semver.comparision : compare;
25 		return compare(this, other);
26 	}
27 
28 	size_t toHash() const nothrow @nogc pure {
29 		import std.algorithm.iteration : each;
30 		size_t hash = this.major.hashOf();
31 		hash = this.minor.hashOf(hash);
32 		hash = this.patch.hashOf(hash);
33 		this.preRelease.each!(it => hash = it.hashOf(hash));
34 		this.buildIdentifier.each!(it => hash = it.hashOf(hash));
35 		return hash;
36 	}
37 
38 	@property SemVer dup() const pure {
39 		auto ret = SemVer(this.major, this.minor, this.patch,
40 				this.preRelease.dup(), this.buildIdentifier.dup());
41 		return ret;
42 	}
43 
44 	static SemVer max() pure {
45 		return SemVer(uint.max, uint.max, uint.max);
46 	}
47 
48 	static SemVer min() pure {
49 		return SemVer(uint.min, uint.min, uint.min);
50 	}
51 
52 	string toString() const @safe pure {
53 		import std.array : appender, empty;
54 		import std.format : format;
55 		string ret = format("%s.%s.%s", this.major, this.minor, this.patch);
56 		if(!this.preRelease.empty) {
57 			ret ~= format("-%-(%s.%)", this.preRelease);
58 		}
59 		if(!this.buildIdentifier.empty) {
60 			ret ~= format("+%-(%s.%)", this.buildIdentifier);
61 		}
62 		return ret;
63 	}
64 }