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 }