From 98bc5bddc18c5414581269964aa7a5e5af1902bd Mon Sep 17 00:00:00 2001 From: xentec Date: Thu, 31 Dec 2015 00:40:42 +0100 Subject: [PATCH] Added basic variant type support This also enables reading properties of DBus interfaces. --- Readme.md | 15 +++++++++++++++ source/ddbus/conv.d | 27 ++++++++++++++++++++++++--- source/ddbus/thin.d | 8 ++++++++ source/ddbus/util.d | 30 ++++++++++++++++++++++++++---- 4 files changed, 73 insertions(+), 7 deletions(-) diff --git a/Readme.md b/Readme.md index 52a7189..bc7c86e 100644 --- a/Readme.md +++ b/Readme.md @@ -42,6 +42,21 @@ auto name = obj.GetNameOwner("org.freedesktop.DBus").to!string(); obj.call!string("GetNameOwner","org.freedesktop.DBus"); ``` +### Working with properties + +```d +import ddbus; +Connection conn = connectToBus(); +PathIface obj = new PathIface(conn, "org.freedesktop.secrets", "/org/freedesktop/secrets/collection/login", "org.freedesktop.DBus.Properties"); + +// read property +string loginLabel = obj.Get("org.freedesktop.Secret.Collection", "Label").to!string(); +loginLabel = "Secret"~login; +// write it back (variant type requires variant() wrapper) +obj.Set("org.freedesktop.Secret.Collection", "Label", variant(loginLabel)); +``` +Setting read only properties results in a thrown `DBusException`. + ## Server Interface You can register a delegate into a `MessageRouter` and a main loop in order to handle messages. diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index 80893ad..c582d15 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -28,6 +28,12 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { buildIter(&sub, x); } dbus_message_iter_close_container(iter, &sub); + } 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(basicDBus!T) { dbus_message_iter_append_basic(iter,typeCode!T,&arg); } @@ -36,6 +42,15 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { T ret; + static if(!isVariant!T) { + if(dbus_message_iter_get_arg_type(iter) == 'v') { + DBusMessageIter sub; + dbus_message_iter_recurse(iter, &sub); + ret = readIter!T(&sub); + dbus_message_iter_next(iter); + return ret; + } + } static if(isTuple!T) { assert(dbus_message_iter_get_arg_type(iter) == 'r'); } else { @@ -60,6 +75,10 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { while(dbus_message_iter_get_arg_type(&sub) != 0) { ret ~= readIter!U(&sub); } + } else static if(isVariant!T) { + DBusMessageIter sub; + dbus_message_iter_recurse(iter, &sub); + ret.data = readIter!(VariantType!T)(&sub); } else static if(basicDBus!T) { dbus_message_iter_get_basic(iter, &ret); } @@ -76,17 +95,19 @@ void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && unittest { import dunit.toolkit; import ddbus.thin; + 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",[6,5],tuple(6.2,4,[["lol"]],emptyB)); + auto args = tuple(5,true,"wow",var(5.9),[6,5],tuple(6.2,4,[["lol"]],emptyB,var([4,2]))); msg.build(args.expand); - msg.signature().assertEqual("ibsai(diaasab)"); + msg.signature().assertEqual("ibsvai(diaasabv)"); msg.readTuple!(typeof(args))().assertEqual(args); DBusMessageIter iter; dbus_message_iter_init(msg.msg, &iter); readIter!int(&iter).assertEqual(5); readIter!bool(&iter).assertEqual(true); readIter!string(&iter).assertEqual("wow"); + readIter!double(&iter).assertEqual(5.9); readIter!(int[])(&iter).assertEqual([6,5]); - readIter!(Tuple!(double,int,string[][],bool[]))(&iter).assertEqual(tuple(6.2,4,[["lol"]],emptyB)); + readIter!(Tuple!(double,int,string[][],bool[],Variant!(int[])))(&iter).assertEqual(tuple(6.2,4,[["lol"]],emptyB,var([4,2]))); } diff --git a/source/ddbus/thin.d b/source/ddbus/thin.d index 545f6fe..8f421e2 100644 --- a/source/ddbus/thin.d +++ b/source/ddbus/thin.d @@ -26,6 +26,14 @@ T wrapErrors(T)(T delegate(DBusError *err) del) { return ret; } +struct Variant(T) { + T data; +} + +Variant!T variant(T)(T data) { + return Variant!T(data); +} + enum MessageType { Invalid = 0, Call, Return, Error, Signal diff --git a/source/ddbus/util.d b/source/ddbus/util.d index 1161b3f..c2b0065 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -1,6 +1,24 @@ module ddbus.util; + +import ddbus.thin; import std.typecons; import std.range; +import std.traits; + +template isVariant(T) { + static if(isBasicType!T || isInputRange!T) { + enum isVariant = false; + } else static if(__traits(compiles, TemplateOf!T) + && __traits(isSame, TemplateOf!T, Variant)) { + enum isVariant = true; + } else { + enum isVariant = false; + } +} + +template VariantType(T) { + alias VariantType = TemplateArgsOf!(T)[0]; +} template allCanDBus(TS...) { static if (TS.length == 0) { @@ -25,6 +43,8 @@ template basicDBus(T) { template canDBus(T) { static if(basicDBus!T) { enum canDBus = true; + } else static if(isVariant!T) { + enum canDBus = canDBus!(VariantType!T); } else static if(isTuple!T) { enum canDBus = allCanDBus!(T.Types); } else static if(isInputRange!T) { @@ -38,7 +58,7 @@ unittest { (canDBus!int).assertTrue(); (canDBus!(int[])).assertTrue(); (allCanDBus!(int,string,bool)).assertTrue(); - (canDBus!(Tuple!(int[],bool))).assertTrue(); + (canDBus!(Tuple!(int[],bool,Variant!short))).assertTrue(); (canDBus!(Tuple!(int[],int[string]))).assertFalse(); (canDBus!(int[string])).assertFalse(); } @@ -64,8 +84,8 @@ string typeSig(T)() if(canDBus!T) { return "d"; } else static if(is(T == string)) { return "s"; - } else static if(is(T == void)) { - return ""; + } else static if(isVariant!T) { + return "v"; } else static if(isTuple!T) { string sig = "("; foreach(i, S; T.Types) { @@ -105,11 +125,13 @@ unittest { typeSig!int().assertEqual("i"); typeSig!bool().assertEqual("b"); typeSig!string().assertEqual("s"); + typeSig!(Variant!int)().assertEqual("v"); // structs typeSig!(Tuple!(int,string,string)).assertEqual("(iss)"); - typeSig!(Tuple!(int,string,Tuple!(int,"k",double,"x"))).assertEqual("(is(id))"); + typeSig!(Tuple!(int,string,Variant!int,Tuple!(int,"k",double,"x"))).assertEqual("(isv(id))"); // arrays typeSig!(int[]).assertEqual("ai"); + typeSig!(Variant!int[]).assertEqual("av"); typeSig!(Tuple!(byte)[][]).assertEqual("aa(y)"); // multiple arguments typeSigAll!(int,bool).assertEqual("ib");