From 6dca60d5eaffff611a643e8f9ecb1172ae243ded Mon Sep 17 00:00:00 2001 From: "Harry T. Vennik" Date: Mon, 17 Jul 2017 20:04:51 +0200 Subject: [PATCH] Add support for enum types --- source/ddbus/conv.d | 40 ++++++++++++++++++++++++++++++++++++++-- source/ddbus/exception.d | 26 ++++++++++++++++++++++++++ source/ddbus/util.d | 10 ++++++++++ 3 files changed, 74 insertions(+), 2 deletions(-) diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index d75425e..85c5369 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -1,7 +1,7 @@ module ddbus.conv; import ddbus.c_lib; -import ddbus.exception : TypeMismatchException; +import ddbus.exception : InvalidValueException, TypeMismatchException; import ddbus.util; import ddbus.thin; import std.exception : enforce; @@ -119,8 +119,22 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { } } -T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { +T readIter(T)(DBusMessageIter *iter) if (is(T == enum)) { + import std.algorithm.searching : canFind; + + alias OriginalType!T B; + + B value = readIter!B(iter); + enforce( + only(EnumMembers!T).canFind(value), + new InvalidValueException(value, T.stringof) + ); + return cast(T) value; +} + +T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && canDBus!T) { T ret; + static if(!isVariant!T || is(T == Variant!DBusAny)) { if(dbus_message_iter_get_arg_type(iter) == 'v') { DBusMessageIter sub; @@ -237,6 +251,7 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { } else static if(basicDBus!T) { dbus_message_iter_get_basic(iter, &ret); } + dbus_message_iter_next(iter); return ret; } @@ -269,6 +284,7 @@ unittest { complexVar.data.type.assertEqual('a'); complexVar.data.signature.assertEqual("{sv}".dup); tupleMember.signature.assertEqual("(vviai(vi)a{ss})"); + auto args = tuple(5,true,"wow",var(5.9),[6,5],tuple(6.2,4,[["lol"]],emptyB,var([4,2])),map,anyVar,complexVar); msg.build(args.expand); msg.signature().assertEqual("ibsvai(diaasabv)a{ss}tv"); @@ -298,3 +314,23 @@ unittest { readIter!DBusAny(&iter).assertEqual(anyVar); readIter!(Variant!DBusAny)(&iter).assertEqual(complexVar); } + +unittest { + import dunit.toolkit; + import ddbus.thin; + + enum E : int { a, b, c } + enum F : uint { x = 1, y = 2, z = 4 } + + Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth2"); + msg.build(E.c, 4, 5u, 8u); + + DBusMessageIter iter, iter2; + dbus_message_iter_init(msg.msg, &iter); + + readIter!E(&iter).assertEqual(E.c); + readIter!E(&iter).assertThrow!InvalidValueException(); + + readIter!F(&iter).assertThrow!InvalidValueException(); + readIter!F(&iter).assertThrow!InvalidValueException(); +} diff --git a/source/ddbus/exception.d b/source/ddbus/exception.d index 7e80bc1..a5a840f 100644 --- a/source/ddbus/exception.d +++ b/source/ddbus/exception.d @@ -64,3 +64,29 @@ class TypeMismatchException : Exception { int _expectedType; int _actualType; } + +/++ + Thrown during type conversion between DBus types and D types when a value is + encountered that can not be represented in the target type. + + This exception should not normally be thrown except when dealing with D types + that have a constrained value set, such as Enums. ++/ +class InvalidValueException : Exception { + package this(Source)( + Source value, + string targetType, + string file = __FILE__, + size_t line = __LINE__, + Throwable next = null + ) { + import std.conv : to; + + static if(__traits(compiles, value.to!string)) + string valueString = value.to!string; + else + string valueString = "(unprintable)"; + + super("Value " ~ valueString ~ " cannot be represented in type " ~ targetType); + } +} diff --git a/source/ddbus/util.d b/source/ddbus/util.d index 2754063..320a55c 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -47,6 +47,8 @@ template basicDBus(T) { || is (T == double) || is (T == string) || is(T == bool) || is (T == ObjectPath)) { enum basicDBus = true; + } else static if(is(T B == enum)) { + enum basicDBus = basicDBus!B; } else { enum basicDBus = false; } @@ -71,6 +73,7 @@ template canDBus(T) { enum canDBus = false; } } + unittest { import dunit.toolkit; (canDBus!int).assertTrue(); @@ -106,6 +109,8 @@ string typeSig(T)() if(canDBus!T) { return "o"; } else static if(isVariant!T) { return "v"; + } else static if(is(T B == enum)) { + return typeSig!B; } else static if(is(T == DBusAny)) { static assert(false, "Cannot determine type signature of DBusAny. Change to Variant!DBusAny if a variant was desired."); } else static if(isTuple!T) { @@ -169,6 +174,11 @@ unittest { typeSig!bool().assertEqual("b"); typeSig!string().assertEqual("s"); typeSig!(Variant!int)().assertEqual("v"); + // enums + enum E : byte { a, b, c } + typeSig!E().assertEqual(typeSig!byte()); + enum U : string { One = "One", Two = "Two" } + typeSig!U().assertEqual(typeSig!string()); // structs typeSig!(Tuple!(int,string,string)).assertEqual("(iss)"); typeSig!(Tuple!(int,string,Variant!int,Tuple!(int,"k",double,"x"))).assertEqual("(isv(id))");