From 4017e95abaeb46c30d211748d40aade1cd577df0 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sat, 22 Apr 2017 23:05:55 +0200 Subject: [PATCH] Support for maps/dictionaries --- source/ddbus/conv.d | 30 ++++++++++++++++++++++++++++-- source/ddbus/simple.d | 4 ++-- source/ddbus/util.d | 26 ++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 6 deletions(-) diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index c582d15..8bc6861 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -5,6 +5,7 @@ import ddbus.util; import std.string; import std.typecons; import std.range; +import std.traits; void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { foreach(index, arg; args) { @@ -28,12 +29,20 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { buildIter(&sub, x); } dbus_message_iter_close_container(iter, &sub); + } else static if(isAssociativeArray!T) { + buildIter(iter, arg.byDictionaryEntries); } else static if(isVariant!T) { DBusMessageIter sub; const(char)* subSig = typeSig!(VariantType!T).toStringz(); 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); } @@ -53,6 +62,8 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { } static if(isTuple!T) { assert(dbus_message_iter_get_arg_type(iter) == 'r'); + } else static if(is(T == DictionaryEntry!(K1, V1), K1, V1)) { + assert(dbus_message_iter_get_arg_type(iter) == 'e'); } else { assert(dbus_message_iter_get_arg_type(iter) == typeCode!T()); } @@ -68,6 +79,11 @@ 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!K(&sub); } else static if(is(T t : U[], U)) { assert(dbus_message_iter_get_element_type(iter) == typeCode!U); DBusMessageIter sub; @@ -79,6 +95,13 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); ret.data = readIter!(VariantType!T)(&sub); + } else static if(isAssociativeArray!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; + } } else static if(basicDBus!T) { dbus_message_iter_get_basic(iter, &ret); } @@ -98,9 +121,11 @@ unittest { Variant!T var(T)(T data){ return Variant!T(data); } Message msg = Message("org.example.wow","/wut","org.test.iface","meth"); bool[] emptyB; - auto args = tuple(5,true,"wow",var(5.9),[6,5],tuple(6.2,4,[["lol"]],emptyB,var([4,2]))); + string[string] map; + map["hello"] = "world"; + auto args = tuple(5,true,"wow",var(5.9),[6,5],tuple(6.2,4,[["lol"]],emptyB,var([4,2])),map); msg.build(args.expand); - msg.signature().assertEqual("ibsvai(diaasabv)"); + msg.signature().assertEqual("ibsvai(diaasabv)a{ss}"); msg.readTuple!(typeof(args))().assertEqual(args); DBusMessageIter iter; dbus_message_iter_init(msg.msg, &iter); @@ -110,4 +135,5 @@ 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]))); + readIter!(string[string])(&iter).assertEqual(["hello": "world"]); } diff --git a/source/ddbus/simple.d b/source/ddbus/simple.d index 1532667..b58b925 100644 --- a/source/ddbus/simple.d +++ b/source/ddbus/simple.d @@ -71,7 +71,7 @@ void registerMethods(T : Object)(MessageRouter router, string path, string iface unittest { import dunit.toolkit; class Tester { - int lol(int x, string s) {return 5;} + int lol(int x, string s, string[string] map) {return 5;} void wat() {} } auto o = new Tester; @@ -82,6 +82,6 @@ unittest { patt.method = "lol"; router.callTable.assertHasKey(patt); auto res = router.callTable[patt]; - res.argSig.assertEqual(["i","s"]); + res.argSig.assertEqual(["i","s", "a{ss}"]); res.retSig.assertEqual(["i"]); } diff --git a/source/ddbus/util.d b/source/ddbus/util.d index c2b0065..ccc33ed 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -5,6 +5,17 @@ import std.typecons; import std.range; import std.traits; +struct DictionaryEntry(K, V) { + K key; + V value; +} + +auto byDictionaryEntries(K, V)(V[K] aa) { + import std.algorithm : map; + + return aa.byKeyValue.map!(pair => DictionaryEntry!(K, V)(pair.key, pair.value)); +} + template isVariant(T) { static if(isBasicType!T || isInputRange!T) { enum isVariant = false; @@ -49,6 +60,10 @@ template canDBus(T) { enum canDBus = allCanDBus!(T.Types); } else static if(isInputRange!T) { 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; } else { enum canDBus = false; } @@ -59,8 +74,8 @@ unittest { (canDBus!(int[])).assertTrue(); (allCanDBus!(int,string,bool)).assertTrue(); (canDBus!(Tuple!(int[],bool,Variant!short))).assertTrue(); - (canDBus!(Tuple!(int[],int[string]))).assertFalse(); - (canDBus!(int[string])).assertFalse(); + (canDBus!(Tuple!(int[],int[string]))).assertTrue(); + (canDBus!(int[string])).assertTrue(); } string typeSig(T)() if(canDBus!T) { @@ -93,8 +108,12 @@ 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) { + return "a{" ~ typeSig!(KeyType!T) ~ typeSig!(ValueType!T) ~ "}"; } } @@ -133,6 +152,9 @@ unittest { typeSig!(int[]).assertEqual("ai"); typeSig!(Variant!int[]).assertEqual("av"); typeSig!(Tuple!(byte)[][]).assertEqual("aa(y)"); + // dictionaries + typeSig!(int[string]).assertEqual("a{si}"); + typeSig!(DictionaryEntry!(string, int)).assertEqual("{si}"); // multiple arguments typeSigAll!(int,bool).assertEqual("ib"); // type codes