From a6aa85ac74a605465dbda0688e31e02bc6b7c394 Mon Sep 17 00:00:00 2001 From: "Harry T. Vennik" Date: Sun, 4 Jun 2017 17:43:19 +0200 Subject: [PATCH 1/3] Some dictionary related typesystem fixes - Keys in a dictionary are required to be basic types - A DictionaryEntry on it's own cannot be sent over DBus, it has to be wrapped in an array to form a dictionary. So, canDBus should be false for DictionaryEntry, but true for an array of DictionaryEntry. --- source/ddbus/util.d | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/ddbus/util.d b/source/ddbus/util.d index 6bdaa4f..ba9b77c 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -59,11 +59,13 @@ template canDBus(T) { } else static if(isTuple!T) { enum canDBus = allCanDBus!(T.Types); } else static if(isInputRange!T) { - enum canDBus = canDBus!(ElementType!T); + static if(is(ElementType!T == DictionaryEntry!(K, V), K, V)) { + enum canDBus = basicDBus!K && canDBus!V; + } else { + enum canDBus = canDBus!(ElementType!T); + } } else static if(isAssociativeArray!T) { - enum canDBus = canDBus!(KeyType!T) && canDBus!(ValueType!T); - } else static if(is(T == DictionaryEntry!(K, V), K, V)) { - enum canDBus = canDBus!K && canDBus!V; + enum canDBus = basicDBus!(KeyType!T) && canDBus!(ValueType!T); } else { enum canDBus = false; } @@ -163,7 +165,7 @@ unittest { typeSig!(Tuple!(byte)[][]).assertEqual("aa(y)"); // dictionaries typeSig!(int[string]).assertEqual("a{si}"); - typeSig!(DictionaryEntry!(string, int)).assertEqual("{si}"); + typeSig!(DictionaryEntry!(string, int)[]).assertEqual("a{si}"); // multiple arguments typeSigAll!(int,bool).assertEqual("ib"); // type codes From 3fa88ee9f7b4df25a00593c1ec16626c6e75b27f Mon Sep 17 00:00:00 2001 From: "Harry T. Vennik" Date: Sun, 18 Jun 2017 17:43:19 +0200 Subject: [PATCH 2/3] Fix various template instantiation errors Some templates broke because canDBus!(DictionaryEntry!(K,V)) now returns false. Also, associative arrays are now handled without using a DictionaryEntry type. This is a first step in eliminating DictionaryEntry. --- source/ddbus/conv.d | 58 ++++++++++++++++++++++++++++++++------------- source/ddbus/util.d | 13 ++++++++-- 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index 166a7db..40b8d46 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -27,11 +27,29 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { const(char)* subSig = (typeSig!(ElementType!T)()).toStringz(); dbus_message_iter_open_container(iter, 'a', subSig, &sub); foreach(x; arg) { - buildIter(&sub, x); + static if(isInstanceOf!(DictionaryEntry, typeof(x))) { + DBusMessageIter entry; + dbus_message_iter_open_container(&sub, 'e', null, &entry); + buildIter(&entry, x.key); + buildIter(&entry, x.value); + dbus_message_iter_close_container(&sub, &entry); + } else { + buildIter(&sub, x); + } } dbus_message_iter_close_container(iter, &sub); } else static if(isAssociativeArray!T) { - buildIter(iter, arg.byDictionaryEntries); + DBusMessageIter sub; + const(char)* subSig = typeSig!T[1..$].toStringz(); + dbus_message_iter_open_container(iter, 'a', subSig, &sub); + foreach(k, v; arg) { + DBusMessageIter entry; + dbus_message_iter_open_container(&sub, 'e', null, &entry); + buildIter(&entry, k); + buildIter(&entry, v); + dbus_message_iter_close_container(&sub, &entry); + } + dbus_message_iter_close_container(iter, &sub); } else static if(is(T == DBusAny) || is(T == Variant!DBusAny)) { static if(is(T == Variant!DBusAny)) { auto val = arg.data; @@ -88,12 +106,6 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { dbus_message_iter_open_container(iter, 'v', subSig, &sub); buildIter(&sub, arg.data); dbus_message_iter_close_container(iter, &sub); - } else static if(is(T == DictionaryEntry!(K, V), K, V)) { - DBusMessageIter sub; - dbus_message_iter_open_container(iter, 'e', null, &sub); - buildIter(&sub, arg.key); - buildIter(&sub, arg.value); - dbus_message_iter_close_container(iter, &sub); } else static if(basicDBus!T) { dbus_message_iter_append_basic(iter,typeCode!T,&arg); } @@ -136,17 +148,19 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); readIterTuple!T(&sub, ret); - } else static if(is(T == DictionaryEntry!(K, V), K, V)) { - DBusMessageIter sub; - dbus_message_iter_recurse(iter, &sub); - ret.key = readIter!K(&sub); - ret.value = readIter!V(&sub); } else static if(is(T t : U[], U)) { assert(dbus_message_iter_get_element_type(iter) == typeCode!U); DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); while(dbus_message_iter_get_arg_type(&sub) != 0) { - ret ~= readIter!U(&sub); + static if(is(U == DictionaryEntry!(K,V), K, V)) { + DBusMessageIter entry; + dbus_message_iter_recurse(&sub, &entry); + ret ~= U(readIter!K(&entry), readIter!V(&entry)); + dbus_message_iter_next(&sub); + } else { + ret ~= readIter!U(&sub); + } } } else static if(isVariant!T) { DBusMessageIter sub; @@ -156,8 +170,12 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); while(dbus_message_iter_get_arg_type(&sub) != 0) { - auto entry = readIter!(DictionaryEntry!(KeyType!T, ValueType!T))(&sub); - ret[entry.key] = entry.value; + DBusMessageIter entry; + dbus_message_iter_recurse(&sub, &entry); + auto k = readIter!(KeyType!T)(&entry); + auto v = readIter!(ValueType!T)(&entry); + ret[k] = v; + dbus_message_iter_next(&sub); } } else static if(is(T == DBusAny)) { ret.type = dbus_message_iter_get_arg_type(iter); @@ -251,7 +269,15 @@ unittest { readIter!double(&iter).assertEqual(5.9); readIter!(int[])(&iter).assertEqual([6,5]); readIter!(Tuple!(double,int,string[][],bool[],Variant!(int[])))(&iter).assertEqual(tuple(6.2,4,[["lol"]],emptyB,var([4,2]))); + + // There are two ways to read a dictionary, so duplicate the iterator to test both. + auto iter2 = iter; readIter!(string[string])(&iter).assertEqual(["hello": "world"]); + auto dict = readIter!(DictionaryEntry!(string,string)[])(&iter2); + dict.length.assertEqual(1); + dict[0].key.assertEqual("hello"); + dict[0].value.assertEqual("world"); + readIter!DBusAny(&iter).assertEqual(anyVar); readIter!(Variant!DBusAny)(&iter).assertEqual(complexVar); } diff --git a/source/ddbus/util.d b/source/ddbus/util.d index ba9b77c..f695016 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -112,8 +112,6 @@ string typeSig(T)() if(canDBus!T) { } sig ~= ")"; return sig; - } else static if(is(T == DictionaryEntry!(K, V), K, V)) { - return '{' ~ typeSig!K ~ typeSig!V ~ '}'; } else static if(isInputRange!T) { return "a" ~ typeSig!(ElementType!T)(); } else static if(isAssociativeArray!T) { @@ -121,6 +119,13 @@ string typeSig(T)() if(canDBus!T) { } } +string typeSig(T)() if(isInstanceOf!(DictionaryEntry, T)) { + static if(is(T == DictionaryEntry!(K, V), K, V)) // need to get K and V somehow + return "{" ~ typeSig!K ~ typeSig!V ~ '}'; + else + static assert (false, "DictionaryEntry always has a key type and value type, right?"); +} + string[] typeSigReturn(T)() if(canDBus!T) { static if(is(T == Tuple!TS, TS...)) return typeSigArr!TS; @@ -149,6 +154,10 @@ int typeCode(T)() if(canDBus!T) { return sig[0]; } +int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) { + return 'e'; +} + unittest { import dunit.toolkit; // basics From 111b5c5af3654c1222e554004ef9bf8af5b52870 Mon Sep 17 00:00:00 2001 From: "Harry T. Vennik" Date: Tue, 20 Jun 2017 21:23:53 +0200 Subject: [PATCH 3/3] Cleanup typeSig implementation for DictionaryEntry --- source/ddbus/util.d | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source/ddbus/util.d b/source/ddbus/util.d index f695016..64d533c 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -120,10 +120,9 @@ string typeSig(T)() if(canDBus!T) { } string typeSig(T)() if(isInstanceOf!(DictionaryEntry, T)) { - static if(is(T == DictionaryEntry!(K, V), K, V)) // need to get K and V somehow - return "{" ~ typeSig!K ~ typeSig!V ~ '}'; - else - static assert (false, "DictionaryEntry always has a key type and value type, right?"); + alias typeof(T.key) K; + alias typeof(T.value) V; + return "{" ~ typeSig!K ~ typeSig!V ~ '}'; } string[] typeSigReturn(T)() if(canDBus!T) {