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