Added support for Phobos-style variants
Only variants that are limited to contain types supported by ddbus are allowed.
This commit is contained in:
parent
da536be3d1
commit
e6d03252d2
|
@ -10,6 +10,7 @@ import std.string;
|
||||||
import std.typecons;
|
import std.typecons;
|
||||||
import std.range;
|
import std.range;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
import std.variant : VariantN;
|
||||||
|
|
||||||
void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
||||||
foreach(index, arg; args) {
|
foreach(index, arg; args) {
|
||||||
|
@ -56,6 +57,19 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
||||||
dbus_message_iter_close_container(&sub, &entry);
|
dbus_message_iter_close_container(&sub, &entry);
|
||||||
}
|
}
|
||||||
dbus_message_iter_close_container(iter, &sub);
|
dbus_message_iter_close_container(iter, &sub);
|
||||||
|
} else static if(isInstanceOf!(VariantN, T)) {
|
||||||
|
enforce(arg.hasValue,
|
||||||
|
new InvalidValueException(arg, "dbus:" ~ cast(char) typeCode!T));
|
||||||
|
|
||||||
|
DBusMessageIter sub;
|
||||||
|
foreach(AT; T.AllowedTypes) {
|
||||||
|
if (arg.peek!AT) {
|
||||||
|
dbus_message_iter_open_container(iter, 'v', typeSig!AT.ptr, &sub);
|
||||||
|
buildIter(&sub, arg.get!AT);
|
||||||
|
dbus_message_iter_close_container(iter, &sub);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else static if(is(T == DBusAny) || is(T == Variant!DBusAny)) {
|
} else static if(is(T == DBusAny) || is(T == Variant!DBusAny)) {
|
||||||
static if(is(T == Variant!DBusAny)) {
|
static if(is(T == Variant!DBusAny)) {
|
||||||
auto val = arg.data;
|
auto val = arg.data;
|
||||||
|
@ -171,10 +185,11 @@ T readIter(T)(DBusMessageIter *iter) if (isInstanceOf!(BitFlags, T)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFlags, T) && canDBus!T) {
|
T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFlags, T) && canDBus!T) {
|
||||||
|
auto argType = dbus_message_iter_get_arg_type(iter);
|
||||||
T ret;
|
T ret;
|
||||||
|
|
||||||
static if(!isVariant!T || is(T == Variant!DBusAny)) {
|
static if(!isVariant!T || is(T == Variant!DBusAny)) {
|
||||||
if(dbus_message_iter_get_arg_type(iter) == 'v') {
|
if(argType == 'v') {
|
||||||
DBusMessageIter sub;
|
DBusMessageIter sub;
|
||||||
dbus_message_iter_recurse(iter, &sub);
|
dbus_message_iter_recurse(iter, &sub);
|
||||||
static if(is(T == Variant!DBusAny)) {
|
static if(is(T == Variant!DBusAny)) {
|
||||||
|
@ -188,8 +203,12 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static if(!is(T == DBusAny) && !is(T == Variant!DBusAny)) {
|
|
||||||
auto argType = dbus_message_iter_get_arg_type(iter);
|
static if(
|
||||||
|
!is(T == DBusAny)
|
||||||
|
&& !is(T == Variant!DBusAny)
|
||||||
|
&& !isInstanceOf!(VariantN, T)
|
||||||
|
) {
|
||||||
enforce(argType == typeCode!T(),
|
enforce(argType == typeCode!T(),
|
||||||
new TypeMismatchException(typeCode!T(), argType));
|
new TypeMismatchException(typeCode!T(), argType));
|
||||||
}
|
}
|
||||||
|
@ -227,6 +246,25 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
DBusMessageIter sub;
|
DBusMessageIter sub;
|
||||||
dbus_message_iter_recurse(iter, &sub);
|
dbus_message_iter_recurse(iter, &sub);
|
||||||
ret.data = readIter!(VariantType!T)(&sub);
|
ret.data = readIter!(VariantType!T)(&sub);
|
||||||
|
} else static if(isInstanceOf!(VariantN, T)) {
|
||||||
|
scope const(char)[] argSig =
|
||||||
|
dbus_message_iter_get_signature(iter).fromStringz();
|
||||||
|
scope(exit)
|
||||||
|
dbus_free(cast(void*) argSig.ptr);
|
||||||
|
|
||||||
|
foreach(AT; T.AllowedTypes) {
|
||||||
|
// We have to compare the full signature here, not just the typecode.
|
||||||
|
// Otherwise, in case of container types, we might select the wrong one.
|
||||||
|
// We would then be calling an incorrect instance of readIter, which would
|
||||||
|
// probably throw a TypeMismatchException.
|
||||||
|
if (typeSig!AT == argSig) {
|
||||||
|
ret = readIter!AT(iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no value is in ret, apparently none of the types matched.
|
||||||
|
enforce(ret.hasValue, new TypeMismatchException(typeCode!T, argType));
|
||||||
} else static if(isAssociativeArray!T) {
|
} else static if(isAssociativeArray!T) {
|
||||||
DBusMessageIter sub;
|
DBusMessageIter sub;
|
||||||
dbus_message_iter_recurse(iter, &sub);
|
dbus_message_iter_recurse(iter, &sub);
|
||||||
|
@ -239,7 +277,7 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
dbus_message_iter_next(&sub);
|
dbus_message_iter_next(&sub);
|
||||||
}
|
}
|
||||||
} else static if(is(T == DBusAny)) {
|
} else static if(is(T == DBusAny)) {
|
||||||
ret.type = dbus_message_iter_get_arg_type(iter);
|
ret.type = argType;
|
||||||
ret.explicitVariant = false;
|
ret.explicitVariant = false;
|
||||||
if(ret.type == 's') {
|
if(ret.type == 's') {
|
||||||
ret.str = readIter!string(iter);
|
ret.str = readIter!string(iter);
|
||||||
|
@ -428,11 +466,16 @@ unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
import ddbus.thin;
|
import ddbus.thin;
|
||||||
|
|
||||||
|
import std.variant : Algebraic;
|
||||||
|
|
||||||
enum E : int { a, b, c }
|
enum E : int { a, b, c }
|
||||||
enum F : uint { x = 1, y = 2, z = 4 }
|
enum F : uint { x = 1, y = 2, z = 4 }
|
||||||
|
alias V = Algebraic!(byte, short, int, long, string);
|
||||||
|
|
||||||
Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth2");
|
Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth2");
|
||||||
msg.build(E.c, 4, 5u, 8u);
|
V v1 = "hello from variant";
|
||||||
|
V v2 = cast(short) 345;
|
||||||
|
msg.build(E.c, 4, 5u, 8u, v1, v2);
|
||||||
|
|
||||||
DBusMessageIter iter, iter2;
|
DBusMessageIter iter, iter2;
|
||||||
dbus_message_iter_init(msg.msg, &iter);
|
dbus_message_iter_init(msg.msg, &iter);
|
||||||
|
@ -446,5 +489,8 @@ unittest {
|
||||||
|
|
||||||
readIter!F(&iter).assertThrow!InvalidValueException();
|
readIter!F(&iter).assertThrow!InvalidValueException();
|
||||||
readIter!(BitFlags!F)(&iter2).assertThrow!InvalidValueException();
|
readIter!(BitFlags!F)(&iter2).assertThrow!InvalidValueException();
|
||||||
|
|
||||||
|
readIter!V(&iter).assertEqual(v1);
|
||||||
|
readIter!short(&iter).assertEqual(v2.get!short);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,15 +48,20 @@ class TypeMismatchException : Exception {
|
||||||
) pure nothrow @safe {
|
) pure nothrow @safe {
|
||||||
_expectedType = expectedType;
|
_expectedType = expectedType;
|
||||||
_actualType = actualType;
|
_actualType = actualType;
|
||||||
|
if (expectedType == 'v') {
|
||||||
|
super("The type of value at the current position in the message is incompatible to the target variant type."
|
||||||
|
~ " Type code of the value: " ~ cast(char) actualType);
|
||||||
|
} else {
|
||||||
super("The type of value at the current position in the message does not match the type of value to be read."
|
super("The type of value at the current position in the message does not match the type of value to be read."
|
||||||
~ " Expected: " ~ cast(char) expectedType ~ ", Got: " ~ cast(char) actualType);
|
~ " Expected: " ~ cast(char) expectedType ~ ", Got: " ~ cast(char) actualType);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int expectedType() @property pure const nothrow @nogc {
|
int expectedType() @property pure const nothrow @safe @nogc {
|
||||||
return _expectedType;
|
return _expectedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
int actualType() @property pure const nothrow @nogc {
|
int actualType() @property pure const nothrow @safe @nogc {
|
||||||
return _actualType;
|
return _actualType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import ddbus.thin;
|
||||||
import std.typecons;
|
import std.typecons;
|
||||||
import std.range;
|
import std.range;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
|
import std.variant : VariantN;
|
||||||
|
|
||||||
struct DictionaryEntry(K, V) {
|
struct DictionaryEntry(K, V) {
|
||||||
K key;
|
K key;
|
||||||
|
@ -62,6 +63,9 @@ template canDBus(T) {
|
||||||
enum canDBus = true;
|
enum canDBus = true;
|
||||||
} else static if(isVariant!T) {
|
} else static if(isVariant!T) {
|
||||||
enum canDBus = canDBus!(VariantType!T);
|
enum canDBus = canDBus!(VariantType!T);
|
||||||
|
} else static if(isInstanceOf!(VariantN, T)) {
|
||||||
|
// Phobos-style variants are supported if limited to DBus compatible types.
|
||||||
|
enum canDBus = (T.AllowedTypes.length > 0) && allCanDBus!(T.AllowedTypes);
|
||||||
} else static if(isTuple!T) {
|
} else static if(isTuple!T) {
|
||||||
enum canDBus = allCanDBus!(T.Types);
|
enum canDBus = allCanDBus!(T.Types);
|
||||||
} else static if(isInputRange!T) {
|
} else static if(isInputRange!T) {
|
||||||
|
@ -112,7 +116,7 @@ string typeSig(T)() if(canDBus!T) {
|
||||||
return "s";
|
return "s";
|
||||||
} else static if(is(T == ObjectPath)) {
|
} else static if(is(T == ObjectPath)) {
|
||||||
return "o";
|
return "o";
|
||||||
} else static if(isVariant!T) {
|
} else static if(isVariant!T || isInstanceOf!(VariantN, T)) {
|
||||||
return "v";
|
return "v";
|
||||||
} else static if(is(T B == enum)) {
|
} else static if(is(T B == enum)) {
|
||||||
return typeSig!B;
|
return typeSig!B;
|
||||||
|
@ -212,6 +216,9 @@ unittest {
|
||||||
typeSig!(DictionaryEntry!(string, int)[]).assertEqual("a{si}");
|
typeSig!(DictionaryEntry!(string, int)[]).assertEqual("a{si}");
|
||||||
// multiple arguments
|
// multiple arguments
|
||||||
typeSigAll!(int,bool).assertEqual("ib");
|
typeSigAll!(int,bool).assertEqual("ib");
|
||||||
|
// Phobos-style variants
|
||||||
|
canDBus!(std.variant.Variant).assertFalse();
|
||||||
|
typeSig!(std.variant.Algebraic!(int, double, string)).assertEqual("v");
|
||||||
// type codes
|
// type codes
|
||||||
typeCode!int().assertEqual(cast(int)('i'));
|
typeCode!int().assertEqual(cast(int)('i'));
|
||||||
typeCode!bool().assertEqual(cast(int)('b'));
|
typeCode!bool().assertEqual(cast(int)('b'));
|
||||||
|
|
Loading…
Reference in a new issue