1 module ddbus.util; 2 3 import ddbus.thin; 4 import std.typecons; 5 import std.range; 6 import std.traits; 7 8 struct DictionaryEntry(K, V) { 9 K key; 10 V value; 11 } 12 13 auto byDictionaryEntries(K, V)(V[K] aa) { 14 import std.algorithm : map; 15 16 return aa.byKeyValue.map!(pair => DictionaryEntry!(K, V)(pair.key, pair.value)); 17 } 18 19 template isVariant(T) { 20 static if(isBasicType!T || isInputRange!T) { 21 enum isVariant = false; 22 } else static if(__traits(compiles, TemplateOf!T) 23 && __traits(isSame, TemplateOf!T, Variant)) { 24 enum isVariant = true; 25 } else { 26 enum isVariant = false; 27 } 28 } 29 30 template VariantType(T) { 31 alias VariantType = TemplateArgsOf!(T)[0]; 32 } 33 34 template allCanDBus(TS...) { 35 static if (TS.length == 0) { 36 enum allCanDBus = true; 37 } else static if(!canDBus!(TS[0])) { 38 enum allCanDBus = false; 39 } else { 40 enum allCanDBus = allCanDBus!(TS[1..$]); 41 } 42 } 43 44 template basicDBus(T) { 45 static if(is(T == byte) || is(T == short) || is (T == ushort) || is (T == int) 46 || is (T == uint) || is (T == long) || is (T == ulong) 47 || is (T == double) || is (T == string) || is(T == bool)) { 48 enum basicDBus = true; 49 } else { 50 enum basicDBus = false; 51 } 52 } 53 54 template canDBus(T) { 55 static if(basicDBus!T || is(T == DBusAny)) { 56 enum canDBus = true; 57 } else static if(isVariant!T) { 58 enum canDBus = canDBus!(VariantType!T); 59 } else static if(isTuple!T) { 60 enum canDBus = allCanDBus!(T.Types); 61 } else static if(isInputRange!T) { 62 enum canDBus = canDBus!(ElementType!T); 63 } else static if(isAssociativeArray!T) { 64 enum canDBus = canDBus!(KeyType!T) && canDBus!(ValueType!T); 65 } else static if(is(T == DictionaryEntry!(K, V), K, V)) { 66 enum canDBus = canDBus!K && canDBus!V; 67 } else { 68 enum canDBus = false; 69 } 70 } 71 unittest { 72 import dunit.toolkit; 73 (canDBus!int).assertTrue(); 74 (canDBus!(int[])).assertTrue(); 75 (allCanDBus!(int,string,bool)).assertTrue(); 76 (canDBus!(Tuple!(int[],bool,Variant!short))).assertTrue(); 77 (canDBus!(Tuple!(int[],int[string]))).assertTrue(); 78 (canDBus!(int[string])).assertTrue(); 79 } 80 81 string typeSig(T)() if(canDBus!T) { 82 static if(is(T == byte)) { 83 return "y"; 84 } else static if(is(T == bool)) { 85 return "b"; 86 } else static if(is(T == short)) { 87 return "n"; 88 } else static if(is(T == ushort)) { 89 return "q"; 90 } else static if(is(T == int)) { 91 return "i"; 92 } else static if(is(T == uint)) { 93 return "u"; 94 } else static if(is(T == long)) { 95 return "x"; 96 } else static if(is(T == ulong)) { 97 return "t"; 98 } else static if(is(T == double)) { 99 return "d"; 100 } else static if(is(T == string)) { 101 return "s"; 102 } else static if(isVariant!T) { 103 return "v"; 104 } else static if(is(T == DBusAny)) { 105 static assert(false, "Cannot determine type signature of DBusAny. Change to Variant!DBusAny if a variant was desired."); 106 } else static if(isTuple!T) { 107 string sig = "("; 108 foreach(i, S; T.Types) { 109 sig ~= typeSig!S(); 110 } 111 sig ~= ")"; 112 return sig; 113 } else static if(is(T == DictionaryEntry!(K, V), K, V)) { 114 return '{' ~ typeSig!K ~ typeSig!V ~ '}'; 115 } else static if(isInputRange!T) { 116 return "a" ~ typeSig!(ElementType!T)(); 117 } else static if(isAssociativeArray!T) { 118 return "a{" ~ typeSig!(KeyType!T) ~ typeSig!(ValueType!T) ~ "}"; 119 } 120 } 121 122 string[] typeSigReturn(T)() if(canDBus!T) { 123 static if(is(T == Tuple!TS, TS...)) 124 return typeSigArr!TS; 125 else 126 return [typeSig!T]; 127 } 128 129 string typeSigAll(TS...)() if(allCanDBus!TS) { 130 string sig = ""; 131 foreach(i,T; TS) { 132 sig ~= typeSig!T(); 133 } 134 return sig; 135 } 136 137 string[] typeSigArr(TS...)() if(allCanDBus!TS) { 138 string[] sig = []; 139 foreach(i,T; TS) { 140 sig ~= typeSig!T(); 141 } 142 return sig; 143 } 144 145 int typeCode(T)() if(canDBus!T) { 146 string sig = typeSig!T(); 147 return sig[0]; 148 } 149 150 unittest { 151 import dunit.toolkit; 152 // basics 153 typeSig!int().assertEqual("i"); 154 typeSig!bool().assertEqual("b"); 155 typeSig!string().assertEqual("s"); 156 typeSig!(Variant!int)().assertEqual("v"); 157 // structs 158 typeSig!(Tuple!(int,string,string)).assertEqual("(iss)"); 159 typeSig!(Tuple!(int,string,Variant!int,Tuple!(int,"k",double,"x"))).assertEqual("(isv(id))"); 160 // arrays 161 typeSig!(int[]).assertEqual("ai"); 162 typeSig!(Variant!int[]).assertEqual("av"); 163 typeSig!(Tuple!(byte)[][]).assertEqual("aa(y)"); 164 // dictionaries 165 typeSig!(int[string]).assertEqual("a{si}"); 166 typeSig!(DictionaryEntry!(string, int)).assertEqual("{si}"); 167 // multiple arguments 168 typeSigAll!(int,bool).assertEqual("ib"); 169 // type codes 170 typeCode!int().assertEqual(cast(int)('i')); 171 typeCode!bool().assertEqual(cast(int)('b')); 172 // ctfe-capable 173 static string sig = typeSig!ulong(); 174 sig.assertEqual("t"); 175 static string sig2 = typeSig!(Tuple!(int,string,string)); 176 sig2.assertEqual("(iss)"); 177 static string sig3 = typeSigAll!(int,string,string); 178 sig3.assertEqual("iss"); 179 } 180