1 module ddbus.conv;
2 
3 import ddbus.c_lib;
4 import ddbus.util;
5 import std.string;
6 import std.typecons;
7 import std.range;
8 import std.traits;
9 
10 void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
11   foreach(index, arg; args) {
12     alias TS[index] T;
13     static if(is(T == string)) {
14       immutable(char)* cStr = arg.toStringz();
15       dbus_message_iter_append_basic(iter,typeCode!T,&cStr);
16     } else static if(is(T==bool)) {
17       dbus_bool_t longerBool = arg; // dbus bools are ints
18       dbus_message_iter_append_basic(iter,typeCode!T,&longerBool);
19     } else static if(isTuple!T) {
20       DBusMessageIter sub;
21       dbus_message_iter_open_container(iter, 'r', null, &sub);
22       buildIter(&sub, arg.expand);
23       dbus_message_iter_close_container(iter, &sub);
24     } else static if(isInputRange!T) {
25       DBusMessageIter sub;
26       const(char)* subSig = (typeSig!(ElementType!T)()).toStringz();
27       dbus_message_iter_open_container(iter, 'a', subSig, &sub);
28       foreach(x; arg) {
29         buildIter(&sub, x);
30       }
31       dbus_message_iter_close_container(iter, &sub);
32     } else static if(isAssociativeArray!T) {
33       DBusMessageIter sub;
34       const(char)* subSig = (typeSig!T())[1..$].toStringz(); // trim off "a" with slice syntax
35       dbus_message_iter_open_container(iter, 'a', subSig, &sub);
36       foreach(x; arg.byKeyValue()) {
37         DBusMessageIter subsub;
38         dbus_message_iter_open_container(sub, 'e', null, &subsub);
39         buildIter(&subsub, x.key, x.value);
40         dbus_message_iter_close_container(sub, &subsub);
41       }
42       dbus_message_iter_close_container(iter, &sub);
43     } else static if(basicDBus!T) {
44       dbus_message_iter_append_basic(iter,typeCode!T,&arg);
45     }
46   }
47 }
48 
49 T readIter(T)(DBusMessageIter *iter) if (canDBus!T) {
50   T ret;
51   assert(dbus_message_iter_get_arg_type(iter) == typeCode!T());
52   static if(is(T==string)) {
53     const(char)* cStr;
54     dbus_message_iter_get_basic(iter, &cStr);
55     ret = cStr.fromStringz().idup; // copy string
56   } else static if(is(T==bool)) {
57     dbus_bool_t longerBool;
58     dbus_message_iter_get_basic(iter, &longerBool);
59     ret = cast(bool)longerBool;
60   } else static if(isTuple!T) {
61     DBusMessageIter sub;
62     dbus_message_iter_recurse(iter, &sub);
63     readIterTuple!T(&sub, ret);
64   } else static if(is(T t : U[], U)) {
65     assert(dbus_message_iter_get_element_type(iter) == typeCode!U);
66     DBusMessageIter sub;
67     dbus_message_iter_recurse(iter, &sub);
68     while(dbus_message_iter_get_arg_type(&sub) != 0) {
69       ret ~= readIter!U(&sub);
70     }
71   } else static if(isAssociativeArray!T) {
72     assert(dbus_message_iter_get_element_type(iter) == 'e');
73     DBusMessageIter sub;
74     dbus_message_iter_recurse(iter, &sub);
75     while(dbus_message_iter_get_arg_type(&sub) != 0) {
76       DBusMessageIter subsub;
77       dbus_message_iter_recurse(sub, &subsub);
78       ret[readIter!(KeyType!T)(subsub)] = readIter!(ValueType!T)(subsub);
79     }
80   } else static if(basicDBus!T) {
81     dbus_message_iter_get_basic(iter, &ret);
82   }
83   dbus_message_iter_next(iter);
84   return ret;
85 }
86 
87 void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && allCanDBus!(Tup.Types)) {
88   foreach(index, T; Tup.Types) {
89     tuple[index] = readIter!T(iter);
90   }
91 }
92 
93 unittest {
94   import dunit.toolkit;
95   import ddbus.thin;
96   Message msg = Message("org.example.wow","/wut","org.test.iface","meth");
97   bool[] emptyB;
98   auto args = tuple(5,true,"wow",[6,5],tuple(6.2,4,[["lol"]],emptyB));
99   msg.build(args.expand);
100   msg.signature().assertEqual("ibsai(diaasab)");
101   msg.readTuple!(typeof(args))().assertEqual(args);
102   DBusMessageIter iter;
103   dbus_message_iter_init(msg.msg, &iter);
104   readIter!int(&iter).assertEqual(5);
105   readIter!bool(&iter).assertEqual(true);
106   readIter!string(&iter).assertEqual("wow");
107   readIter!(int[])(&iter).assertEqual([6,5]);
108   readIter!(Tuple!(double,int,string[][],bool[]))(&iter).assertEqual(tuple(6.2,4,[["lol"]],emptyB));
109 }