Add support for enum types

This commit is contained in:
Harry T. Vennik 2017-07-17 20:04:51 +02:00
parent 547705ae11
commit 6dca60d5ea
3 changed files with 74 additions and 2 deletions

View file

@ -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();
}

View file

@ -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);
}
}

View file

@ -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))");