1 module ddbus.conv; 2 3 import ddbus.c_lib; 4 import ddbus.util; 5 import ddbus.thin; 6 import std.string; 7 import std.typecons; 8 import std.range; 9 import std.traits; 10 11 void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { 12 foreach(index, arg; args) { 13 alias TS[index] T; 14 static if(is(T == string)) { 15 immutable(char)* cStr = arg.toStringz(); 16 dbus_message_iter_append_basic(iter,typeCode!T,&cStr); 17 } else static if(is(T==bool)) { 18 dbus_bool_t longerBool = arg; // dbus bools are ints 19 dbus_message_iter_append_basic(iter,typeCode!T,&longerBool); 20 } else static if(isTuple!T) { 21 DBusMessageIter sub; 22 dbus_message_iter_open_container(iter, 'r', null, &sub); 23 buildIter(&sub, arg.expand); 24 dbus_message_iter_close_container(iter, &sub); 25 } else static if(isInputRange!T) { 26 DBusMessageIter sub; 27 const(char)* subSig = (typeSig!(ElementType!T)()).toStringz(); 28 dbus_message_iter_open_container(iter, 'a', subSig, &sub); 29 foreach(x; arg) { 30 buildIter(&sub, x); 31 } 32 dbus_message_iter_close_container(iter, &sub); 33 } else static if(isAssociativeArray!T) { 34 buildIter(iter, arg.byDictionaryEntries); 35 } else static if(is(T == DBusAny) || is(T == Variant!DBusAny)) { 36 static if(is(T == Variant!DBusAny)) { 37 auto val = arg.data; 38 val.explicitVariant = true; 39 } else { 40 auto val = arg; 41 } 42 DBusMessageIter subStore; 43 DBusMessageIter* sub = &subStore; 44 char[] sig = [cast(char) val.type]; 45 if(val.type == 'a') 46 sig ~= val.signature; 47 else if(val.type == 'r') 48 sig = val.signature; 49 sig ~= '\0'; 50 if (!val.explicitVariant) 51 sub = iter; 52 else 53 dbus_message_iter_open_container(iter, 'v', sig.ptr, sub); 54 if(val.type == 's') { 55 buildIter(sub, val.str); 56 } else if(val.type == 'b') { 57 buildIter(sub,val.boolean); 58 } else if(dbus_type_is_basic(val.type)) { 59 dbus_message_iter_append_basic(sub,val.type,&val.int64); 60 } else if(val.type == 'a') { 61 DBusMessageIter arr; 62 dbus_message_iter_open_container(sub, 'a', sig[1 .. $].ptr, &arr); 63 if (val.signature == ['y']) 64 foreach (item; val.binaryData) 65 dbus_message_iter_append_basic(&arr, 'y', &item); 66 else 67 foreach(item; val.array) 68 buildIter(&arr, item); 69 dbus_message_iter_close_container(sub, &arr); 70 } else if(val.type == 'r') { 71 DBusMessageIter arr; 72 dbus_message_iter_open_container(sub, 'r', null, &arr); 73 foreach(item; val.tuple) 74 buildIter(&arr, item); 75 dbus_message_iter_close_container(sub, &arr); 76 } else if(val.type == 'e') { 77 DBusMessageIter entry; 78 dbus_message_iter_open_container(sub, 'e', null, &entry); 79 buildIter(&entry, val.entry.key); 80 buildIter(&entry, val.entry.value); 81 dbus_message_iter_close_container(sub, &entry); 82 } 83 if(val.explicitVariant) 84 dbus_message_iter_close_container(iter, sub); 85 } else static if(isVariant!T) { 86 DBusMessageIter sub; 87 const(char)* subSig = typeSig!(VariantType!T).toStringz(); 88 dbus_message_iter_open_container(iter, 'v', subSig, &sub); 89 buildIter(&sub, arg.data); 90 dbus_message_iter_close_container(iter, &sub); 91 } else static if(is(T == DictionaryEntry!(K, V), K, V)) { 92 DBusMessageIter sub; 93 dbus_message_iter_open_container(iter, 'e', null, &sub); 94 buildIter(&sub, arg.key); 95 buildIter(&sub, arg.value); 96 dbus_message_iter_close_container(iter, &sub); 97 } else static if(basicDBus!T) { 98 dbus_message_iter_append_basic(iter,typeCode!T,&arg); 99 } 100 } 101 } 102 103 T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { 104 T ret; 105 static if(!isVariant!T || is(T == Variant!DBusAny)) { 106 if(dbus_message_iter_get_arg_type(iter) == 'v') { 107 DBusMessageIter sub; 108 dbus_message_iter_recurse(iter, &sub); 109 static if(is(T == Variant!DBusAny)) { 110 ret = variant(readIter!DBusAny(&sub)); 111 } else { 112 ret = readIter!T(&sub); 113 static if(is(T == DBusAny)) 114 ret.explicitVariant = true; 115 } 116 dbus_message_iter_next(iter); 117 return ret; 118 } 119 } 120 static if(isTuple!T) { 121 assert(dbus_message_iter_get_arg_type(iter) == 'r'); 122 } else static if(is(T == DictionaryEntry!(K1, V1), K1, V1)) { 123 assert(dbus_message_iter_get_arg_type(iter) == 'e'); 124 } else static if(!is(T == DBusAny) && !is(T == Variant!DBusAny)) { 125 assert(dbus_message_iter_get_arg_type(iter) == typeCode!T()); 126 } 127 static if(is(T==string)) { 128 const(char)* cStr; 129 dbus_message_iter_get_basic(iter, &cStr); 130 ret = cStr.fromStringz().idup; // copy string 131 } else static if(is(T==bool)) { 132 dbus_bool_t longerBool; 133 dbus_message_iter_get_basic(iter, &longerBool); 134 ret = cast(bool)longerBool; 135 } else static if(isTuple!T) { 136 DBusMessageIter sub; 137 dbus_message_iter_recurse(iter, &sub); 138 readIterTuple!T(&sub, ret); 139 } else static if(is(T == DictionaryEntry!(K, V), K, V)) { 140 DBusMessageIter sub; 141 dbus_message_iter_recurse(iter, &sub); 142 ret.key = readIter!K(&sub); 143 ret.value = readIter!V(&sub); 144 } else static if(is(T t : U[], U)) { 145 assert(dbus_message_iter_get_element_type(iter) == typeCode!U); 146 DBusMessageIter sub; 147 dbus_message_iter_recurse(iter, &sub); 148 while(dbus_message_iter_get_arg_type(&sub) != 0) { 149 ret ~= readIter!U(&sub); 150 } 151 } else static if(isVariant!T) { 152 DBusMessageIter sub; 153 dbus_message_iter_recurse(iter, &sub); 154 ret.data = readIter!(VariantType!T)(&sub); 155 } else static if(isAssociativeArray!T) { 156 DBusMessageIter sub; 157 dbus_message_iter_recurse(iter, &sub); 158 while(dbus_message_iter_get_arg_type(&sub) != 0) { 159 auto entry = readIter!(DictionaryEntry!(KeyType!T, ValueType!T))(&sub); 160 ret[entry.key] = entry.value; 161 } 162 } else static if(is(T == DBusAny)) { 163 ret.type = dbus_message_iter_get_arg_type(iter); 164 ret.explicitVariant = false; 165 if(ret.type == 's') { 166 ret.str = readIter!string(iter); 167 return ret; 168 } else if(ret.type == 'b') { 169 ret.boolean = readIter!bool(iter); 170 return ret; 171 } else if(dbus_type_is_basic(ret.type)) { 172 dbus_message_iter_get_basic(iter, &ret.int64); 173 } else if(ret.type == 'a') { 174 DBusMessageIter sub; 175 dbus_message_iter_recurse(iter, &sub); 176 auto sig = dbus_message_iter_get_signature(&sub); 177 ret.signature = sig.fromStringz.dup; 178 dbus_free(sig); 179 if (ret.signature == ['y']) 180 while(dbus_message_iter_get_arg_type(&sub) != 0) { 181 ubyte b; 182 assert(dbus_message_iter_get_arg_type(&sub) == 'y'); 183 dbus_message_iter_get_basic(&sub, &b); 184 dbus_message_iter_next(&sub); 185 ret.binaryData ~= b; 186 } 187 else 188 while(dbus_message_iter_get_arg_type(&sub) != 0) { 189 ret.array ~= readIter!DBusAny(&sub); 190 } 191 } else if(ret.type == 'r') { 192 auto sig = dbus_message_iter_get_signature(iter); 193 ret.signature = sig.fromStringz.dup; 194 dbus_free(sig); 195 DBusMessageIter sub; 196 dbus_message_iter_recurse(iter, &sub); 197 while(dbus_message_iter_get_arg_type(&sub) != 0) { 198 ret.tuple ~= readIter!DBusAny(&sub); 199 } 200 } else if(ret.type == 'e') { 201 DBusMessageIter sub; 202 dbus_message_iter_recurse(iter, &sub); 203 ret.entry = new DictionaryEntry!(DBusAny, DBusAny); 204 ret.entry.key = readIter!DBusAny(&sub); 205 ret.entry.value = readIter!DBusAny(&sub); 206 } 207 } else static if(basicDBus!T) { 208 dbus_message_iter_get_basic(iter, &ret); 209 } 210 dbus_message_iter_next(iter); 211 return ret; 212 } 213 214 void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && allCanDBus!(Tup.Types)) { 215 foreach(index, T; Tup.Types) { 216 tuple[index] = readIter!T(iter); 217 } 218 } 219 220 unittest { 221 import dunit.toolkit; 222 import ddbus.thin; 223 Variant!T var(T)(T data){ return Variant!T(data); } 224 Message msg = Message("org.example.wow","/wut","org.test.iface","meth"); 225 bool[] emptyB; 226 string[string] map; 227 map["hello"] = "world"; 228 DBusAny anyVar = DBusAny(cast(ulong) 1561); 229 anyVar.type.assertEqual('t'); 230 anyVar.uint64.assertEqual(1561); 231 anyVar.explicitVariant.assertEqual(false); 232 auto tupleMember = DBusAny(tuple(Variant!int(45), Variant!ushort(5), 32, [1, 2], tuple(variant(4), 5), map)); 233 Variant!DBusAny complexVar = variant(DBusAny([ 234 "hello world": variant(DBusAny(1337)), 235 "array value": variant(DBusAny([42, 64])), 236 "tuple value": variant(tupleMember), 237 "optimized binary data": variant(DBusAny(cast(ubyte[]) [1, 2, 3, 4, 5, 6])) 238 ])); 239 complexVar.data.type.assertEqual('a'); 240 complexVar.data.signature.assertEqual("{sv}".dup); 241 tupleMember.signature.assertEqual("(vviai(vi)a{ss})"); 242 auto args = tuple(5,true,"wow",var(5.9),[6,5],tuple(6.2,4,[["lol"]],emptyB,var([4,2])),map,anyVar,complexVar); 243 msg.build(args.expand); 244 msg.signature().assertEqual("ibsvai(diaasabv)a{ss}tv"); 245 msg.readTuple!(typeof(args))().assertEqual(args); 246 DBusMessageIter iter; 247 dbus_message_iter_init(msg.msg, &iter); 248 readIter!int(&iter).assertEqual(5); 249 readIter!bool(&iter).assertEqual(true); 250 readIter!string(&iter).assertEqual("wow"); 251 readIter!double(&iter).assertEqual(5.9); 252 readIter!(int[])(&iter).assertEqual([6,5]); 253 readIter!(Tuple!(double,int,string[][],bool[],Variant!(int[])))(&iter).assertEqual(tuple(6.2,4,[["lol"]],emptyB,var([4,2]))); 254 readIter!(string[string])(&iter).assertEqual(["hello": "world"]); 255 readIter!DBusAny(&iter).assertEqual(anyVar); 256 readIter!(Variant!DBusAny)(&iter).assertEqual(complexVar); 257 }