From 6bce6cf6490ce819f048b7ea8f1458ec66fbf1c8 Mon Sep 17 00:00:00 2001 From: "Harry T. Vennik" Date: Thu, 20 Jul 2017 16:55:20 +0200 Subject: [PATCH] Added support for POD structs Note: structs are deliberately considered last, because other stuff may be implemented as structs as well. So we need to take care of special cases before trying struct (de)serialization. --- source/ddbus/conv.d | 35 +++++++++++++++++++++++++++++++++++ source/ddbus/util.d | 22 +++++++++++++++++----- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index a8d4c19..d4a74cd 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -113,6 +113,11 @@ 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 == struct)) { + DBusMessageIter sub; + dbus_message_iter_open_container(iter, 'r', null, &sub); + buildIter(&sub, arg.tupleof); + dbus_message_iter_close_container(iter, &sub); } else static if(basicDBus!T) { dbus_message_iter_append_basic(iter,typeCode!T,&arg); } @@ -265,6 +270,10 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla ret.entry.key = readIter!DBusAny(&sub); ret.entry.value = readIter!DBusAny(&sub); } + } else static if(is(T == struct)) { + DBusMessageIter sub; + dbus_message_iter_recurse(iter, &sub); + readIterStruct!T(&sub, ret); } else static if(basicDBus!T) { dbus_message_iter_get_basic(iter, &ret); } @@ -279,6 +288,13 @@ void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && } } +void readIterStruct(S)(DBusMessageIter *iter, ref S s) if(is(S == struct) && allCanDBus!(Fields!S)) { + alias FieldNameTuple!S names; + foreach(index, T; Fields!S) { + __traits(getMember, s, names[index]) = readIter!T(iter); + } +} + unittest { import dunit.toolkit; import ddbus.thin; @@ -355,3 +371,22 @@ unittest { readIter!F(&iter).assertThrow!InvalidValueException(); readIter!(BitFlags!F)(&iter2).assertThrow!InvalidValueException(); } + +unittest { + import dunit.toolkit; + import ddbus.thin; + + struct S1 { int a; double b; string s; } + struct S2 { Variant!int c; string d; S1 e; uint f; } + + Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth3"); + + enum testStruct = S2(variant(5), "blah", S1(-7, 63.5, "test"), 16); + msg.build(testStruct); + + DBusMessageIter iter; + dbus_message_iter_init(msg.msg, &iter); + + readIter!S2(&iter).assertEqual(testStruct); +} + diff --git a/source/ddbus/util.d b/source/ddbus/util.d index 968e89a..960624d 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -72,6 +72,8 @@ template canDBus(T) { } } else static if(isAssociativeArray!T) { enum canDBus = basicDBus!(KeyType!T) && canDBus!(ValueType!T); + } else static if(is(T == struct) && !isInstanceOf!(DictionaryEntry, T)) { + enum canDBus = allCanDBus!(Fields!T); } else { enum canDBus = false; } @@ -130,6 +132,13 @@ string typeSig(T)() if(canDBus!T) { return "a" ~ typeSig!(ElementType!T)(); } else static if(isAssociativeArray!T) { return "a{" ~ typeSig!(KeyType!T) ~ typeSig!(ValueType!T) ~ "}"; + } else static if(is(T == struct)) { + string sig = "("; + foreach(i, S; Fields!T) { + sig ~= typeSig!S(); + } + sig ~= ")"; + return sig; } } @@ -163,10 +172,8 @@ string[] typeSigArr(TS...)() if(allCanDBus!TS) { } int typeCode(T)() if(canDBus!T) { - static if (isTuple!T) - return 'r'; - else - return typeSig!T()[0]; + int code = typeSig!T()[0]; + return (code != '(') ? code : 'r'; } int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) { @@ -188,9 +195,14 @@ unittest { // bit flags enum F : uint { a = 1, b = 2, c = 4 } typeSig!(BitFlags!F)().assertEqual(typeSig!uint()); - // structs + // tuples (represented as structs in DBus) typeSig!(Tuple!(int,string,string)).assertEqual("(iss)"); typeSig!(Tuple!(int,string,Variant!int,Tuple!(int,"k",double,"x"))).assertEqual("(isv(id))"); + // structs + struct S1 { int a; double b; string s; } + typeSig!S1.assertEqual("(ids)"); + struct S2 { Variant!int c; string d; S1 e; uint f; } + typeSig!S2.assertEqual("(vs(ids)u)"); // arrays typeSig!(int[]).assertEqual("ai"); typeSig!(Variant!int[]).assertEqual("av");