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)
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)

View file

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

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,
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 {