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
This commit is contained in:
WebFreak001 2020-08-25 16:41:59 +02:00 committed by Jan Jurzitza
parent f988709b7a
commit 2fde2e12af
3 changed files with 99 additions and 40 deletions

View file

@ -17,7 +17,7 @@ import std.variant : VariantN;
void buildIter(TS...)(DBusMessageIter* iter, TS args) void buildIter(TS...)(DBusMessageIter* iter, TS args)
if (allCanDBus!TS) { if (allCanDBus!TS) {
foreach (index, arg; args) { foreach (index, arg; args) {
alias TS[index] T; alias T = Unqual!(TS[index]);
static if (is(T == string) || is(T == InterfaceName) || is(T == BusName)) { static if (is(T == string) || is(T == InterfaceName) || is(T == BusName)) {
immutable(char)* cStr = arg.toStringz(); immutable(char)* cStr = arg.toStringz();
dbus_message_iter_append_basic(iter, typeCode!T, &cStr); 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) 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; import std.algorithm.searching : canFind;
alias OriginalType!T B; alias B = Unqual!(OriginalType!T);
B value = readIter!B(iter); B value = readIter!B(iter);
enforce(only(EnumMembers!T).canFind(value), new InvalidValueException(value, T.stringof)); 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); return T(cast(E) value);
} }
T readIter(T)(DBusMessageIter* iter) U readIter(U)(DBusMessageIter* iter)
if (!(is(T == enum) && !is(T == InterfaceName) && !is(T == BusName)) && !isInstanceOf!(BitFlags, T) && canDBus!T) { 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); auto argType = dbus_message_iter_get_arg_type(iter);
T ret; T ret;
@ -214,7 +216,7 @@ T readIter(T)(DBusMessageIter* iter)
ret.explicitVariant = true; ret.explicitVariant = true;
} }
dbus_message_iter_next(iter); dbus_message_iter_next(iter);
return ret; return cast(U) ret;
} }
} }
@ -226,7 +228,7 @@ T readIter(T)(DBusMessageIter* iter)
const(char)* cStr; const(char)* cStr;
dbus_message_iter_get_basic(iter, &cStr); dbus_message_iter_get_basic(iter, &cStr);
string str = cStr.fromStringz().idup; // copy string 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; ret = cast(T)str;
} else { } else {
ret = ObjectPath(str); ret = ObjectPath(str);
@ -239,20 +241,20 @@ T readIter(T)(DBusMessageIter* iter)
DBusMessageIter sub; DBusMessageIter sub;
dbus_message_iter_recurse(iter, &sub); dbus_message_iter_recurse(iter, &sub);
readIterTuple!T(&sub, ret); readIterTuple!T(&sub, ret);
} else static if (is(T t : U[], U)) { } else static if (is(T t : S[], S)) {
assert(dbus_message_iter_get_element_type(iter) == typeCode!U); assert(dbus_message_iter_get_element_type(iter) == typeCode!S);
DBusMessageIter sub; DBusMessageIter sub;
dbus_message_iter_recurse(iter, &sub); dbus_message_iter_recurse(iter, &sub);
while (dbus_message_iter_get_arg_type(&sub) != 0) { 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; DBusMessageIter entry;
dbus_message_iter_recurse(&sub, &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); dbus_message_iter_next(&sub);
} else { } else {
ret ~= readIter!U(&sub); ret ~= readIter!S(&sub);
} }
} }
} else static if (isInstanceOf!(Variant, T)) { } else static if (isInstanceOf!(Variant, T)) {
@ -295,13 +297,13 @@ T readIter(T)(DBusMessageIter* iter)
if (ret.type == 's') { if (ret.type == 's') {
ret.str = readIter!string(iter); ret.str = readIter!string(iter);
return ret; return cast(U) ret;
} else if (ret.type == 'o') { } else if (ret.type == 'o') {
ret.obj = readIter!ObjectPath(iter); ret.obj = readIter!ObjectPath(iter);
return ret; return cast(U) ret;
} else if (ret.type == 'b') { } else if (ret.type == 'b') {
ret.boolean = readIter!bool(iter); ret.boolean = readIter!bool(iter);
return ret; return cast(U) ret;
} else if (dbus_type_is_basic(ret.type)) { } else if (dbus_type_is_basic(ret.type)) {
dbus_message_iter_get_basic(iter, &ret.int64); dbus_message_iter_get_basic(iter, &ret.int64);
} else if (ret.type == 'a') { } else if (ret.type == 'a') {
@ -351,7 +353,7 @@ T readIter(T)(DBusMessageIter* iter)
} }
dbus_message_iter_next(iter); dbus_message_iter_next(iter);
return ret; return cast(U) ret;
} }
void readIterTuple(Tup)(DBusMessageIter* iter, ref Tup tuple) void readIterTuple(Tup)(DBusMessageIter* iter, ref Tup tuple)

View file

@ -46,6 +46,10 @@ struct ObjectPath {
return hashOf(_value); return hashOf(_value);
} }
T opCast(T : ObjectPath)() const pure @nogc nothrow @safe {
return this;
}
T opCast(T : string)() const pure @nogc nothrow @safe { T opCast(T : string)() const pure @nogc nothrow @safe {
return value; return value;
} }
@ -482,25 +486,26 @@ struct DBusAny {
TypeMismatchException if the DBus type of the current value of the 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. DBusAny object is not the same as the DBus type used to represent T.
+/ +/
T get(T)() @property const U get(U)() @property const
if (staticIndexOf!(T, BasicTypes) >= 0) { if (staticIndexOf!(Unqual!U, BasicTypes) >= 0) {
alias T = Unqual!U;
enforce(type == typeCode!T, new TypeMismatchException( enforce(type == typeCode!T, new TypeMismatchException(
"Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ typeSig ~ "'.", "Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ typeSig ~ "'.",
typeCode!T, type)); typeCode!T, type));
static if (isIntegral!T) { static if (isIntegral!T) {
enum memberName = (isUnsigned!T ? "uint" : "int") ~ (T.sizeof * 8).to!string; 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)) { } else static if (is(T == double)) {
return float64; return cast(U) float64;
} else static if (is(T == string)) { } else static if (is(T == string)) {
return str; return cast(U) str;
} else static if (is(T == InterfaceName) || is(T == BusName)) { } else static if (is(T == InterfaceName) || is(T == BusName)) {
return cast(T) str; return cast(U) str;
} else static if (is(T == ObjectPath)) { } else static if (is(T == ObjectPath)) {
return obj; return cast(U) obj;
} else static if (is(T == bool)) { } else static if (is(T == bool)) {
return boolean; return cast(U) boolean;
} else { } else {
static assert(false); static assert(false);
} }
@ -696,6 +701,21 @@ struct DBusAny {
return uint64 == b.uint64; 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 { unittest {
@ -706,23 +726,26 @@ unittest {
return v; return v;
} }
void test(T)(T value, DBusAny b) { void test(bool testGet = false, T)(T value, DBusAny b) {
assertEqual(DBusAny(value), b); assertEqual(DBusAny(value), b);
assertEqual(b.to!T, value); assertEqual(b.to!T, value);
static if (testGet)
assertEqual(b.get!T, value);
b.toString(); b.toString();
} }
test(cast(ubyte) 184, set!"uint8"(DBusAny('y', null, false), cast(ubyte) 184)); test!true(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(byte) 184, set!"uint8"(DBusAny('y', null, false), cast(byte) 184));
test(cast(ushort) 184, set!"uint16"(DBusAny('q', null, false), cast(ushort) 184)); test!true(cast(short) 184, set!"int16"(DBusAny('n', null, false), cast(short) 184));
test(cast(int) 184, set!"int32"(DBusAny('i', null, false), cast(int) 184)); test!true(cast(ushort) 184, set!"uint16"(DBusAny('q', null, false), cast(ushort) 184));
test(cast(uint) 184, set!"uint32"(DBusAny('u', null, false), cast(uint) 184)); test!true(cast(int) 184, set!"int32"(DBusAny('i', null, false), cast(int) 184));
test(cast(long) 184, set!"int64"(DBusAny('x', null, false), cast(long) 184)); test!true(cast(uint) 184, set!"uint32"(DBusAny('u', null, false), cast(uint) 184));
test(cast(ulong) 184, set!"uint64"(DBusAny('t', null, false), cast(ulong) 184)); test!true(cast(long) 184, set!"int64"(DBusAny('x', null, false), cast(long) 184));
test(1.84, set!"float64"(DBusAny('d', null, false), 1.84)); test!true(cast(ulong) 184, set!"uint64"(DBusAny('t', null, false), cast(ulong) 184));
test(true, set!"boolean"(DBusAny('b', null, false), true)); test!true(1.84, set!"float64"(DBusAny('d', null, false), 1.84));
test("abc", set!"str"(DBusAny('s', null, false), "abc")); test!true(true, set!"boolean"(DBusAny('b', null, false), true));
test(ObjectPath("/foo/Bar"), set!"obj"(DBusAny('o', null, false), ObjectPath("/foo/Bar"))); 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), test(cast(ubyte[])[1, 2, 3], set!"binaryData"(DBusAny('a', ['y'], false),
cast(ubyte[])[1, 2, 3])); cast(ubyte[])[1, 2, 3]));

View file

@ -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, alias BasicTypes = AliasSeq!(bool, ubyte, short, ushort, int, uint, long, ulong,
double, string, ObjectPath, InterfaceName, BusName); double, string, ObjectPath, InterfaceName, BusName);
template basicDBus(T) { template basicDBus(U) {
alias T = Unqual!U;
static if (staticIndexOf!(T, BasicTypes) >= 0) { static if (staticIndexOf!(T, BasicTypes) >= 0) {
enum basicDBus = true; enum basicDBus = true;
} else static if (is(T B == enum)) { } 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)) { static if (basicDBus!T || is(T == DBusAny)) {
enum canDBus = true; enum canDBus = true;
} else static if (isInstanceOf!(Variant, T)) { } else static if (isInstanceOf!(Variant, T)) {
@ -106,8 +108,9 @@ unittest {
(canDBus!(int[string])).assertTrue(); (canDBus!(int[string])).assertTrue();
} }
string typeSig(T)() string typeSig(U)()
if (canDBus!T) { if (canDBus!U) {
alias T = Unqual!U;
static if (is(T == ubyte)) { static if (is(T == ubyte)) {
return "y"; return "y";
} else static if (is(T == bool)) { } else static if (is(T == bool)) {
@ -205,6 +208,33 @@ int typeCode(T)()
return 'e'; 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 { unittest {
import dunit.toolkit; import dunit.toolkit;
@ -216,6 +246,10 @@ unittest {
typeSig!int().assertEqual("i"); typeSig!int().assertEqual("i");
typeSig!bool().assertEqual("b"); typeSig!bool().assertEqual("b");
typeSig!string().assertEqual("s"); 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"); typeSig!(Variant!int)().assertEqual("v");
// enums // enums
enum E : ubyte { enum E : ubyte {