1 module dud.semver.comparision;
2 
3 import std.array : empty;
4 import std.typecons : nullable, Nullable;
5 
6 import dud.semver.semver;
7 import dud.semver.exception;
8 
9 @safe pure:
10 
11 int compare(const(SemVer) a, const(SemVer) b) nothrow {
12 	if(a.major != b.major) {
13 		return a.major < b.major ? -1 : 1;
14 	}
15 
16 	if(a.minor != b.minor) {
17 		return a.minor < b.minor ? -1 : 1;
18 	}
19 
20 	if(a.patch != b.patch) {
21 		return a.patch < b.patch ? -1 : 1;
22 	}
23 
24 	if(a.preRelease.empty != b.preRelease.empty) {
25 		return a.preRelease.empty ? 1 : -1;
26 	}
27 
28 	size_t idx;
29 	while(idx < a.preRelease.length && idx < b.preRelease.length) {
30 		string aStr = a.preRelease[idx];
31 		string bStr = b.preRelease[idx];
32 		Nullable!uint aNumN = isAllNum(aStr);
33 		Nullable!uint bNumN = isAllNum(bStr);
34 		if(!aNumN.isNull() && !bNumN.isNull()) {
35 			uint aNum = aNumN.get();
36 			uint bNum = bNumN.get();
37 
38 			if(aNum != bNum) {
39 				return aNum < bNum ? -1 : 1;
40 			}
41 		} else if(aStr != bStr) {
42 			return aStr < bStr ? -1 : 1;
43 		}
44 		++idx;
45 	}
46 
47 	if(idx == a.preRelease.length && idx == b.preRelease.length) {
48 		return 0;
49 	}
50 
51 	return idx < a.preRelease.length ? 1 : -1;
52 }
53 
54 Nullable!uint isAllNum(string s) nothrow {
55 	import std.utf : byUTF;
56 	import dud.semver.helper : isDigit;
57 	import std.algorithm.searching : all;
58 	import std.conv : to, ConvException;
59 
60 	const bool allNum = s.byUTF!char().all!isDigit();
61 
62 	if(allNum) {
63 		try {
64 			return nullable(to!uint(s));
65 		} catch(Exception e) {
66 			assert(false, s);
67 		}
68 	}
69 	return Nullable!(uint).init;
70 }
71 
72 unittest {
73 	import std.format : format;
74 	auto i = isAllNum("hello world");
75 	assert(i.isNull());
76 
77 	i = isAllNum("12354");
78 	assert(!i.isNull());
79 	assert(i.get() == 12354);
80 
81 	i = isAllNum("0002354");
82 	assert(!i.isNull());
83 	assert(i.get() == 2354);
84 }