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.
This commit is contained in:
Harry T. Vennik 2017-07-20 16:55:20 +02:00
parent 15ae9fec23
commit 6bce6cf649
2 changed files with 52 additions and 5 deletions

View file

@ -113,6 +113,11 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
dbus_message_iter_open_container(iter, 'v', subSig, &sub); dbus_message_iter_open_container(iter, 'v', subSig, &sub);
buildIter(&sub, arg.data); buildIter(&sub, arg.data);
dbus_message_iter_close_container(iter, &sub); 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) { } else static if(basicDBus!T) {
dbus_message_iter_append_basic(iter,typeCode!T,&arg); 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.key = readIter!DBusAny(&sub);
ret.entry.value = 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) { } else static if(basicDBus!T) {
dbus_message_iter_get_basic(iter, &ret); 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 { unittest {
import dunit.toolkit; import dunit.toolkit;
import ddbus.thin; import ddbus.thin;
@ -355,3 +371,22 @@ unittest {
readIter!F(&iter).assertThrow!InvalidValueException(); readIter!F(&iter).assertThrow!InvalidValueException();
readIter!(BitFlags!F)(&iter2).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);
}

View file

@ -72,6 +72,8 @@ template canDBus(T) {
} }
} else static if(isAssociativeArray!T) { } else static if(isAssociativeArray!T) {
enum canDBus = basicDBus!(KeyType!T) && canDBus!(ValueType!T); enum canDBus = basicDBus!(KeyType!T) && canDBus!(ValueType!T);
} else static if(is(T == struct) && !isInstanceOf!(DictionaryEntry, T)) {
enum canDBus = allCanDBus!(Fields!T);
} else { } else {
enum canDBus = false; enum canDBus = false;
} }
@ -130,6 +132,13 @@ string typeSig(T)() if(canDBus!T) {
return "a" ~ typeSig!(ElementType!T)(); return "a" ~ typeSig!(ElementType!T)();
} else static if(isAssociativeArray!T) { } else static if(isAssociativeArray!T) {
return "a{" ~ typeSig!(KeyType!T) ~ typeSig!(ValueType!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) { int typeCode(T)() if(canDBus!T) {
static if (isTuple!T) int code = typeSig!T()[0];
return 'r'; return (code != '(') ? code : 'r';
else
return typeSig!T()[0];
} }
int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) { int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) {
@ -188,9 +195,14 @@ unittest {
// bit flags // bit flags
enum F : uint { a = 1, b = 2, c = 4 } enum F : uint { a = 1, b = 2, c = 4 }
typeSig!(BitFlags!F)().assertEqual(typeSig!uint()); typeSig!(BitFlags!F)().assertEqual(typeSig!uint());
// structs // tuples (represented as structs in DBus)
typeSig!(Tuple!(int,string,string)).assertEqual("(iss)"); typeSig!(Tuple!(int,string,string)).assertEqual("(iss)");
typeSig!(Tuple!(int,string,Variant!int,Tuple!(int,"k",double,"x"))).assertEqual("(isv(id))"); 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 // arrays
typeSig!(int[]).assertEqual("ai"); typeSig!(int[]).assertEqual("ai");
typeSig!(Variant!int[]).assertEqual("av"); typeSig!(Variant!int[]).assertEqual("av");