1 module ddbus.util; 2 import std.typecons; 3 import std.range; 4 import std.traits; 5 6 template allCanDBus(TS...) { 7 static if (TS.length == 0) { 8 enum allCanDBus = true; 9 } else static if(!canDBus!(TS[0])) { 10 enum allCanDBus = false; 11 } else { 12 enum allCanDBus = allCanDBus!(TS[1..$]); 13 } 14 } 15 16 template basicDBus(T) { 17 static if(is(T == byte) || is(T == short) || is (T == ushort) || is (T == int) 18 || is (T == uint) || is (T == long) || is (T == ulong) 19 || is (T == double) || is (T == string) || is(T == bool)) { 20 enum basicDBus = true; 21 } else { 22 enum basicDBus = false; 23 } 24 } 25 26 template canDBus(T) { 27 static if(basicDBus!T) { 28 enum canDBus = true; 29 } else static if(isTuple!T) { 30 enum canDBus = allCanDBus!(T.Types); 31 } else static if(isInputRange!T) { 32 enum canDBus = canDBus!(ElementType!T); 33 } else static if(isAssociativeArray!T) { 34 enum canDBus = canDBus!(ValueType!T) && basicDBus!(KeyType!T); 35 } else { 36 enum canDBus = false; 37 } 38 } 39 unittest { 40 import dunit.toolkit; 41 (canDBus!int).assertTrue(); 42 (canDBus!(int[])).assertTrue(); 43 (allCanDBus!(int,string,bool)).assertTrue(); 44 (canDBus!(Tuple!(int[],bool))).assertTrue(); 45 (canDBus!(Tuple!(int[],int[string]))).assertFalse(); 46 (canDBus!(int[string])).assertFalse(); 47 } 48 49 string typeSig(T)() if(canDBus!T) { 50 static if(is(T == byte)) { 51 return "y"; 52 } else static if(is(T == bool)) { 53 return "b"; 54 } else static if(is(T == short)) { 55 return "n"; 56 } else static if(is(T == ushort)) { 57 return "q"; 58 } else static if(is(T == int)) { 59 return "i"; 60 } else static if(is(T == uint)) { 61 return "u"; 62 } else static if(is(T == long)) { 63 return "x"; 64 } else static if(is(T == ulong)) { 65 return "t"; 66 } else static if(is(T == double)) { 67 return "d"; 68 } else static if(is(T == string)) { 69 return "s"; 70 } else static if(is(T == void)) { 71 return ""; 72 } else static if(isTuple!T) { 73 string sig = "("; 74 foreach(i, S; T.Types) { 75 sig ~= typeSig!S(); 76 } 77 sig ~= ")"; 78 return sig; 79 } else static if(isInputRange!T) { 80 return "a" ~ typeSig!(ElementType!T)(); 81 } else static if(isAssociativeArray!T) { 82 return "a{" ~ typeSig!(KeyType!T)() ~ typeSig!(ValueType!T)() ~ "}"; 83 } 84 } 85 86 string typeSigAll(TS...)() if(allCanDBus!TS) { 87 string sig = ""; 88 foreach(i,T; TS) { 89 sig ~= typeSig!T(); 90 } 91 return sig; 92 } 93 94 string[] typeSigArr(TS...)() if(allCanDBus!TS) { 95 string[] sig = []; 96 foreach(i,T; TS) { 97 sig ~= typeSig!T(); 98 } 99 return sig; 100 } 101 102 int typeCode(T)() if(canDBus!T) { 103 static if(isTuple!T) { 104 return 'r'; 105 } else { 106 string sig = typeSig!T(); 107 return sig[0]; 108 } 109 } 110 111 unittest { 112 import dunit.toolkit; 113 // basics 114 typeSig!int().assertEqual("i"); 115 typeSig!bool().assertEqual("b"); 116 typeSig!string().assertEqual("s"); 117 // structs 118 typeSig!(Tuple!(int,string,string)).assertEqual("(iss)"); 119 typeSig!(Tuple!(int,string,Tuple!(int,"k",double,"x"))).assertEqual("(is(id))"); 120 // arrays 121 typeSig!(int[]).assertEqual("ai"); 122 typeSig!(Tuple!(byte)[][]).assertEqual("aa(y)"); 123 // multiple arguments 124 typeSigAll!(int,bool).assertEqual("ib"); 125 // type codes 126 typeCode!int().assertEqual(cast(int)('i')); 127 typeCode!bool().assertEqual(cast(int)('b')); 128 // ctfe-capable 129 static string sig = typeSig!ulong(); 130 sig.assertEqual("t"); 131 static string sig2 = typeSig!(Tuple!(int,string,string)); 132 sig2.assertEqual("(iss)"); 133 static string sig3 = typeSigAll!(int,string,string); 134 sig3.assertEqual("iss"); 135 } 136