From 2fde2e12af210f7d75ad0baf73891b975906881b Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Tue, 25 Aug 2020 16:41:59 +0200 Subject: [PATCH] fix immutable/const types & add type convenience Before it was not properly possible to use static immutable name = interfaceName(...) in a message, which is now fixed --- source/ddbus/conv.d | 34 ++++++++++++------------ source/ddbus/thin.d | 63 +++++++++++++++++++++++++++++++-------------- source/ddbus/util.d | 42 +++++++++++++++++++++++++++--- 3 files changed, 99 insertions(+), 40 deletions(-) diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index b90b2a0..6a73b94 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -17,7 +17,7 @@ import std.variant : VariantN; void buildIter(TS...)(DBusMessageIter* iter, TS args) if (allCanDBus!TS) { foreach (index, arg; args) { - alias TS[index] T; + alias T = Unqual!(TS[index]); static if (is(T == string) || is(T == InterfaceName) || is(T == BusName)) { immutable(char)* cStr = arg.toStringz(); dbus_message_iter_append_basic(iter, typeCode!T, &cStr); @@ -172,10 +172,10 @@ void buildIter(TS...)(DBusMessageIter* iter, TS args) } T readIter(T)(DBusMessageIter* iter) - if (is(T == enum) && !is(T == InterfaceName) && !is(T == BusName)) { + if (is(T == enum) && !is(Unqual!T == InterfaceName) && !is(Unqual!T == BusName)) { import std.algorithm.searching : canFind; - alias OriginalType!T B; + alias B = Unqual!(OriginalType!T); B value = readIter!B(iter); enforce(only(EnumMembers!T).canFind(value), new InvalidValueException(value, T.stringof)); @@ -197,8 +197,10 @@ T readIter(T)(DBusMessageIter* iter) return T(cast(E) value); } -T readIter(T)(DBusMessageIter* iter) - if (!(is(T == enum) && !is(T == InterfaceName) && !is(T == BusName)) && !isInstanceOf!(BitFlags, T) && canDBus!T) { +U readIter(U)(DBusMessageIter* iter) + if (!(is(U == enum) && !is(Unqual!U == InterfaceName) && !is(Unqual!U == BusName)) && !isInstanceOf!(BitFlags, U) && canDBus!U) { + alias T = Unqual!U; + auto argType = dbus_message_iter_get_arg_type(iter); T ret; @@ -214,7 +216,7 @@ T readIter(T)(DBusMessageIter* iter) ret.explicitVariant = true; } dbus_message_iter_next(iter); - return ret; + return cast(U) ret; } } @@ -226,7 +228,7 @@ T readIter(T)(DBusMessageIter* iter) const(char)* cStr; dbus_message_iter_get_basic(iter, &cStr); string str = cStr.fromStringz().idup; // copy string - static if (is(T == string) || is(T == InterfaceName) || is(T == BusName)) { + static if (is(T == string) || is(T : InterfaceName) || is(T : BusName)) { ret = cast(T)str; } else { ret = ObjectPath(str); @@ -239,20 +241,20 @@ T readIter(T)(DBusMessageIter* iter) DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); readIterTuple!T(&sub, ret); - } else static if (is(T t : U[], U)) { - assert(dbus_message_iter_get_element_type(iter) == typeCode!U); + } else static if (is(T t : S[], S)) { + assert(dbus_message_iter_get_element_type(iter) == typeCode!S); DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); while (dbus_message_iter_get_arg_type(&sub) != 0) { - static if (is(U == DictionaryEntry!(K, V), K, V)) { + static if (is(S == DictionaryEntry!(K, V), K, V)) { DBusMessageIter entry; dbus_message_iter_recurse(&sub, &entry); - ret ~= U(readIter!K(&entry), readIter!V(&entry)); + ret ~= S(readIter!K(&entry), readIter!V(&entry)); dbus_message_iter_next(&sub); } else { - ret ~= readIter!U(&sub); + ret ~= readIter!S(&sub); } } } else static if (isInstanceOf!(Variant, T)) { @@ -295,13 +297,13 @@ T readIter(T)(DBusMessageIter* iter) if (ret.type == 's') { ret.str = readIter!string(iter); - return ret; + return cast(U) ret; } else if (ret.type == 'o') { ret.obj = readIter!ObjectPath(iter); - return ret; + return cast(U) ret; } else if (ret.type == 'b') { ret.boolean = readIter!bool(iter); - return ret; + return cast(U) ret; } else if (dbus_type_is_basic(ret.type)) { dbus_message_iter_get_basic(iter, &ret.int64); } else if (ret.type == 'a') { @@ -351,7 +353,7 @@ T readIter(T)(DBusMessageIter* iter) } dbus_message_iter_next(iter); - return ret; + return cast(U) ret; } void readIterTuple(Tup)(DBusMessageIter* iter, ref Tup tuple) diff --git a/source/ddbus/thin.d b/source/ddbus/thin.d index c8c7bf6..74e7a6e 100644 --- a/source/ddbus/thin.d +++ b/source/ddbus/thin.d @@ -46,6 +46,10 @@ struct ObjectPath { return hashOf(_value); } + T opCast(T : ObjectPath)() const pure @nogc nothrow @safe { + return this; + } + T opCast(T : string)() const pure @nogc nothrow @safe { return value; } @@ -482,25 +486,26 @@ struct DBusAny { TypeMismatchException if the DBus type of the current value of the DBusAny object is not the same as the DBus type used to represent T. +/ - T get(T)() @property const - if (staticIndexOf!(T, BasicTypes) >= 0) { + U get(U)() @property const + if (staticIndexOf!(Unqual!U, BasicTypes) >= 0) { + alias T = Unqual!U; enforce(type == typeCode!T, new TypeMismatchException( "Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ typeSig ~ "'.", typeCode!T, type)); static if (isIntegral!T) { enum memberName = (isUnsigned!T ? "uint" : "int") ~ (T.sizeof * 8).to!string; - return __traits(getMember, this, memberName); + return cast(U) __traits(getMember, this, memberName); } else static if (is(T == double)) { - return float64; + return cast(U) float64; } else static if (is(T == string)) { - return str; + return cast(U) str; } else static if (is(T == InterfaceName) || is(T == BusName)) { - return cast(T) str; + return cast(U) str; } else static if (is(T == ObjectPath)) { - return obj; + return cast(U) obj; } else static if (is(T == bool)) { - return boolean; + return cast(U) boolean; } else { static assert(false); } @@ -696,6 +701,21 @@ struct DBusAny { return uint64 == b.uint64; } } + + /// Returns: true if this variant is an integer. + bool typeIsIntegral() const @property { + return type.dbusIsIntegral; + } + + /// Returns: true if this variant is a floating point value. + bool typeIsFloating() const @property { + return type.dbusIsFloating; + } + + /// Returns: true if this variant is an integer or a floating point value. + bool typeIsNumeric() const @property { + return type.dbusIsNumeric; + } } unittest { @@ -706,23 +726,26 @@ unittest { return v; } - void test(T)(T value, DBusAny b) { + void test(bool testGet = false, T)(T value, DBusAny b) { assertEqual(DBusAny(value), b); assertEqual(b.to!T, value); + static if (testGet) + assertEqual(b.get!T, value); b.toString(); } - test(cast(ubyte) 184, set!"uint8"(DBusAny('y', null, false), cast(ubyte) 184)); - test(cast(short) 184, set!"int16"(DBusAny('n', null, false), cast(short) 184)); - test(cast(ushort) 184, set!"uint16"(DBusAny('q', null, false), cast(ushort) 184)); - test(cast(int) 184, set!"int32"(DBusAny('i', null, false), cast(int) 184)); - test(cast(uint) 184, set!"uint32"(DBusAny('u', null, false), cast(uint) 184)); - test(cast(long) 184, set!"int64"(DBusAny('x', null, false), cast(long) 184)); - test(cast(ulong) 184, set!"uint64"(DBusAny('t', null, false), cast(ulong) 184)); - test(1.84, set!"float64"(DBusAny('d', null, false), 1.84)); - test(true, set!"boolean"(DBusAny('b', null, false), true)); - test("abc", set!"str"(DBusAny('s', null, false), "abc")); - test(ObjectPath("/foo/Bar"), set!"obj"(DBusAny('o', null, false), ObjectPath("/foo/Bar"))); + test!true(cast(ubyte) 184, set!"uint8"(DBusAny('y', null, false), cast(ubyte) 184)); + test(cast(byte) 184, set!"uint8"(DBusAny('y', null, false), cast(byte) 184)); + test!true(cast(short) 184, set!"int16"(DBusAny('n', null, false), cast(short) 184)); + test!true(cast(ushort) 184, set!"uint16"(DBusAny('q', null, false), cast(ushort) 184)); + test!true(cast(int) 184, set!"int32"(DBusAny('i', null, false), cast(int) 184)); + test!true(cast(uint) 184, set!"uint32"(DBusAny('u', null, false), cast(uint) 184)); + test!true(cast(long) 184, set!"int64"(DBusAny('x', null, false), cast(long) 184)); + test!true(cast(ulong) 184, set!"uint64"(DBusAny('t', null, false), cast(ulong) 184)); + test!true(1.84, set!"float64"(DBusAny('d', null, false), 1.84)); + test!true(true, set!"boolean"(DBusAny('b', null, false), true)); + test!true("abc", set!"str"(DBusAny('s', null, false), "abc")); + test!true(ObjectPath("/foo/Bar"), set!"obj"(DBusAny('o', null, false), ObjectPath("/foo/Bar"))); test(cast(ubyte[])[1, 2, 3], set!"binaryData"(DBusAny('a', ['y'], false), cast(ubyte[])[1, 2, 3])); diff --git a/source/ddbus/util.d b/source/ddbus/util.d index db6c647..ede8dc7 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -57,7 +57,8 @@ package // Don't add to the API yet, 'cause I intend to move it later alias BasicTypes = AliasSeq!(bool, ubyte, short, ushort, int, uint, long, ulong, double, string, ObjectPath, InterfaceName, BusName); -template basicDBus(T) { +template basicDBus(U) { + alias T = Unqual!U; static if (staticIndexOf!(T, BasicTypes) >= 0) { enum basicDBus = true; } else static if (is(T B == enum)) { @@ -70,7 +71,8 @@ template basicDBus(T) { } } -template canDBus(T) { +template canDBus(U) { + alias T = Unqual!U; static if (basicDBus!T || is(T == DBusAny)) { enum canDBus = true; } else static if (isInstanceOf!(Variant, T)) { @@ -106,8 +108,9 @@ unittest { (canDBus!(int[string])).assertTrue(); } -string typeSig(T)() - if (canDBus!T) { +string typeSig(U)() + if (canDBus!U) { + alias T = Unqual!U; static if (is(T == ubyte)) { return "y"; } else static if (is(T == bool)) { @@ -205,6 +208,33 @@ int typeCode(T)() return 'e'; } +/** + Params: + type = the type code of a type (first character in a type string) + Returns: true if the given type is an integer. +*/ +bool dbusIsIntegral(int type) @property { + return type == 'y' || type == 'n' || type == 'q' || type == 'i' || type == 'u' || type == 'x' || type == 't'; +} + +/** + Params: + type = the type code of a type (first character in a type string) + Returns: true if the given type is a floating point value. +*/ +bool dbusIsFloating(int type) @property { + return type == 'd'; +} + +/** + Params: + type = the type code of a type (first character in a type string) + Returns: true if the given type is an integer or a floating point value. +*/ +bool dbusIsNumeric(int type) @property { + return dbusIsIntegral(type) || dbusIsFloating(type); +} + unittest { import dunit.toolkit; @@ -216,6 +246,10 @@ unittest { typeSig!int().assertEqual("i"); typeSig!bool().assertEqual("b"); typeSig!string().assertEqual("s"); + typeSig!InterfaceName().assertEqual("s"); + typeSig!(immutable(InterfaceName))().assertEqual("s"); + typeSig!ObjectPath().assertEqual("o"); + typeSig!(immutable(ObjectPath))().assertEqual("o"); typeSig!(Variant!int)().assertEqual("v"); // enums enum E : ubyte {