1 module dud.resolve.conf;
2 
3 import std.array : empty;
4 import std.typecons : Flag;
5 import std.stdio;
6 import std.format : format;
7 
8 import dud.resolve.positive;
9 import dud.semver.versionrange;
10 import dud.resolve.confs;
11 
12 @safe pure:
13 
14 struct Conf {
15 @safe pure:
16 	/// empty means wildcard
17 	string conf;
18 	/// true means the inverse of the `conf` inverse of `conf.empty`
19 	/// still means wildcard
20 	IsPositive isPositive;
21 
22 	this(string s) {
23 		this(s, IsPositive.yes);
24 	}
25 
26 	this(string s, IsPositive b) {
27 		this.conf = s;
28 		this.isPositive = b;
29 	}
30 
31 	Conf dup() const {
32 		return Conf(this.conf, this.isPositive);
33 	}
34 
35 	int opCmp(const(Conf) other) const nothrow @nogc {
36 		return this.conf < other.conf
37 			? -1
38 			: this.conf > other.conf
39 				? 1
40 				: this.isPositive < other.isPositive
41 					? -1
42 					: this.isPositive > other.isPositive
43 						? 1
44 						: 0;
45 	}
46 
47 	bool opEquals(const(Conf) other) const nothrow @nogc {
48 		return this.conf == other.conf && this.isPositive == other.isPositive;
49 	}
50 }
51 
52 Conf invert(const(Conf) c) {
53 	return Conf(c.conf, cast(IsPositive)!c.isPositive);
54 }
55 
56 bool allowsAny(const(Conf) a, const(Conf) b) {
57 	if(a.isPositive == IsPositive.no && a.conf.empty) {
58 		return false;
59 	}
60 
61 	if(b.isPositive == IsPositive.no && b.conf.empty) {
62 		return false;
63 	}
64 
65 	if(a.isPositive == IsPositive.yes && a.conf.empty) {
66 		return true;
67 	}
68 
69 	if(b.isPositive == IsPositive.yes && b.conf.empty) {
70 		return true;
71 	}
72 
73 	return a.isPositive == IsPositive.yes && b.isPositive == IsPositive.yes
74 		? a.conf == b.conf
75 		: false;
76 }
77 
78 bool allowsAll(const(Conf) a, const(Conf) b) {
79 	return a.isPositive == IsPositive.yes && a.conf.empty
80 		? true
81 		: a.isPositive == IsPositive.no && a.conf.empty
82 			? false
83 			: a.isPositive == IsPositive.yes && a.isPositive == b.isPositive
84 				? a.conf == b.conf
85 				: false;
86 }
87 
88 Confs intersectionOf(const(Conf) a, const(Conf) b) {
89 	if((a.isPositive == IsPositive.no && a.conf.empty)
90 		|| (b.isPositive == IsPositive.no && b.conf.empty))
91 	{
92 		return Confs([Conf("", IsPositive.no)]);
93 	}
94 
95 	if(a.isPositive == IsPositive.yes && a.conf.empty) {
96 		return b.isPositive == IsPositive.no
97 			? Confs([a, Conf(b.conf, b.isPositive)])
98 			: Confs([Conf(b.conf, b.isPositive)]);
99 	}
100 
101 	if(b.isPositive == IsPositive.yes && b.conf.empty) {
102 		return a.isPositive == IsPositive.no
103 			? Confs([b, Conf(a.conf, a.isPositive)])
104 			: Confs([Conf(a.conf, a.isPositive)]);
105 	}
106 
107 	if(a == b) {
108 		return Confs([Conf(a.conf, a.isPositive)]);
109 	}
110 
111 	return Confs([]);
112 }
113 
114 Confs differenceOf(const(Conf) a, const(Conf) b) {
115 	return a == b
116 		? Confs([])
117 		: Confs([a]);
118 }
119 
120 /** Return if a is a subset of b, or if a and b are disjoint, or
121 if a and b overlap
122 */
123 SetRelation relation(const(Conf) a, const(Conf) b) pure {
124 	return allowsAll(b, a)
125 		? SetRelation.subset
126 		: allowsAny(b, a)
127 			? SetRelation.overlapping
128 			: SetRelation.disjoint;
129 }