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 }