Improved code formatting (#33)
- Used dfmt (otbs style) - Added some empty lines and braces on all block statements - Add .editorconfig Closes #29
This commit is contained in:
parent
c42eb823a2
commit
137b3c36b7
8
.editorconfig
Normal file
8
.editorconfig
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[**.d]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
dfmt_brace_style = otbs
|
||||||
|
dfmt_space_after_keywords = true
|
||||||
|
dfmt_space_after_cast = true
|
||||||
|
dfmt_template_constraint_style = always_newline_indent
|
|
@ -10,10 +10,16 @@ import std.typecons : BitFlags, Flag;
|
||||||
Default is to include public fields only
|
Default is to include public fields only
|
||||||
+/
|
+/
|
||||||
enum MarshalingFlag : ubyte {
|
enum MarshalingFlag : ubyte {
|
||||||
includePrivateFields = 1 << 0, /// Automatically include private fields
|
/++
|
||||||
manualOnly = 1 << 7 /// Only include fields with explicit
|
Automatically include private fields
|
||||||
/// `@Yes.DBusMarshal`. This overrides any
|
+/
|
||||||
/// `include` flags.
|
includePrivateFields = 1 << 0,
|
||||||
|
|
||||||
|
/++
|
||||||
|
Only include fields with explicit `@Yes.DBusMarshal`. This overrides any
|
||||||
|
`include` flags.
|
||||||
|
+/
|
||||||
|
manualOnly = 1 << 7
|
||||||
}
|
}
|
||||||
|
|
||||||
/++
|
/++
|
||||||
|
@ -31,35 +37,38 @@ package(ddbus) template isAllowedField(alias field) {
|
||||||
static if (UDAs.length != 0) {
|
static if (UDAs.length != 0) {
|
||||||
static assert(UDAs.length == 1,
|
static assert(UDAs.length == 1,
|
||||||
"Only one UDA of type Flag!\"DBusMarshal\" allowed on struct field.");
|
"Only one UDA of type Flag!\"DBusMarshal\" allowed on struct field.");
|
||||||
|
|
||||||
static assert(is(typeof(UDAs[0]) == Flag!"DBusMarshal"),
|
static assert(is(typeof(UDAs[0]) == Flag!"DBusMarshal"),
|
||||||
"Did you intend to add UDA Yes.DBusMarshal or No.DBusMarshal?");
|
"Did you intend to add UDA Yes.DBusMarshal or No.DBusMarshal?");
|
||||||
|
|
||||||
enum isAllowedField = cast(bool) UDAs[0];
|
enum isAllowedField = cast(bool) UDAs[0];
|
||||||
} else static if (!(flags & MarshalingFlag.manualOnly)) {
|
} else static if (!(flags & MarshalingFlag.manualOnly)) {
|
||||||
static if (__traits(getProtection, field) == "public")
|
static if (__traits(getProtection, field) == "public") {
|
||||||
enum isAllowedField = true;
|
enum isAllowedField = true;
|
||||||
else static if (cast(bool) (flags & MarshalingFlag.includePrivateFields))
|
} else static if (cast(bool)(flags & MarshalingFlag.includePrivateFields)) {
|
||||||
enum isAllowedField = true;
|
enum isAllowedField = true;
|
||||||
else
|
} else {
|
||||||
enum isAllowedField = false;
|
enum isAllowedField = false;
|
||||||
} else
|
}
|
||||||
|
} else {
|
||||||
enum isAllowedField = false;
|
enum isAllowedField = false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private template isMarshalingFlag(T) {
|
private template isMarshalingFlag(T) {
|
||||||
enum isMarshalingFlag = is(T == MarshalingFlag);
|
enum isMarshalingFlag = is(T == MarshalingFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
private template marshalingFlags(S) if (is(S == struct)) {
|
private template marshalingFlags(S)
|
||||||
|
if (is(S == struct)) {
|
||||||
private alias getUDAs!(S, BitFlags!MarshalingFlag) UDAs;
|
private alias getUDAs!(S, BitFlags!MarshalingFlag) UDAs;
|
||||||
|
|
||||||
static if (UDAs.length == 0)
|
static if (UDAs.length == 0) {
|
||||||
enum marshalingFlags = BitFlags!MarshalingFlag.init;
|
enum marshalingFlags = BitFlags!MarshalingFlag.init;
|
||||||
else {
|
} else {
|
||||||
static assert (UDAs.length == 1,
|
static assert(UDAs.length == 1, "Only one @dbusMarshaling UDA allowed on type.");
|
||||||
"Only one @dbusMarshaling UDA allowed on type.");
|
|
||||||
static assert(is(typeof(UDAs[0]) == BitFlags!MarshalingFlag),
|
static assert(is(typeof(UDAs[0]) == BitFlags!MarshalingFlag),
|
||||||
"Huh? Did you intend to use @dbusMarshaling UDA?");
|
"Huh? Did you intend to use @dbusMarshaling UDA?");
|
||||||
enum marshalingFlags = UDAs[0];
|
enum marshalingFlags = UDAs[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,9 @@ enum BusPath = "/org/freedesktop/DBus";
|
||||||
enum BusInterface = "org.freedesktop.DBus";
|
enum BusInterface = "org.freedesktop.DBus";
|
||||||
|
|
||||||
enum NameFlags {
|
enum NameFlags {
|
||||||
AllowReplace = 1, ReplaceExisting = 2, NoQueue = 4
|
AllowReplace = 1,
|
||||||
|
ReplaceExisting = 2,
|
||||||
|
NoQueue = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Requests a DBus well-known name.
|
/// Requests a DBus well-known name.
|
||||||
|
@ -28,7 +30,8 @@ bool requestName(Connection conn, string name,
|
||||||
/// and isn't guaranteed to work with other tasks and threads.
|
/// and isn't guaranteed to work with other tasks and threads.
|
||||||
/// Use only for apps that only do DBus triggered things.
|
/// Use only for apps that only do DBus triggered things.
|
||||||
void simpleMainLoop(Connection conn) {
|
void simpleMainLoop(Connection conn) {
|
||||||
while(dbus_connection_read_write_dispatch(conn.conn, -1)) {} // empty loop body
|
while (dbus_connection_read_write_dispatch(conn.conn, -1)) {
|
||||||
|
} // empty loop body
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Single tick in the DBus connection which can be used for
|
/// Single tick in the DBus connection which can be used for
|
||||||
|
@ -39,7 +42,7 @@ bool tick(Connection conn) {
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
Connection conn = connectToBus();
|
Connection conn = connectToBus();
|
||||||
conn.requestName("ca.thume.ddbus.testing").assertTrue();
|
conn.requestName("ca.thume.ddbus.testing").assertTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
module ddbus.c_lib;
|
module ddbus.c_lib;
|
||||||
|
|
||||||
import core.stdc.config;
|
import core.stdc.config;
|
||||||
import core.stdc.stdarg;
|
import core.stdc.stdarg;
|
||||||
|
|
||||||
|
// dfmt off
|
||||||
|
|
||||||
extern (C):
|
extern (C):
|
||||||
// START dbus/dbus-arch-deps.d
|
// START dbus/dbus-arch-deps.d
|
||||||
alias c_long dbus_int64_t;
|
alias c_long dbus_int64_t;
|
||||||
|
|
|
@ -14,7 +14,8 @@ import std.range;
|
||||||
import std.traits;
|
import std.traits;
|
||||||
import std.variant : VariantN;
|
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) {
|
||||||
alias TS[index] T;
|
alias TS[index] T;
|
||||||
static if (is(T == string)) {
|
static if (is(T == string)) {
|
||||||
|
@ -60,8 +61,7 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
||||||
}
|
}
|
||||||
dbus_message_iter_close_container(iter, &sub);
|
dbus_message_iter_close_container(iter, &sub);
|
||||||
} else static if (isInstanceOf!(VariantN, T)) {
|
} else static if (isInstanceOf!(VariantN, T)) {
|
||||||
enforce(arg.hasValue,
|
enforce(arg.hasValue, new InvalidValueException(arg, "dbus:" ~ cast(char) typeCode!T));
|
||||||
new InvalidValueException(arg, "dbus:" ~ cast(char) typeCode!T));
|
|
||||||
|
|
||||||
DBusMessageIter sub;
|
DBusMessageIter sub;
|
||||||
foreach (AT; T.AllowedTypes) {
|
foreach (AT; T.AllowedTypes) {
|
||||||
|
@ -82,15 +82,20 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
||||||
DBusMessageIter subStore;
|
DBusMessageIter subStore;
|
||||||
DBusMessageIter* sub = &subStore;
|
DBusMessageIter* sub = &subStore;
|
||||||
const(char)[] sig = [cast(char) val.type];
|
const(char)[] sig = [cast(char) val.type];
|
||||||
if(val.type == 'a')
|
if (val.type == 'a') {
|
||||||
sig ~= val.signature;
|
sig ~= val.signature;
|
||||||
else if(val.type == 'r')
|
} else if (val.type == 'r') {
|
||||||
sig = val.signature;
|
sig = val.signature;
|
||||||
|
}
|
||||||
|
|
||||||
sig ~= '\0';
|
sig ~= '\0';
|
||||||
if (!val.explicitVariant)
|
|
||||||
|
if (!val.explicitVariant) {
|
||||||
sub = iter;
|
sub = iter;
|
||||||
else
|
} else {
|
||||||
dbus_message_iter_open_container(iter, 'v', sig.ptr, sub);
|
dbus_message_iter_open_container(iter, 'v', sig.ptr, sub);
|
||||||
|
}
|
||||||
|
|
||||||
if (val.type == 's') {
|
if (val.type == 's') {
|
||||||
buildIter(sub, val.str);
|
buildIter(sub, val.str);
|
||||||
} else if (val.type == 'o') {
|
} else if (val.type == 'o') {
|
||||||
|
@ -102,18 +107,26 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
||||||
} else if (val.type == 'a') {
|
} else if (val.type == 'a') {
|
||||||
DBusMessageIter arr;
|
DBusMessageIter arr;
|
||||||
dbus_message_iter_open_container(sub, 'a', sig[1 .. $].ptr, &arr);
|
dbus_message_iter_open_container(sub, 'a', sig[1 .. $].ptr, &arr);
|
||||||
if (val.signature == ['y'])
|
|
||||||
foreach (item; val.binaryData)
|
if (val.signature == ['y']) {
|
||||||
|
foreach (item; val.binaryData) {
|
||||||
dbus_message_iter_append_basic(&arr, 'y', &item);
|
dbus_message_iter_append_basic(&arr, 'y', &item);
|
||||||
else
|
}
|
||||||
foreach(item; val.array)
|
} else {
|
||||||
|
foreach (item; val.array) {
|
||||||
buildIter(&arr, item);
|
buildIter(&arr, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dbus_message_iter_close_container(sub, &arr);
|
dbus_message_iter_close_container(sub, &arr);
|
||||||
} else if (val.type == 'r') {
|
} else if (val.type == 'r') {
|
||||||
DBusMessageIter arr;
|
DBusMessageIter arr;
|
||||||
dbus_message_iter_open_container(sub, 'r', null, &arr);
|
dbus_message_iter_open_container(sub, 'r', null, &arr);
|
||||||
foreach(item; val.tuple)
|
|
||||||
|
foreach (item; val.tuple) {
|
||||||
buildIter(&arr, item);
|
buildIter(&arr, item);
|
||||||
|
}
|
||||||
|
|
||||||
dbus_message_iter_close_container(sub, &arr);
|
dbus_message_iter_close_container(sub, &arr);
|
||||||
} else if (val.type == 'e') {
|
} else if (val.type == 'e') {
|
||||||
DBusMessageIter entry;
|
DBusMessageIter entry;
|
||||||
|
@ -122,8 +135,10 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
||||||
buildIter(&entry, val.entry.value);
|
buildIter(&entry, val.entry.value);
|
||||||
dbus_message_iter_close_container(sub, &entry);
|
dbus_message_iter_close_container(sub, &entry);
|
||||||
}
|
}
|
||||||
if(val.explicitVariant)
|
|
||||||
|
if (val.explicitVariant) {
|
||||||
dbus_message_iter_close_container(iter, sub);
|
dbus_message_iter_close_container(iter, sub);
|
||||||
|
}
|
||||||
} else static if (isInstanceOf!(Variant, T)) {
|
} else static if (isInstanceOf!(Variant, T)) {
|
||||||
DBusMessageIter sub;
|
DBusMessageIter sub;
|
||||||
const(char)* subSig = typeSig!(VariantType!T).toStringz();
|
const(char)* subSig = typeSig!(VariantType!T).toStringz();
|
||||||
|
@ -156,20 +171,19 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
T readIter(T)(DBusMessageIter *iter) if (is(T == enum)) {
|
T readIter(T)(DBusMessageIter* iter)
|
||||||
|
if (is(T == enum)) {
|
||||||
import std.algorithm.searching : canFind;
|
import std.algorithm.searching : canFind;
|
||||||
|
|
||||||
alias OriginalType!T B;
|
alias OriginalType!T B;
|
||||||
|
|
||||||
B value = readIter!B(iter);
|
B value = readIter!B(iter);
|
||||||
enforce(
|
enforce(only(EnumMembers!T).canFind(value), new InvalidValueException(value, T.stringof));
|
||||||
only(EnumMembers!T).canFind(value),
|
|
||||||
new InvalidValueException(value, T.stringof)
|
|
||||||
);
|
|
||||||
return cast(T) value;
|
return cast(T) value;
|
||||||
}
|
}
|
||||||
|
|
||||||
T readIter(T)(DBusMessageIter *iter) if (isInstanceOf!(BitFlags, T)) {
|
T readIter(T)(DBusMessageIter* iter)
|
||||||
|
if (isInstanceOf!(BitFlags, T)) {
|
||||||
import std.algorithm.iteration : fold;
|
import std.algorithm.iteration : fold;
|
||||||
|
|
||||||
alias TemplateArgsOf!T[0] E;
|
alias TemplateArgsOf!T[0] E;
|
||||||
|
@ -178,15 +192,13 @@ T readIter(T)(DBusMessageIter *iter) if (isInstanceOf!(BitFlags, T)) {
|
||||||
B mask = only(EnumMembers!E).fold!((a, b) => cast(B)(a | b));
|
B mask = only(EnumMembers!E).fold!((a, b) => cast(B)(a | b));
|
||||||
|
|
||||||
B value = readIter!B(iter);
|
B value = readIter!B(iter);
|
||||||
enforce(
|
enforce(!(value & ~mask), new InvalidValueException(value, T.stringof));
|
||||||
!(value & ~mask),
|
|
||||||
new InvalidValueException(value, T.stringof)
|
|
||||||
);
|
|
||||||
|
|
||||||
return T(cast(E) value);
|
return T(cast(E) value);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
auto argType = dbus_message_iter_get_arg_type(iter);
|
||||||
T ret;
|
T ret;
|
||||||
|
|
||||||
|
@ -206,22 +218,19 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static if(
|
static if (!is(T == DBusAny) && !is(T == Variant!DBusAny) && !isInstanceOf!(VariantN, T)) {
|
||||||
!is(T == DBusAny)
|
enforce(argType == typeCode!T(), new TypeMismatchException(typeCode!T(), argType));
|
||||||
&& !is(T == Variant!DBusAny)
|
|
||||||
&& !isInstanceOf!(VariantN, T)
|
|
||||||
) {
|
|
||||||
enforce(argType == typeCode!T(),
|
|
||||||
new TypeMismatchException(typeCode!T(), argType));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static if (is(T == string) || is(T == ObjectPath)) {
|
static if (is(T == string) || is(T == ObjectPath)) {
|
||||||
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))
|
static if (is(T == string)) {
|
||||||
ret = str;
|
ret = str;
|
||||||
else
|
} else {
|
||||||
ret = ObjectPath(str);
|
ret = ObjectPath(str);
|
||||||
|
}
|
||||||
} else static if (is(T == bool)) {
|
} else static if (is(T == bool)) {
|
||||||
dbus_bool_t longerBool;
|
dbus_bool_t longerBool;
|
||||||
dbus_message_iter_get_basic(iter, &longerBool);
|
dbus_message_iter_get_basic(iter, &longerBool);
|
||||||
|
@ -232,8 +241,10 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
readIterTuple!T(&sub, ret);
|
readIterTuple!T(&sub, ret);
|
||||||
} else static if (is(T t : U[], U)) {
|
} else static if (is(T t : U[], U)) {
|
||||||
assert(dbus_message_iter_get_element_type(iter) == typeCode!U);
|
assert(dbus_message_iter_get_element_type(iter) == typeCode!U);
|
||||||
|
|
||||||
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(U == DictionaryEntry!(K, V), K, V)) {
|
||||||
DBusMessageIter entry;
|
DBusMessageIter entry;
|
||||||
|
@ -249,8 +260,7 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
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)) {
|
} else static if (isInstanceOf!(VariantN, T)) {
|
||||||
scope const(char)[] argSig =
|
scope const(char)[] argSig = dbus_message_iter_get_signature(iter).fromStringz();
|
||||||
dbus_message_iter_get_signature(iter).fromStringz();
|
|
||||||
scope (exit)
|
scope (exit)
|
||||||
dbus_free(cast(void*) argSig.ptr);
|
dbus_free(cast(void*) argSig.ptr);
|
||||||
|
|
||||||
|
@ -270,6 +280,7 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
} 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);
|
||||||
|
|
||||||
while (dbus_message_iter_get_arg_type(&sub) != 0) {
|
while (dbus_message_iter_get_arg_type(&sub) != 0) {
|
||||||
DBusMessageIter entry;
|
DBusMessageIter entry;
|
||||||
dbus_message_iter_recurse(&sub, &entry);
|
dbus_message_iter_recurse(&sub, &entry);
|
||||||
|
@ -281,6 +292,7 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
} else static if (is(T == DBusAny)) {
|
} else static if (is(T == DBusAny)) {
|
||||||
ret.type = argType;
|
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);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -298,7 +310,7 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
auto sig = dbus_message_iter_get_signature(&sub);
|
auto sig = dbus_message_iter_get_signature(&sub);
|
||||||
ret.signature = sig.fromStringz.dup;
|
ret.signature = sig.fromStringz.dup;
|
||||||
dbus_free(sig);
|
dbus_free(sig);
|
||||||
if (ret.signature == ['y'])
|
if (ret.signature == ['y']) {
|
||||||
while (dbus_message_iter_get_arg_type(&sub) != 0) {
|
while (dbus_message_iter_get_arg_type(&sub) != 0) {
|
||||||
ubyte b;
|
ubyte b;
|
||||||
assert(dbus_message_iter_get_arg_type(&sub) == 'y');
|
assert(dbus_message_iter_get_arg_type(&sub) == 'y');
|
||||||
|
@ -306,22 +318,26 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
dbus_message_iter_next(&sub);
|
dbus_message_iter_next(&sub);
|
||||||
ret.binaryData ~= b;
|
ret.binaryData ~= b;
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
while (dbus_message_iter_get_arg_type(&sub) != 0) {
|
while (dbus_message_iter_get_arg_type(&sub) != 0) {
|
||||||
ret.array ~= readIter!DBusAny(&sub);
|
ret.array ~= readIter!DBusAny(&sub);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if (ret.type == 'r') {
|
} else if (ret.type == 'r') {
|
||||||
auto sig = dbus_message_iter_get_signature(iter);
|
auto sig = dbus_message_iter_get_signature(iter);
|
||||||
ret.signature = sig.fromStringz.dup;
|
ret.signature = sig.fromStringz.dup;
|
||||||
dbus_free(sig);
|
dbus_free(sig);
|
||||||
|
|
||||||
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) {
|
||||||
ret.tuple ~= readIter!DBusAny(&sub);
|
ret.tuple ~= readIter!DBusAny(&sub);
|
||||||
}
|
}
|
||||||
} else if (ret.type == 'e') {
|
} else if (ret.type == 'e') {
|
||||||
DBusMessageIter sub;
|
DBusMessageIter sub;
|
||||||
dbus_message_iter_recurse(iter, &sub);
|
dbus_message_iter_recurse(iter, &sub);
|
||||||
|
|
||||||
ret.entry = new DictionaryEntry!(DBusAny, DBusAny);
|
ret.entry = new DictionaryEntry!(DBusAny, DBusAny);
|
||||||
ret.entry.key = readIter!DBusAny(&sub);
|
ret.entry.key = readIter!DBusAny(&sub);
|
||||||
ret.entry.value = readIter!DBusAny(&sub);
|
ret.entry.value = readIter!DBusAny(&sub);
|
||||||
|
@ -338,14 +354,15 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && allCanDBus!(Tup.Types)) {
|
void readIterTuple(Tup)(DBusMessageIter* iter, ref Tup tuple)
|
||||||
|
if (isTuple!Tup && allCanDBus!(Tup.Types)) {
|
||||||
foreach (index, T; Tup.Types) {
|
foreach (index, T; Tup.Types) {
|
||||||
tuple[index] = readIter!T(iter);
|
tuple[index] = readIter!T(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void readIterStruct(S)(DBusMessageIter *iter, ref S s) if(is(S == struct) && canDBus!S)
|
void readIterStruct(S)(DBusMessageIter* iter, ref S s)
|
||||||
{
|
if (is(S == struct) && canDBus!S) {
|
||||||
foreach (index, T; Fields!S) {
|
foreach (index, T; Fields!S) {
|
||||||
static if (isAllowedField!(s.tupleof[index])) {
|
static if (isAllowedField!(s.tupleof[index])) {
|
||||||
s.tupleof[index] = readIter!T(iter);
|
s.tupleof[index] = readIter!T(iter);
|
||||||
|
@ -356,7 +373,11 @@ void readIterStruct(S)(DBusMessageIter *iter, ref S s) if(is(S == struct) && can
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
import ddbus.thin;
|
import ddbus.thin;
|
||||||
Variant!T var(T)(T data){ return Variant!T(data); }
|
|
||||||
|
Variant!T var(T)(T data) {
|
||||||
|
return Variant!T(data);
|
||||||
|
}
|
||||||
|
|
||||||
Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth");
|
Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth");
|
||||||
bool[] emptyB;
|
bool[] emptyB;
|
||||||
string[string] map;
|
string[string] map;
|
||||||
|
@ -365,18 +386,18 @@ unittest {
|
||||||
anyVar.type.assertEqual('t');
|
anyVar.type.assertEqual('t');
|
||||||
anyVar.uint64.assertEqual(1561);
|
anyVar.uint64.assertEqual(1561);
|
||||||
anyVar.explicitVariant.assertEqual(false);
|
anyVar.explicitVariant.assertEqual(false);
|
||||||
auto tupleMember = DBusAny(tuple(Variant!int(45), Variant!ushort(5), 32, [1, 2], tuple(variant(4), 5), map));
|
auto tupleMember = DBusAny(tuple(Variant!int(45), Variant!ushort(5), 32,
|
||||||
Variant!DBusAny complexVar = variant(DBusAny([
|
[1, 2], tuple(variant(4), 5), map));
|
||||||
"hello world": variant(DBusAny(1337)),
|
Variant!DBusAny complexVar = variant(DBusAny(["hello world" : variant(DBusAny(1337)),
|
||||||
"array value": variant(DBusAny([42, 64])),
|
"array value" : variant(DBusAny([42, 64])), "tuple value"
|
||||||
"tuple value": variant(tupleMember),
|
: variant(tupleMember), "optimized binary data"
|
||||||
"optimized binary data": variant(DBusAny(cast(ubyte[]) [1, 2, 3, 4, 5, 6]))
|
: variant(DBusAny(cast(ubyte[])[1, 2, 3, 4, 5, 6]))]));
|
||||||
]));
|
|
||||||
complexVar.data.type.assertEqual('a');
|
complexVar.data.type.assertEqual('a');
|
||||||
complexVar.data.signature.assertEqual("{sv}".dup);
|
complexVar.data.signature.assertEqual("{sv}".dup);
|
||||||
tupleMember.signature.assertEqual("(vviai(vi)a{ss})");
|
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);
|
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.build(args.expand);
|
||||||
msg.signature().assertEqual("ibsvai(diaasabv)a{ss}tv");
|
msg.signature().assertEqual("ibsvai(diaasabv)a{ss}tv");
|
||||||
|
|
||||||
|
@ -392,7 +413,8 @@ unittest {
|
||||||
readIter!string(&iter).assertEqual("wow");
|
readIter!string(&iter).assertEqual("wow");
|
||||||
readIter!double(&iter).assertEqual(5.9);
|
readIter!double(&iter).assertEqual(5.9);
|
||||||
readIter!(int[])(&iter).assertEqual([6, 5]);
|
readIter!(int[])(&iter).assertEqual([6, 5]);
|
||||||
readIter!(Tuple!(double,int,string[][],bool[],Variant!(int[])))(&iter).assertEqual(tuple(6.2,4,[["lol"]],emptyB,var([4,2])));
|
readIter!(Tuple!(double, int, string[][], bool[], Variant!(int[])))(&iter).assertEqual(
|
||||||
|
tuple(6.2, 4, [["lol"]], emptyB, var([4, 2])));
|
||||||
|
|
||||||
// There are two ways to read a dictionary, so duplicate the iterator to test both.
|
// There are two ways to read a dictionary, so duplicate the iterator to test both.
|
||||||
auto iter2 = iter;
|
auto iter2 = iter;
|
||||||
|
@ -412,8 +434,18 @@ unittest {
|
||||||
|
|
||||||
import std.variant : Algebraic;
|
import std.variant : Algebraic;
|
||||||
|
|
||||||
enum E : int { a, b, c }
|
enum E : int {
|
||||||
enum F : uint { x = 1, y = 2, z = 4 }
|
a,
|
||||||
|
b,
|
||||||
|
c
|
||||||
|
}
|
||||||
|
|
||||||
|
enum F : uint {
|
||||||
|
x = 1,
|
||||||
|
y = 2,
|
||||||
|
z = 4
|
||||||
|
}
|
||||||
|
|
||||||
alias V = Algebraic!(byte, short, int, long, string);
|
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");
|
||||||
|
@ -437,4 +469,3 @@ unittest {
|
||||||
readIter!V(&iter).assertEqual(v1);
|
readIter!V(&iter).assertEqual(v1);
|
||||||
readIter!short(&iter).assertEqual(v2.get!short);
|
readIter!short(&iter).assertEqual(v2.get!short);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,12 +2,8 @@ module ddbus.exception;
|
||||||
|
|
||||||
import ddbus.c_lib;
|
import ddbus.c_lib;
|
||||||
|
|
||||||
package T wrapErrors(T)(
|
package T wrapErrors(T)(T delegate(DBusError* err) del, string file = __FILE__,
|
||||||
T delegate(DBusError *err) del,
|
size_t line = __LINE__, Throwable next = null) {
|
||||||
string file = __FILE__,
|
|
||||||
size_t line = __LINE__,
|
|
||||||
Throwable next = null
|
|
||||||
) {
|
|
||||||
DBusError error;
|
DBusError error;
|
||||||
dbus_error_init(&error);
|
dbus_error_init(&error);
|
||||||
T ret = del(&error);
|
T ret = del(&error);
|
||||||
|
@ -23,12 +19,8 @@ package T wrapErrors(T)(
|
||||||
Thrown when a DBus error code was returned by libdbus.
|
Thrown when a DBus error code was returned by libdbus.
|
||||||
+/
|
+/
|
||||||
class DBusException : Exception {
|
class DBusException : Exception {
|
||||||
private this(
|
private this(scope DBusError* err, string file = __FILE__,
|
||||||
scope DBusError *err,
|
size_t line = __LINE__, Throwable next = null) pure nothrow {
|
||||||
string file = __FILE__,
|
|
||||||
size_t line = __LINE__,
|
|
||||||
Throwable next = null
|
|
||||||
) pure nothrow {
|
|
||||||
import std.string : fromStringz;
|
import std.string : fromStringz;
|
||||||
|
|
||||||
super(err.message.fromStringz().idup, file, line, next);
|
super(err.message.fromStringz().idup, file, line, next);
|
||||||
|
@ -41,37 +33,27 @@ class DBusException : Exception {
|
||||||
of its actual value.
|
of its actual value.
|
||||||
+/
|
+/
|
||||||
class TypeMismatchException : Exception {
|
class TypeMismatchException : Exception {
|
||||||
package this(
|
package this(int expectedType, int actualType, string file = __FILE__,
|
||||||
int expectedType,
|
size_t line = __LINE__, Throwable next = null) pure nothrow @safe {
|
||||||
int actualType,
|
|
||||||
string file = __FILE__,
|
|
||||||
size_t line = __LINE__,
|
|
||||||
Throwable next = null
|
|
||||||
) pure nothrow @safe {
|
|
||||||
string message;
|
string message;
|
||||||
|
|
||||||
|
// dfmt off
|
||||||
if (expectedType == 'v') {
|
if (expectedType == 'v') {
|
||||||
message = "The type of value at the current position in the message is"
|
message = "The type of value at the current position in the message is"
|
||||||
~ " incompatible to the target variant type."
|
~ " incompatible to the target variant type." ~ " Type code of the value: '"
|
||||||
~ " Type code of the value: '" ~ cast(char) actualType ~ '\'';
|
~ cast(char) actualType ~ '\'';
|
||||||
} else {
|
} else {
|
||||||
message = "The type of value at the current position in the message does"
|
message = "The type of value at the current position in the message does"
|
||||||
~ " not match the type of value to be read."
|
~ " not match the type of value to be read." ~ " Expected: '"
|
||||||
~ " Expected: '" ~ cast(char) expectedType ~ "',"
|
~ cast(char) expectedType ~ "'," ~ " Got: '" ~ cast(char) actualType ~ '\'';
|
||||||
~ " Got: '" ~ cast(char) actualType ~ '\'';
|
|
||||||
}
|
}
|
||||||
|
// dfmt on
|
||||||
|
|
||||||
this(message, expectedType, actualType, file, line, next);
|
this(message, expectedType, actualType, file, line, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
this(
|
this(string message, int expectedType, int actualType, string file = __FILE__,
|
||||||
string message,
|
size_t line = __LINE__, Throwable next = null) pure nothrow @safe {
|
||||||
int expectedType,
|
|
||||||
int actualType,
|
|
||||||
string file = __FILE__,
|
|
||||||
size_t line = __LINE__,
|
|
||||||
Throwable next = null
|
|
||||||
) pure nothrow @safe {
|
|
||||||
_expectedType = expectedType;
|
_expectedType = expectedType;
|
||||||
_actualType = actualType;
|
_actualType = actualType;
|
||||||
super(message, file, line, next);
|
super(message, file, line, next);
|
||||||
|
@ -98,19 +80,15 @@ class TypeMismatchException : Exception {
|
||||||
that have a constrained value set, such as Enums.
|
that have a constrained value set, such as Enums.
|
||||||
+/
|
+/
|
||||||
class InvalidValueException : Exception {
|
class InvalidValueException : Exception {
|
||||||
package this(Source)(
|
package this(Source)(Source value, string targetType, string file = __FILE__,
|
||||||
Source value,
|
size_t line = __LINE__, Throwable next = null) {
|
||||||
string targetType,
|
|
||||||
string file = __FILE__,
|
|
||||||
size_t line = __LINE__,
|
|
||||||
Throwable next = null
|
|
||||||
) {
|
|
||||||
import std.conv : to;
|
import std.conv : to;
|
||||||
|
|
||||||
static if(__traits(compiles, value.to!string))
|
static if (__traits(compiles, value.to!string)) {
|
||||||
string valueString = value.to!string;
|
string valueString = value.to!string;
|
||||||
else
|
} else {
|
||||||
string valueString = "(unprintable)";
|
string valueString = "(unprintable)";
|
||||||
|
}
|
||||||
|
|
||||||
super("Value " ~ valueString ~ " cannot be represented in type " ~ targetType);
|
super("Value " ~ valueString ~ " cannot be represented in type " ~ targetType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,13 +40,14 @@ struct MessagePattern {
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool opEquals(ref const this s) const @safe pure nothrow {
|
bool opEquals(ref const typeof(this) s) const @safe pure nothrow {
|
||||||
return (path == s.path) && (iface == s.iface) && (method == s.method) && (signal == s.signal);
|
return (path == s.path) && (iface == s.iface) && (method == s.method) && (signal == s.signal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
auto msg = Message("org.example.test", "/test", "org.example.testing", "testMethod");
|
auto msg = Message("org.example.test", "/test", "org.example.testing", "testMethod");
|
||||||
auto patt = new MessagePattern(msg);
|
auto patt = new MessagePattern(msg);
|
||||||
patt.assertEqual(patt);
|
patt.assertEqual(patt);
|
||||||
|
@ -66,19 +67,23 @@ class MessageRouter {
|
||||||
|
|
||||||
bool handle(Message msg, Connection conn) {
|
bool handle(Message msg, Connection conn) {
|
||||||
MessageType type = msg.type();
|
MessageType type = msg.type();
|
||||||
if(type != MessageType.Call && type != MessageType.Signal)
|
if (type != MessageType.Call && type != MessageType.Signal) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto pattern = MessagePattern(msg);
|
auto pattern = MessagePattern(msg);
|
||||||
// import std.stdio; debug writeln("Handling ", pattern);
|
// import std.stdio; debug writeln("Handling ", pattern);
|
||||||
|
|
||||||
if(pattern.iface == "org.freedesktop.DBus.Introspectable" &&
|
if (pattern.iface == "org.freedesktop.DBus.Introspectable"
|
||||||
pattern.method == "Introspect" && !pattern.signal) {
|
&& pattern.method == "Introspect" && !pattern.signal) {
|
||||||
handleIntrospect(pattern.path, msg, conn);
|
handleIntrospect(pattern.path, msg, conn);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageHandler* handler = (pattern in callTable);
|
MessageHandler* handler = (pattern in callTable);
|
||||||
if(handler is null) return false;
|
if (handler is null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Check for matching argument types
|
// Check for matching argument types
|
||||||
version (DDBusNoChecking) {
|
version (DDBusNoChecking) {
|
||||||
|
@ -97,25 +102,39 @@ class MessageRouter {
|
||||||
void handlerWrapper(Message call, Connection conn) {
|
void handlerWrapper(Message call, Connection conn) {
|
||||||
Tuple!Args args = call.readTuple!(Tuple!Args)();
|
Tuple!Args args = call.readTuple!(Tuple!Args)();
|
||||||
auto retMsg = call.createReturn();
|
auto retMsg = call.createReturn();
|
||||||
|
|
||||||
static if (!is(Ret == void)) {
|
static if (!is(Ret == void)) {
|
||||||
Ret ret = handler(args.expand);
|
Ret ret = handler(args.expand);
|
||||||
static if (is(Ret == Tuple!T, T...))
|
static if (is(Ret == Tuple!T, T...)) {
|
||||||
retMsg.build!T(ret.expand);
|
retMsg.build!T(ret.expand);
|
||||||
else
|
} else {
|
||||||
retMsg.build(ret);
|
retMsg.build(ret);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
handler(args.expand);
|
handler(args.expand);
|
||||||
}
|
}
|
||||||
if(!patt.signal)
|
|
||||||
|
if (!patt.signal) {
|
||||||
conn.send(retMsg);
|
conn.send(retMsg);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static string[] args = typeSigArr!Args;
|
static string[] args = typeSigArr!Args;
|
||||||
|
|
||||||
static if (is(Ret == void)) {
|
static if (is(Ret == void)) {
|
||||||
static string[] ret = [];
|
static string[] ret = [];
|
||||||
} else {
|
} else {
|
||||||
static string[] ret = typeSigReturn!Ret;
|
static string[] ret = typeSigReturn!Ret;
|
||||||
}
|
}
|
||||||
MessageHandler handleStruct = {func: &handlerWrapper, argSig: args, retSig: ret};
|
|
||||||
|
// dfmt off
|
||||||
|
MessageHandler handleStruct = {
|
||||||
|
func: &handlerWrapper,
|
||||||
|
argSig: args,
|
||||||
|
retSig: ret
|
||||||
|
};
|
||||||
|
// dfmt on
|
||||||
|
|
||||||
callTable[patt] = handleStruct;
|
callTable[patt] = handleStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,25 +142,35 @@ class MessageRouter {
|
||||||
<node name="%s">`;
|
<node name="%s">`;
|
||||||
|
|
||||||
string introspectXML(string path) {
|
string introspectXML(string path) {
|
||||||
auto methods = callTable.byKey().filter!(a => (a.path == path) && !a.signal)().array()
|
// dfmt off
|
||||||
// .schwartzSort!((a) => a.iface, "a<b")();
|
auto methods = callTable
|
||||||
|
.byKey()
|
||||||
|
.filter!(a => (a.path == path) && !a.signal)
|
||||||
|
.array
|
||||||
.sort!((a, b) => a.iface < b.iface)();
|
.sort!((a, b) => a.iface < b.iface)();
|
||||||
|
// dfmt on
|
||||||
|
|
||||||
auto ifaces = methods.groupBy();
|
auto ifaces = methods.groupBy();
|
||||||
auto app = appender!string;
|
auto app = appender!string;
|
||||||
formattedWrite(app, introspectHeader, path);
|
formattedWrite(app, introspectHeader, path);
|
||||||
foreach (iface; ifaces) {
|
foreach (iface; ifaces) {
|
||||||
formattedWrite(app, `<interface name="%s">`, iface.front.iface);
|
formattedWrite(app, `<interface name="%s">`, iface.front.iface);
|
||||||
|
|
||||||
foreach (methodPatt; iface.array()) {
|
foreach (methodPatt; iface.array()) {
|
||||||
formattedWrite(app, `<method name="%s">`, methodPatt.method);
|
formattedWrite(app, `<method name="%s">`, methodPatt.method);
|
||||||
auto handler = callTable[methodPatt];
|
auto handler = callTable[methodPatt];
|
||||||
|
|
||||||
foreach (arg; handler.argSig) {
|
foreach (arg; handler.argSig) {
|
||||||
formattedWrite(app, `<arg type="%s" direction="in"/>`, arg);
|
formattedWrite(app, `<arg type="%s" direction="in"/>`, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (arg; handler.retSig) {
|
foreach (arg; handler.retSig) {
|
||||||
formattedWrite(app, `<arg type="%s" direction="out"/>`, arg);
|
formattedWrite(app, `<arg type="%s" direction="out"/>`, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.put("</method>");
|
app.put("</method>");
|
||||||
}
|
}
|
||||||
|
|
||||||
app.put("</interface>");
|
app.put("</interface>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,10 +178,12 @@ class MessageRouter {
|
||||||
if (!childPath.endsWith("/")) {
|
if (!childPath.endsWith("/")) {
|
||||||
childPath ~= "/";
|
childPath ~= "/";
|
||||||
}
|
}
|
||||||
auto children = callTable.byKey().filter!(a => (a.path.startsWith(childPath)) && !a.signal)()
|
|
||||||
.map!((s) => s.path.chompPrefix(childPath))
|
auto children = callTable.byKey()
|
||||||
.map!((s) => s.splitter('/').front)
|
.filter!(a => (a.path.startsWith(childPath)) && !a.signal)().map!(
|
||||||
.array().sort().uniq();
|
(s) => s.path.chompPrefix(childPath)).map!((s) => s.splitter('/')
|
||||||
|
.front).array().sort().uniq();
|
||||||
|
|
||||||
foreach (child; children) {
|
foreach (child; children) {
|
||||||
formattedWrite(app, `<node name="%s"/>`, child);
|
formattedWrite(app, `<node name="%s"/>`, child);
|
||||||
}
|
}
|
||||||
|
@ -168,13 +199,15 @@ class MessageRouter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern(C) private DBusHandlerResult filterFunc(DBusConnection *dConn, DBusMessage *dMsg, void *routerP) {
|
extern (C) private DBusHandlerResult filterFunc(DBusConnection* dConn,
|
||||||
|
DBusMessage* dMsg, void* routerP) {
|
||||||
MessageRouter router = cast(MessageRouter) routerP;
|
MessageRouter router = cast(MessageRouter) routerP;
|
||||||
dbus_message_ref(dMsg);
|
dbus_message_ref(dMsg);
|
||||||
Message msg = Message(dMsg);
|
Message msg = Message(dMsg);
|
||||||
dbus_connection_ref(dConn);
|
dbus_connection_ref(dConn);
|
||||||
Connection conn = Connection(dConn);
|
Connection conn = Connection(dConn);
|
||||||
bool handled = router.handle(msg, conn);
|
bool handled = router.handle(msg, conn);
|
||||||
|
|
||||||
if (handled) {
|
if (handled) {
|
||||||
return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED;
|
return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED;
|
||||||
} else {
|
} else {
|
||||||
|
@ -207,24 +240,46 @@ unittest{
|
||||||
patt = MessagePattern("/root/wat", "ca.thume.tester", "lolwut");
|
patt = MessagePattern("/root/wat", "ca.thume.tester", "lolwut");
|
||||||
router.setHandler!(int, int)(patt, (int p) { return 6; });
|
router.setHandler!(int, int)(patt, (int p) { return 6; });
|
||||||
patt = MessagePattern("/root/bar", "ca.thume.tester", "lolwut");
|
patt = MessagePattern("/root/bar", "ca.thume.tester", "lolwut");
|
||||||
router.setHandler!(Variant!DBusAny,int)(patt,(int p) {return variant(DBusAny(p));});
|
router.setHandler!(Variant!DBusAny, int)(patt, (int p) {
|
||||||
|
return variant(DBusAny(p));
|
||||||
|
});
|
||||||
patt = MessagePattern("/root/foo", "ca.thume.tester", "lolwut");
|
patt = MessagePattern("/root/foo", "ca.thume.tester", "lolwut");
|
||||||
router.setHandler!(Tuple!(string,string,int),int,Variant!DBusAny)(patt,(int p, Variant!DBusAny any) {Tuple!(string,string,int) ret; ret[0] = "a"; ret[1] = "b"; ret[2] = p; return ret;});
|
router.setHandler!(Tuple!(string, string, int), int,
|
||||||
|
Variant!DBusAny)(patt, (int p, Variant!DBusAny any) {
|
||||||
|
Tuple!(string, string, int) ret;
|
||||||
|
ret[0] = "a";
|
||||||
|
ret[1] = "b";
|
||||||
|
ret[2] = p;
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
patt = MessagePattern("/troll", "ca.thume.tester", "wow");
|
patt = MessagePattern("/troll", "ca.thume.tester", "wow");
|
||||||
router.setHandler!(void)(patt, { return; });
|
router.setHandler!(void)(patt, { return; });
|
||||||
|
|
||||||
patt = MessagePattern("/root/fancy", "ca.thume.tester", "crazyTest");
|
patt = MessagePattern("/root/fancy", "ca.thume.tester", "crazyTest");
|
||||||
enum F : ushort { a = 1, b = 8, c = 16 }
|
enum F : ushort {
|
||||||
struct S { byte b; ulong ul; F f; }
|
a = 1,
|
||||||
|
b = 8,
|
||||||
|
c = 16
|
||||||
|
}
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
byte b;
|
||||||
|
ulong ul;
|
||||||
|
F f;
|
||||||
|
}
|
||||||
|
|
||||||
router.setHandler!(int)(patt, (Algebraic!(ushort, BitFlags!F, S) v) {
|
router.setHandler!(int)(patt, (Algebraic!(ushort, BitFlags!F, S) v) {
|
||||||
if (v.type is typeid(ushort) || v.type is typeid(BitFlags!F)) {
|
if (v.type is typeid(ushort) || v.type is typeid(BitFlags!F)) {
|
||||||
return v.coerce!int;
|
return v.coerce!int;
|
||||||
} else if (v.type is typeid(S)) {
|
} else if (v.type is typeid(S)) {
|
||||||
auto s = v.get!S;
|
auto s = v.get!S;
|
||||||
final switch (s.f) {
|
final switch (s.f) {
|
||||||
case F.a: return s.b;
|
case F.a:
|
||||||
case F.b: return cast(int) s.ul;
|
return s.b;
|
||||||
case F.c: return cast(int) s.ul + s.b;
|
case F.b:
|
||||||
|
return cast(int) s.ul;
|
||||||
|
case F.c:
|
||||||
|
return cast(int) s.ul + s.b;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,5 +301,6 @@ unittest{
|
||||||
static string introspectResult3 = `<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
static string introspectResult3 = `<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
<node name="/root/fancy"><interface name="ca.thume.tester"><method name="crazyTest"><arg type="v" direction="in"/><arg type="i" direction="out"/></method></interface></node>`;
|
<node name="/root/fancy"><interface name="ca.thume.tester"><method name="crazyTest"><arg type="v" direction="in"/><arg type="i" direction="out"/></method></interface></node>`;
|
||||||
router.introspectXML("/root/fancy").assertEqual(introspectResult3);
|
router.introspectXML("/root/fancy").assertEqual(introspectResult3);
|
||||||
router.introspectXML("/").assertEndsWith(`<node name="/"><node name="root"/><node name="troll"/></node>`);
|
router.introspectXML("/")
|
||||||
|
.assertEndsWith(`<node name="/"><node name="root"/><node name="troll"/></node>`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,8 @@ class PathIface {
|
||||||
this.iface = iface.toStringz();
|
this.iface = iface.toStringz();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ret call(Ret, Args...)(string meth, Args args) if(allCanDBus!Args && canDBus!Ret) {
|
Ret call(Ret, Args...)(string meth, Args args)
|
||||||
|
if (allCanDBus!Args && canDBus!Ret) {
|
||||||
Message msg = Message(dbus_message_new_method_call(dest, path, iface, meth.toStringz()));
|
Message msg = Message(dbus_message_new_method_call(dest, path, iface, meth.toStringz()));
|
||||||
msg.build(args);
|
msg.build(args);
|
||||||
Message ret = conn.sendWithReplyBlocking(msg);
|
Message ret = conn.sendWithReplyBlocking(msg);
|
||||||
|
@ -40,9 +41,10 @@ class PathIface {
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
Connection conn = connectToBus();
|
Connection conn = connectToBus();
|
||||||
PathIface obj = new PathIface(conn, "org.freedesktop.DBus","/org/freedesktop/DBus",
|
PathIface obj = new PathIface(conn, "org.freedesktop.DBus",
|
||||||
"org.freedesktop.DBus");
|
"/org/freedesktop/DBus", "org.freedesktop.DBus");
|
||||||
auto names = obj.GetNameOwner("org.freedesktop.DBus").to!string();
|
auto names = obj.GetNameOwner("org.freedesktop.DBus").to!string();
|
||||||
names.assertEqual("org.freedesktop.DBus");
|
names.assertEqual("org.freedesktop.DBus");
|
||||||
obj.call!string("GetNameOwner", "org.freedesktop.DBus").assertEqual("org.freedesktop.DBus");
|
obj.call!string("GetNameOwner", "org.freedesktop.DBus").assertEqual("org.freedesktop.DBus");
|
||||||
|
@ -65,6 +67,7 @@ enum SignalMethod;
|
||||||
void registerMethods(T : Object)(MessageRouter router, string path, string iface, T obj) {
|
void registerMethods(T : Object)(MessageRouter router, string path, string iface, T obj) {
|
||||||
MessagePattern patt = MessagePattern(path, iface, "", false);
|
MessagePattern patt = MessagePattern(path, iface, "", false);
|
||||||
foreach (member; __traits(allMembers, T)) {
|
foreach (member; __traits(allMembers, T)) {
|
||||||
|
// dfmt off
|
||||||
static if (__traits(compiles, __traits(getOverloads, obj, member))
|
static if (__traits(compiles, __traits(getOverloads, obj, member))
|
||||||
&& __traits(getOverloads, obj, member).length > 0
|
&& __traits(getOverloads, obj, member).length > 0
|
||||||
&& __traits(compiles, router.setHandler(patt, &__traits(getOverloads, obj, member)[0]))) {
|
&& __traits(compiles, router.setHandler(patt, &__traits(getOverloads, obj, member)[0]))) {
|
||||||
|
@ -72,17 +75,25 @@ void registerMethods(T : Object)(MessageRouter router, string path, string iface
|
||||||
patt.signal = hasUDA!(__traits(getOverloads, obj, member)[0], SignalMethod);
|
patt.signal = hasUDA!(__traits(getOverloads, obj, member)[0], SignalMethod);
|
||||||
router.setHandler(patt, &__traits(getOverloads, obj, member)[0]);
|
router.setHandler(patt, &__traits(getOverloads, obj, member)[0]);
|
||||||
}
|
}
|
||||||
|
// dfmt on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
class Tester {
|
class Tester {
|
||||||
int lol(int x, string s, string[string] map, Variant!DBusAny any) {return 5;}
|
int lol(int x, string s, string[string] map, Variant!DBusAny any) {
|
||||||
void wat() {}
|
return 5;
|
||||||
@SignalMethod
|
|
||||||
void signalRecv() {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wat() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@SignalMethod void signalRecv() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto o = new Tester;
|
auto o = new Tester;
|
||||||
auto router = new MessageRouter;
|
auto router = new MessageRouter;
|
||||||
registerMethods(router, "/", "ca.thume.test", o);
|
registerMethods(router, "/", "ca.thume.test", o);
|
||||||
|
|
|
@ -48,24 +48,28 @@ struct ObjectPath {
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectPath opBinary(string op : "~")(string rhs) const pure @safe {
|
ObjectPath opBinary(string op : "~")(string rhs) const pure @safe {
|
||||||
if (!rhs.startsWith("/"))
|
if (!rhs.startsWith("/")) {
|
||||||
return opBinary!"~"(ObjectPath("/" ~ rhs));
|
return opBinary!"~"(ObjectPath("/" ~ rhs));
|
||||||
else
|
} else {
|
||||||
return opBinary!"~"(ObjectPath(rhs));
|
return opBinary!"~"(ObjectPath(rhs));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ObjectPath opBinary(string op : "~")(ObjectPath rhs) const pure @safe
|
ObjectPath opBinary(string op : "~")(ObjectPath rhs) const pure @safe
|
||||||
in {
|
in {
|
||||||
assert(ObjectPath.isValid(_value) && ObjectPath.isValid(rhs._value));
|
assert(ObjectPath.isValid(_value) && ObjectPath.isValid(rhs._value));
|
||||||
} out (v) {
|
}
|
||||||
|
out (v) {
|
||||||
assert(ObjectPath.isValid(v._value));
|
assert(ObjectPath.isValid(v._value));
|
||||||
} body {
|
}
|
||||||
|
body {
|
||||||
ObjectPath ret;
|
ObjectPath ret;
|
||||||
|
|
||||||
if (_value == "/")
|
if (_value == "/") {
|
||||||
ret._value = rhs._value;
|
ret._value = rhs._value;
|
||||||
else
|
} else {
|
||||||
ret._value = _value ~ rhs._value;
|
ret._value = _value ~ rhs._value;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -85,20 +89,21 @@ struct ObjectPath {
|
||||||
static bool isValid(string objPath) pure @nogc nothrow @safe {
|
static bool isValid(string objPath) pure @nogc nothrow @safe {
|
||||||
import std.ascii : isAlphaNum;
|
import std.ascii : isAlphaNum;
|
||||||
|
|
||||||
if (!objPath.length)
|
if (!objPath.length) {
|
||||||
return false;
|
return false;
|
||||||
if (objPath == "/")
|
}
|
||||||
|
|
||||||
|
if (objPath == "/") {
|
||||||
return true;
|
return true;
|
||||||
if (objPath[0] != '/' || objPath[$ - 1] == '/')
|
}
|
||||||
|
|
||||||
|
if (objPath[0] != '/' || objPath[$ - 1] == '/') {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// .representation to avoid unicode exceptions -> @nogc & nothrow
|
// .representation to avoid unicode exceptions -> @nogc & nothrow
|
||||||
return objPath.representation.splitter('/').drop(1)
|
return objPath.representation.splitter('/').drop(1).all!(a => a.length
|
||||||
.all!(a =>
|
&& a.all!(c => c.isAlphaNum || c == '_'));
|
||||||
a.length &&
|
|
||||||
a.all!(c =>
|
|
||||||
c.isAlphaNum || c == '_'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,8 +142,7 @@ struct DBusAny {
|
||||||
/// Same functionality as Variant!T but with dynamic types if true.
|
/// Same functionality as Variant!T but with dynamic types if true.
|
||||||
bool explicitVariant;
|
bool explicitVariant;
|
||||||
|
|
||||||
union
|
union {
|
||||||
{
|
|
||||||
///
|
///
|
||||||
byte int8;
|
byte int8;
|
||||||
///
|
///
|
||||||
|
@ -220,16 +224,18 @@ struct DBusAny {
|
||||||
signature = value.data.signature;
|
signature = value.data.signature;
|
||||||
explicitVariant = true;
|
explicitVariant = true;
|
||||||
if (type == 'a' || type == 'r') {
|
if (type == 'a' || type == 'r') {
|
||||||
if(signature == ['y'])
|
if (signature == ['y']) {
|
||||||
binaryData = value.data.binaryData;
|
binaryData = value.data.binaryData;
|
||||||
else
|
} else {
|
||||||
array = value.data.array;
|
array = value.data.array;
|
||||||
} else if(type == 's')
|
}
|
||||||
|
} else if (type == 's') {
|
||||||
str = value.data.str;
|
str = value.data.str;
|
||||||
else if(type == 'e')
|
} else if (type == 'e') {
|
||||||
entry = value.data.entry;
|
entry = value.data.entry;
|
||||||
else
|
} else {
|
||||||
uint64 = value.data.uint64;
|
uint64 = value.data.uint64;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this(value.data);
|
this(value.data);
|
||||||
explicitVariant = true;
|
explicitVariant = true;
|
||||||
|
@ -237,45 +243,61 @@ struct DBusAny {
|
||||||
} else static if (is(T : DictionaryEntry!(K, V), K, V)) {
|
} else static if (is(T : DictionaryEntry!(K, V), K, V)) {
|
||||||
this('e', null, false);
|
this('e', null, false);
|
||||||
entry = new DictionaryEntry!(DBusAny, DBusAny)();
|
entry = new DictionaryEntry!(DBusAny, DBusAny)();
|
||||||
static if(is(K == DBusAny))
|
static if (is(K == DBusAny)) {
|
||||||
entry.key = value.key;
|
entry.key = value.key;
|
||||||
else
|
} else {
|
||||||
entry.key = DBusAny(value.key);
|
entry.key = DBusAny(value.key);
|
||||||
static if(is(V == DBusAny))
|
}
|
||||||
|
static if (is(V == DBusAny)) {
|
||||||
entry.value = value.value;
|
entry.value = value.value;
|
||||||
else
|
} else {
|
||||||
entry.value = DBusAny(value.value);
|
entry.value = DBusAny(value.value);
|
||||||
|
}
|
||||||
} else static if (is(T == ubyte[]) || is(T == byte[])) {
|
} else static if (is(T == ubyte[]) || is(T == byte[])) {
|
||||||
this('a', ['y'], false);
|
this('a', ['y'], false);
|
||||||
binaryData = cast(ubyte[]) value;
|
binaryData = cast(ubyte[]) value;
|
||||||
} else static if (isInputRange!T) {
|
} else static if (isInputRange!T) {
|
||||||
this.type = 'a';
|
this.type = 'a';
|
||||||
static assert(!is(ElementType!T == DBusAny), "Array must consist of the same type, use Variant!DBusAny or DBusAny(tuple(...)) instead");
|
|
||||||
|
static assert(!is(ElementType!T == DBusAny),
|
||||||
|
"Array must consist of the same type, use Variant!DBusAny or DBusAny(tuple(...)) instead");
|
||||||
|
|
||||||
static assert(.typeSig!(ElementType!T) != "y");
|
static assert(.typeSig!(ElementType!T) != "y");
|
||||||
|
|
||||||
this.signature = .typeSig!(ElementType!T);
|
this.signature = .typeSig!(ElementType!T);
|
||||||
this.explicitVariant = false;
|
this.explicitVariant = false;
|
||||||
foreach(elem; value)
|
|
||||||
|
foreach (elem; value) {
|
||||||
array ~= DBusAny(elem);
|
array ~= DBusAny(elem);
|
||||||
|
}
|
||||||
} else static if (isTuple!T) {
|
} else static if (isTuple!T) {
|
||||||
this.type = 'r';
|
this.type = 'r';
|
||||||
this.signature = ['('];
|
this.signature = ['('];
|
||||||
this.explicitVariant = false;
|
this.explicitVariant = false;
|
||||||
|
|
||||||
foreach (index, R; value.Types) {
|
foreach (index, R; value.Types) {
|
||||||
auto var = DBusAny(value[index]);
|
auto var = DBusAny(value[index]);
|
||||||
tuple ~= var;
|
tuple ~= var;
|
||||||
if(var.explicitVariant)
|
|
||||||
|
if (var.explicitVariant) {
|
||||||
this.signature ~= 'v';
|
this.signature ~= 'v';
|
||||||
else {
|
} else {
|
||||||
if (var.type != 'r')
|
if (var.type != 'r') {
|
||||||
this.signature ~= cast(char) var.type;
|
this.signature ~= cast(char) var.type;
|
||||||
if(var.type == 'a' || var.type == 'r')
|
}
|
||||||
|
|
||||||
|
if (var.type == 'a' || var.type == 'r') {
|
||||||
this.signature ~= var.signature;
|
this.signature ~= var.signature;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.signature ~= ')';
|
this.signature ~= ')';
|
||||||
} else static if (isAssociativeArray!T) {
|
} else static if (isAssociativeArray!T) {
|
||||||
this(value.byDictionaryEntries);
|
this(value.byDictionaryEntries);
|
||||||
} else static assert(false, T.stringof ~ " not convertible to a Variant");
|
} else {
|
||||||
|
static assert(false, T.stringof ~ " not convertible to a Variant");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
|
@ -318,10 +340,12 @@ struct DBusAny {
|
||||||
case 'a':
|
case 'a':
|
||||||
import std.digest.digest : toHexString;
|
import std.digest.digest : toHexString;
|
||||||
|
|
||||||
if(signature == ['y'])
|
if (signature == ['y']) {
|
||||||
valueStr = "binary(" ~ binaryData.toHexString ~ ')';
|
valueStr = "binary(" ~ binaryData.toHexString ~ ')';
|
||||||
else
|
} else {
|
||||||
valueStr = '[' ~ array.map!(a => a.toString).join(", ") ~ ']';
|
valueStr = '[' ~ array.map!(a => a.toString).join(", ") ~ ']';
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
valueStr = '(' ~ tuple.map!(a => a.toString).join(", ") ~ ')';
|
valueStr = '(' ~ tuple.map!(a => a.toString).join(", ") ~ ')';
|
||||||
|
@ -333,10 +357,9 @@ struct DBusAny {
|
||||||
valueStr = "unknown";
|
valueStr = "unknown";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return "DBusAny(" ~ cast(char) type
|
|
||||||
~ ", \"" ~ signature.idup
|
return "DBusAny(" ~ cast(char) type ~ ", \"" ~ signature.idup ~ "\", " ~ (explicitVariant
|
||||||
~ "\", " ~ (explicitVariant ? "explicit" : "implicit")
|
? "explicit" : "implicit") ~ ", " ~ valueStr ~ ")";
|
||||||
~ ", " ~ valueStr ~ ")";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/++
|
/++
|
||||||
|
@ -354,16 +377,13 @@ struct DBusAny {
|
||||||
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
|
T get(T)() @property const
|
||||||
if(staticIndexOf!(T, BasicTypes) >= 0)
|
if (staticIndexOf!(T, BasicTypes) >= 0) {
|
||||||
{
|
enforce(type == typeCode!T, new TypeMismatchException(
|
||||||
enforce(type == typeCode!T,
|
"Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ typeSig ~ "'.",
|
||||||
new TypeMismatchException(
|
typeCode!T, type));
|
||||||
"Cannot get a " ~ T.stringof ~ " from a DBusAny with"
|
|
||||||
~ " a value of DBus type '" ~ typeSig ~ "'.", typeCode!T, type));
|
|
||||||
|
|
||||||
static if (isIntegral!T) {
|
static if (isIntegral!T) {
|
||||||
enum memberName =
|
enum memberName = (isUnsigned!T ? "uint" : "int") ~ (T.sizeof * 8).to!string;
|
||||||
(isUnsigned!T ? "uint" : "int") ~ (T.sizeof * 8).to!string;
|
|
||||||
return __traits(getMember, this, memberName);
|
return __traits(getMember, this, memberName);
|
||||||
} else static if (is(T == double)) {
|
} else static if (is(T == double)) {
|
||||||
return float64;
|
return float64;
|
||||||
|
@ -380,12 +400,9 @@ struct DBusAny {
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
T get(T)() @property const
|
T get(T)() @property const
|
||||||
if(is(T == const(DBusAny)[]))
|
if (is(T == const(DBusAny)[])) {
|
||||||
{
|
enforce((type == 'a' && signature != "y") || type == 'r', new TypeMismatchException(
|
||||||
enforce((type == 'a' && signature != "y") || type == 'r',
|
"Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ this.typeSig ~ "'.",
|
||||||
new TypeMismatchException(
|
|
||||||
"Cannot get a " ~ T.stringof ~ " from a DBusAny with"
|
|
||||||
~ " a value of DBus type '" ~ this.typeSig ~ "'.",
|
|
||||||
typeCode!T, type));
|
typeCode!T, type));
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
|
@ -393,12 +410,9 @@ struct DBusAny {
|
||||||
|
|
||||||
/// ditto
|
/// ditto
|
||||||
T get(T)() @property const
|
T get(T)() @property const
|
||||||
if (is(T == const(ubyte)[]))
|
if (is(T == const(ubyte)[])) {
|
||||||
{
|
enforce(type == 'a' && signature == "y", new TypeMismatchException(
|
||||||
enforce(type == 'a' && signature == "y",
|
"Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ this.typeSig ~ "'.",
|
||||||
new TypeMismatchException(
|
|
||||||
"Cannot get a " ~ T.stringof ~ " from a DBusAny with"
|
|
||||||
~ " a value of DBus type '" ~ this.typeSig ~ "'.",
|
|
||||||
typeCode!T, type));
|
typeCode!T, type));
|
||||||
|
|
||||||
return binaryData;
|
return binaryData;
|
||||||
|
@ -408,10 +422,12 @@ struct DBusAny {
|
||||||
DBusAny[DBusAny] toAA() {
|
DBusAny[DBusAny] toAA() {
|
||||||
enforce(type == 'a' && signature && signature[0] == '{');
|
enforce(type == 'a' && signature && signature[0] == '{');
|
||||||
DBusAny[DBusAny] aa;
|
DBusAny[DBusAny] aa;
|
||||||
|
|
||||||
foreach (val; array) {
|
foreach (val; array) {
|
||||||
enforce(val.type == 'e');
|
enforce(val.type == 'e');
|
||||||
aa[val.entry.key] = val.entry.value;
|
aa[val.entry.key] = val.entry.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
return aa;
|
return aa;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,8 +437,7 @@ struct DBusAny {
|
||||||
Returns:
|
Returns:
|
||||||
The type signature of the value stored in this DBusAny object.
|
The type signature of the value stored in this DBusAny object.
|
||||||
+/
|
+/
|
||||||
string typeSig() @property const pure nothrow @safe
|
string typeSig() @property const pure nothrow @safe {
|
||||||
{
|
|
||||||
if (type == 'a') {
|
if (type == 'a') {
|
||||||
return "a" ~ signature;
|
return "a" ~ signature;
|
||||||
} else if (type == 'r') {
|
} else if (type == 'r') {
|
||||||
|
@ -443,8 +458,9 @@ struct DBusAny {
|
||||||
auto v = to!R;
|
auto v = to!R;
|
||||||
v.explicitVariant = false;
|
v.explicitVariant = false;
|
||||||
return Variant!R(v);
|
return Variant!R(v);
|
||||||
} else
|
} else {
|
||||||
return Variant!R(to!R);
|
return Variant!R(to!R);
|
||||||
|
}
|
||||||
} else static if (is(T == DBusAny)) {
|
} else static if (is(T == DBusAny)) {
|
||||||
return this;
|
return this;
|
||||||
} else static if (isIntegral!T || isFloatingPoint!T) {
|
} else static if (isIntegral!T || isFloatingPoint!T) {
|
||||||
|
@ -469,78 +485,105 @@ struct DBusAny {
|
||||||
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
||||||
}
|
}
|
||||||
} else static if (is(T == bool)) {
|
} else static if (is(T == bool)) {
|
||||||
if(type == 'b')
|
if (type == 'b') {
|
||||||
return boolean;
|
return boolean;
|
||||||
else
|
} else {
|
||||||
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
||||||
|
}
|
||||||
} else static if (isSomeString!T) {
|
} else static if (isSomeString!T) {
|
||||||
if(type == 's')
|
if (type == 's') {
|
||||||
return str.to!T;
|
return str.to!T;
|
||||||
else if(type == 'o')
|
} else if (type == 'o') {
|
||||||
return obj.toString();
|
return obj.toString();
|
||||||
else
|
} else {
|
||||||
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
||||||
|
}
|
||||||
} else static if (is(T == ObjectPath)) {
|
} else static if (is(T == ObjectPath)) {
|
||||||
if(type == 'o')
|
if (type == 'o') {
|
||||||
return obj;
|
return obj;
|
||||||
else
|
} else {
|
||||||
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
||||||
|
}
|
||||||
} else static if (isDynamicArray!T) {
|
} else static if (isDynamicArray!T) {
|
||||||
if(type != 'a' && type != 'r')
|
if (type != 'a' && type != 'r') {
|
||||||
throw new Exception("Can't convert type " ~ cast(char) type ~ " to an array");
|
throw new Exception("Can't convert type " ~ cast(char) type ~ " to an array");
|
||||||
|
}
|
||||||
|
|
||||||
T ret;
|
T ret;
|
||||||
if (signature == ['y']) {
|
if (signature == ['y']) {
|
||||||
static if(isIntegral!(ElementType!T))
|
static if (isIntegral!(ElementType!T)) {
|
||||||
foreach(elem; binaryData)
|
foreach (elem; binaryData) {
|
||||||
ret ~= elem.to!(ElementType!T);
|
ret ~= elem.to!(ElementType!T);
|
||||||
} else
|
}
|
||||||
foreach(elem; array)
|
}
|
||||||
|
} else {
|
||||||
|
foreach (elem; array) {
|
||||||
ret ~= elem.to!(ElementType!T);
|
ret ~= elem.to!(ElementType!T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} else static if (isTuple!T) {
|
} else static if (isTuple!T) {
|
||||||
if(type != 'r')
|
if (type != 'r') {
|
||||||
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
||||||
|
}
|
||||||
|
|
||||||
T ret;
|
T ret;
|
||||||
enforce(ret.Types.length == tuple.length, "Tuple length mismatch");
|
enforce(ret.Types.length == tuple.length, "Tuple length mismatch");
|
||||||
foreach(index, T; ret.Types)
|
foreach (index, T; ret.Types) {
|
||||||
ret[index] = tuple[index].to!T;
|
ret[index] = tuple[index].to!T;
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} else static if (isAssociativeArray!T) {
|
} else static if (isAssociativeArray!T) {
|
||||||
if(type != 'a' || !signature || signature[0] != '{')
|
if (type != 'a' || !signature || signature[0] != '{') {
|
||||||
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof);
|
||||||
|
}
|
||||||
|
|
||||||
T ret;
|
T ret;
|
||||||
foreach (pair; array) {
|
foreach (pair; array) {
|
||||||
enforce(pair.type == 'e');
|
enforce(pair.type == 'e');
|
||||||
ret[pair.entry.key.to!(KeyType!T)] = pair.entry.value.to!(ValueType!T);
|
ret[pair.entry.key.to!(KeyType!T)] = pair.entry.value.to!(ValueType!T);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
} else static assert(false, "Can't convert variant to " ~ T.stringof);
|
} else {
|
||||||
|
static assert(false, "Can't convert variant to " ~ T.stringof);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool opEquals(ref in DBusAny b) const {
|
bool opEquals(ref in DBusAny b) const {
|
||||||
if(b.type != type || b.explicitVariant != explicitVariant)
|
if (b.type != type || b.explicitVariant != explicitVariant) {
|
||||||
return false;
|
return false;
|
||||||
if((type == 'a' || type == 'r') && b.signature != signature)
|
}
|
||||||
|
|
||||||
|
if ((type == 'a' || type == 'r') && b.signature != signature) {
|
||||||
return false;
|
return false;
|
||||||
if(type == 'a' && signature == ['y'])
|
}
|
||||||
|
|
||||||
|
if (type == 'a' && signature == ['y']) {
|
||||||
return binaryData == b.binaryData;
|
return binaryData == b.binaryData;
|
||||||
if(type == 'a')
|
}
|
||||||
|
|
||||||
|
if (type == 'a') {
|
||||||
return array == b.array;
|
return array == b.array;
|
||||||
else if(type == 'r')
|
} else if (type == 'r') {
|
||||||
return tuple == b.tuple;
|
return tuple == b.tuple;
|
||||||
else if(type == 's')
|
} else if (type == 's') {
|
||||||
return str == b.str;
|
return str == b.str;
|
||||||
else if(type == 'o')
|
} else if (type == 'o') {
|
||||||
return obj == b.obj;
|
return obj == b.obj;
|
||||||
else if(type == 'e')
|
} else if (type == 'e') {
|
||||||
return entry == b.entry || (entry && b.entry && *entry == *b.entry);
|
return entry == b.entry || (entry && b.entry && *entry == *b.entry);
|
||||||
else
|
} else {
|
||||||
return uint64 == b.uint64;
|
return uint64 == b.uint64;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
DBusAny set(string member, T)(DBusAny v, T value) {
|
DBusAny set(string member, T)(DBusAny v, T value) {
|
||||||
mixin("v." ~ member ~ " = value;");
|
mixin("v." ~ member ~ " = value;");
|
||||||
return v;
|
return v;
|
||||||
|
@ -550,12 +593,14 @@ unittest {
|
||||||
assertEqual(DBusAny(value), b);
|
assertEqual(DBusAny(value), b);
|
||||||
|
|
||||||
static if (is(T == Variant!R, R)) {
|
static if (is(T == Variant!R, R)) {
|
||||||
static if(__traits(compiles, b.get!R))
|
static if (__traits(compiles, b.get!R)) {
|
||||||
assertEqual(b.get!R, value.data);
|
assertEqual(b.get!R, value.data);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
static if(__traits(compiles, b.get!T))
|
static if (__traits(compiles, b.get!T)) {
|
||||||
assertEqual(b.get!T, value);
|
assertEqual(b.get!T, value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
assertEqual(b.to!T, value);
|
assertEqual(b.to!T, value);
|
||||||
b.toString();
|
b.toString();
|
||||||
|
@ -569,7 +614,8 @@ unittest {
|
||||||
test(cast(long) 184, set!"int64"(DBusAny('x', null, false), cast(long) 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(cast(ulong) 184, set!"uint64"(DBusAny('t', null, false), cast(ulong) 184));
|
||||||
test(true, set!"boolean"(DBusAny('b', null, false), true));
|
test(true, set!"boolean"(DBusAny('b', null, false), true));
|
||||||
test(cast(ubyte[]) [1, 2, 3], set!"binaryData"(DBusAny('a', ['y'], false), cast(ubyte[]) [1, 2, 3]));
|
test(cast(ubyte[])[1, 2, 3], set!"binaryData"(DBusAny('a', ['y'], false),
|
||||||
|
cast(ubyte[])[1, 2, 3]));
|
||||||
|
|
||||||
test(variant(cast(ubyte) 184), set!"int8"(DBusAny('y', null, true), cast(byte) 184));
|
test(variant(cast(ubyte) 184), set!"int8"(DBusAny('y', null, true), cast(byte) 184));
|
||||||
test(variant(cast(short) 184), set!"int16"(DBusAny('n', null, true), cast(short) 184));
|
test(variant(cast(short) 184), set!"int16"(DBusAny('n', null, true), cast(short) 184));
|
||||||
|
@ -579,18 +625,24 @@ unittest {
|
||||||
test(variant(cast(long) 184), set!"int64"(DBusAny('x', null, true), cast(long) 184));
|
test(variant(cast(long) 184), set!"int64"(DBusAny('x', null, true), cast(long) 184));
|
||||||
test(variant(cast(ulong) 184), set!"uint64"(DBusAny('t', null, true), cast(ulong) 184));
|
test(variant(cast(ulong) 184), set!"uint64"(DBusAny('t', null, true), cast(ulong) 184));
|
||||||
test(variant(true), set!"boolean"(DBusAny('b', null, true), true));
|
test(variant(true), set!"boolean"(DBusAny('b', null, true), true));
|
||||||
test(variant(cast(ubyte[]) [1, 2, 3]), set!"binaryData"(DBusAny('a', ['y'], true), cast(ubyte[]) [1, 2, 3]));
|
test(variant(cast(ubyte[])[1, 2, 3]), set!"binaryData"(DBusAny('a', ['y'],
|
||||||
|
true), cast(ubyte[])[1, 2, 3]));
|
||||||
|
|
||||||
test(variant(DBusAny(5)), set!"int32"(DBusAny('i', null, true), 5));
|
test(variant(DBusAny(5)), set!"int32"(DBusAny('i', null, true), 5));
|
||||||
|
|
||||||
test([1, 2, 3], set!"array"(DBusAny('a', ['i'], false), [DBusAny(1), DBusAny(2), DBusAny(3)]));
|
test([1, 2, 3], set!"array"(DBusAny('a', ['i'], false), [DBusAny(1), DBusAny(2), DBusAny(3)]));
|
||||||
test(variant([1, 2, 3]), set!"array"(DBusAny('a', ['i'], true), [DBusAny(1), DBusAny(2), DBusAny(3)]));
|
test(variant([1, 2, 3]), set!"array"(DBusAny('a', ['i'], true), [DBusAny(1),
|
||||||
|
DBusAny(2), DBusAny(3)]));
|
||||||
|
|
||||||
test(tuple("a", 4, [1, 2]), set!"tuple"(DBusAny('r', "(siai)".dup, false), [DBusAny("a"), DBusAny(4), DBusAny([1, 2])]));
|
test(tuple("a", 4, [1, 2]), set!"tuple"(DBusAny('r', "(siai)".dup, false),
|
||||||
test(tuple("a", variant(4), variant([1, 2])), set!"tuple"(DBusAny('r', "(svv)", false), [DBusAny("a"), DBusAny(variant(4)), DBusAny(variant([1, 2]))]));
|
[DBusAny("a"), DBusAny(4), DBusAny([1, 2])]));
|
||||||
|
test(tuple("a", variant(4), variant([1, 2])), set!"tuple"(DBusAny('r',
|
||||||
|
"(svv)", false), [DBusAny("a"), DBusAny(variant(4)), DBusAny(variant([1, 2]))]));
|
||||||
|
|
||||||
test(["a": "b"], set!"array"(DBusAny('a', "{ss}", false), [DBusAny(DictionaryEntry!(DBusAny, DBusAny)(DBusAny("a"), DBusAny("b")))]));
|
test(["a" : "b"], set!"array"(DBusAny('a', "{ss}", false),
|
||||||
test([variant("a"): 4], set!"array"(DBusAny('a', "{vi}", false), [DBusAny(DictionaryEntry!(DBusAny, DBusAny)(DBusAny(variant("a")), DBusAny(4)))]));
|
[DBusAny(DictionaryEntry!(DBusAny, DBusAny)(DBusAny("a"), DBusAny("b")))]));
|
||||||
|
test([variant("a") : 4], set!"array"(DBusAny('a', "{vi}", false),
|
||||||
|
[DBusAny(DictionaryEntry!(DBusAny, DBusAny)(DBusAny(variant("a")), DBusAny(4)))]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Marks the data as variant on serialization
|
/// Marks the data as variant on serialization
|
||||||
|
@ -605,14 +657,18 @@ Variant!T variant(T)(T data) {
|
||||||
|
|
||||||
enum MessageType {
|
enum MessageType {
|
||||||
Invalid = 0,
|
Invalid = 0,
|
||||||
Call, Return, Error, Signal
|
Call,
|
||||||
|
Return,
|
||||||
|
Error,
|
||||||
|
Signal
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Message {
|
struct Message {
|
||||||
DBusMessage* msg;
|
DBusMessage* msg;
|
||||||
|
|
||||||
this(string dest, string path, string iface, string method) {
|
this(string dest, string path, string iface, string method) {
|
||||||
msg = dbus_message_new_method_call(dest.toStringz(), path.toStringz(), iface.toStringz(), method.toStringz());
|
msg = dbus_message_new_method_call(dest.toStringz(), path.toStringz(),
|
||||||
|
iface.toStringz(), method.toStringz());
|
||||||
}
|
}
|
||||||
|
|
||||||
this(DBusMessage* m) {
|
this(DBusMessage* m) {
|
||||||
|
@ -627,7 +683,8 @@ struct Message {
|
||||||
dbus_message_unref(msg);
|
dbus_message_unref(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void build(TS...)(TS args) if(allCanDBus!TS) {
|
void build(TS...)(TS args)
|
||||||
|
if (allCanDBus!TS) {
|
||||||
DBusMessageIter iter;
|
DBusMessageIter iter;
|
||||||
dbus_message_iter_init_append(msg, &iter);
|
dbus_message_iter_init_append(msg, &iter);
|
||||||
buildIter(&iter, args);
|
buildIter(&iter, args);
|
||||||
|
@ -639,14 +696,17 @@ struct Message {
|
||||||
read the first argument. This is suitable for single item returns.
|
read the first argument. This is suitable for single item returns.
|
||||||
To read multiple arguments use readTuple.
|
To read multiple arguments use readTuple.
|
||||||
*/
|
*/
|
||||||
T read(T)() if(canDBus!T) {
|
T read(T)()
|
||||||
|
if (canDBus!T) {
|
||||||
DBusMessageIter iter;
|
DBusMessageIter iter;
|
||||||
dbus_message_iter_init(msg, &iter);
|
dbus_message_iter_init(msg, &iter);
|
||||||
return readIter!T(&iter);
|
return readIter!T(&iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
alias read to;
|
alias read to;
|
||||||
|
|
||||||
Tup readTuple(Tup)() if(isTuple!Tup && allCanDBus!(Tup.Types)) {
|
Tup readTuple(Tup)()
|
||||||
|
if (isTuple!Tup && allCanDBus!(Tup.Types)) {
|
||||||
DBusMessageIter iter;
|
DBusMessageIter iter;
|
||||||
dbus_message_iter_init(msg, &iter);
|
dbus_message_iter_init(msg, &iter);
|
||||||
Tup ret;
|
Tup ret;
|
||||||
|
@ -673,21 +733,25 @@ struct Message {
|
||||||
assert(cStr != null);
|
assert(cStr != null);
|
||||||
return cStr.fromStringz().idup;
|
return cStr.fromStringz().idup;
|
||||||
}
|
}
|
||||||
|
|
||||||
string path() {
|
string path() {
|
||||||
const(char)* cStr = dbus_message_get_path(msg);
|
const(char)* cStr = dbus_message_get_path(msg);
|
||||||
assert(cStr != null);
|
assert(cStr != null);
|
||||||
return cStr.fromStringz().idup;
|
return cStr.fromStringz().idup;
|
||||||
}
|
}
|
||||||
|
|
||||||
string iface() {
|
string iface() {
|
||||||
const(char)* cStr = dbus_message_get_interface(msg);
|
const(char)* cStr = dbus_message_get_interface(msg);
|
||||||
assert(cStr != null);
|
assert(cStr != null);
|
||||||
return cStr.fromStringz().idup;
|
return cStr.fromStringz().idup;
|
||||||
}
|
}
|
||||||
|
|
||||||
string member() {
|
string member() {
|
||||||
const(char)* cStr = dbus_message_get_member(msg);
|
const(char)* cStr = dbus_message_get_member(msg);
|
||||||
assert(cStr != null);
|
assert(cStr != null);
|
||||||
return cStr.fromStringz().idup;
|
return cStr.fromStringz().idup;
|
||||||
}
|
}
|
||||||
|
|
||||||
string sender() {
|
string sender() {
|
||||||
const(char)* cStr = dbus_message_get_sender(msg);
|
const(char)* cStr = dbus_message_get_sender(msg);
|
||||||
assert(cStr != null);
|
assert(cStr != null);
|
||||||
|
@ -697,6 +761,7 @@ struct Message {
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
auto msg = Message("org.example.test", "/test", "org.example.testing", "testMethod");
|
auto msg = Message("org.example.test", "/test", "org.example.testing", "testMethod");
|
||||||
msg.path().assertEqual("/test");
|
msg.path().assertEqual("/test");
|
||||||
}
|
}
|
||||||
|
@ -774,26 +839,17 @@ unittest {
|
||||||
|
|
||||||
__gshared int dummy;
|
__gshared int dummy;
|
||||||
|
|
||||||
enum testStruct = S3(
|
enum testStruct = S3(variant(5), "blah", S1(-7, 63.5, "test"), S2(84, -123,
|
||||||
variant(5), "blah",
|
78, 432, &dummy), 16);
|
||||||
S1(-7, 63.5, "test"),
|
|
||||||
S2(84, -123, 78, 432, &dummy),
|
|
||||||
16
|
|
||||||
);
|
|
||||||
|
|
||||||
msg.build(testStruct);
|
msg.build(testStruct);
|
||||||
|
|
||||||
// Non-marshaled fields should appear as freshly initialized
|
// Non-marshaled fields should appear as freshly initialized
|
||||||
enum expectedResult = S3(
|
enum expectedResult = S3(variant(5), "blah", S1(int.init, 63.5, "test"),
|
||||||
variant(5), "blah",
|
S2(int.init, int.init, 78, 432, null), uint.init);
|
||||||
S1(int.init, 63.5, "test"),
|
|
||||||
S2(int.init, int.init, 78, 432, null),
|
|
||||||
uint.init
|
|
||||||
);
|
|
||||||
|
|
||||||
msg.read!S3().assertEqual(expectedResult);
|
msg.read!S3().assertEqual(expectedResult);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection connectToBus(DBusBusType bus = DBusBusType.DBUS_BUS_SESSION) {
|
Connection connectToBus(DBusBusType bus = DBusBusType.DBUS_BUS_SESSION) {
|
||||||
|
@ -803,6 +859,7 @@ Connection connectToBus(DBusBusType bus = DBusBusType.DBUS_BUS_SESSION) {
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
// This test will only pass if DBus is installed.
|
// This test will only pass if DBus is installed.
|
||||||
Connection conn = connectToBus();
|
Connection conn = connectToBus();
|
||||||
conn.conn.assertTruthy();
|
conn.conn.assertTruthy();
|
||||||
|
|
|
@ -26,12 +26,10 @@ auto byDictionaryEntries(K, V)(V[K] aa) {
|
||||||
Its meaning became unclear when support for Phobos-style variants was added.
|
Its meaning became unclear when support for Phobos-style variants was added.
|
||||||
It seemed best to remove it at that point.
|
It seemed best to remove it at that point.
|
||||||
+/
|
+/
|
||||||
deprecated("Use std.traits.isInstanceOf instead.")
|
deprecated("Use std.traits.isInstanceOf instead.") template isVariant(T) {
|
||||||
template isVariant(T) {
|
|
||||||
static if (isBasicType!T || isInputRange!T) {
|
static if (isBasicType!T || isInputRange!T) {
|
||||||
enum isVariant = false;
|
enum isVariant = false;
|
||||||
} else static if(__traits(compiles, TemplateOf!T)
|
} else static if (__traits(compiles, TemplateOf!T) && __traits(isSame, TemplateOf!T, Variant)) {
|
||||||
&& __traits(isSame, TemplateOf!T, Variant)) {
|
|
||||||
enum isVariant = true;
|
enum isVariant = true;
|
||||||
} else {
|
} else {
|
||||||
enum isVariant = false;
|
enum isVariant = false;
|
||||||
|
@ -56,19 +54,8 @@ template allCanDBus(TS...) {
|
||||||
AliasSeq of all basic types in terms of the DBus typesystem
|
AliasSeq of all basic types in terms of the DBus typesystem
|
||||||
+/
|
+/
|
||||||
package // Don't add to the API yet, 'cause I intend to move it later
|
package // Don't add to the API yet, 'cause I intend to move it later
|
||||||
alias BasicTypes = AliasSeq!(
|
alias BasicTypes = AliasSeq!(bool, byte, short, ushort, int, uint, long, ulong,
|
||||||
bool,
|
double, string, ObjectPath);
|
||||||
byte,
|
|
||||||
short,
|
|
||||||
ushort,
|
|
||||||
int,
|
|
||||||
uint,
|
|
||||||
long,
|
|
||||||
ulong,
|
|
||||||
double,
|
|
||||||
string,
|
|
||||||
ObjectPath
|
|
||||||
);
|
|
||||||
|
|
||||||
template basicDBus(T) {
|
template basicDBus(T) {
|
||||||
static if (staticIndexOf!(T, BasicTypes) >= 0) {
|
static if (staticIndexOf!(T, BasicTypes) >= 0) {
|
||||||
|
@ -110,6 +97,7 @@ template canDBus(T) {
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
(canDBus!int).assertTrue();
|
(canDBus!int).assertTrue();
|
||||||
(canDBus!(int[])).assertTrue();
|
(canDBus!(int[])).assertTrue();
|
||||||
(allCanDBus!(int, string, bool)).assertTrue();
|
(allCanDBus!(int, string, bool)).assertTrue();
|
||||||
|
@ -118,7 +106,8 @@ unittest {
|
||||||
(canDBus!(int[string])).assertTrue();
|
(canDBus!(int[string])).assertTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
string typeSig(T)() if(canDBus!T) {
|
string typeSig(T)()
|
||||||
|
if (canDBus!T) {
|
||||||
static if (is(T == byte)) {
|
static if (is(T == byte)) {
|
||||||
return "y";
|
return "y";
|
||||||
} else static if (is(T == bool)) {
|
} else static if (is(T == bool)) {
|
||||||
|
@ -149,7 +138,8 @@ string typeSig(T)() if(canDBus!T) {
|
||||||
alias TemplateArgsOf!T[0] E;
|
alias TemplateArgsOf!T[0] E;
|
||||||
return typeSig!E;
|
return typeSig!E;
|
||||||
} else static if (is(T == DBusAny)) {
|
} else static if (is(T == DBusAny)) {
|
||||||
static assert(false, "Cannot determine type signature of DBusAny. Change to Variant!DBusAny if a variant was desired.");
|
static assert(false,
|
||||||
|
"Cannot determine type signature of DBusAny. Change to Variant!DBusAny if a variant was desired.");
|
||||||
} else static if (isTuple!T) {
|
} else static if (isTuple!T) {
|
||||||
string sig = "(";
|
string sig = "(";
|
||||||
foreach (i, S; T.Types) {
|
foreach (i, S; T.Types) {
|
||||||
|
@ -171,20 +161,23 @@ string typeSig(T)() if(canDBus!T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string typeSig(T)() if(isInstanceOf!(DictionaryEntry, T)) {
|
string typeSig(T)()
|
||||||
|
if (isInstanceOf!(DictionaryEntry, T)) {
|
||||||
alias typeof(T.key) K;
|
alias typeof(T.key) K;
|
||||||
alias typeof(T.value) V;
|
alias typeof(T.value) V;
|
||||||
return "{" ~ typeSig!K ~ typeSig!V ~ '}';
|
return "{" ~ typeSig!K ~ typeSig!V ~ '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] typeSigReturn(T)() if(canDBus!T) {
|
string[] typeSigReturn(T)()
|
||||||
|
if (canDBus!T) {
|
||||||
static if (is(T == Tuple!TS, TS...))
|
static if (is(T == Tuple!TS, TS...))
|
||||||
return typeSigArr!TS;
|
return typeSigArr!TS;
|
||||||
else
|
else
|
||||||
return [typeSig!T];
|
return [typeSig!T];
|
||||||
}
|
}
|
||||||
|
|
||||||
string typeSigAll(TS...)() if(allCanDBus!TS) {
|
string typeSigAll(TS...)()
|
||||||
|
if (allCanDBus!TS) {
|
||||||
string sig = "";
|
string sig = "";
|
||||||
foreach (i, T; TS) {
|
foreach (i, T; TS) {
|
||||||
sig ~= typeSig!T();
|
sig ~= typeSig!T();
|
||||||
|
@ -192,7 +185,8 @@ string typeSigAll(TS...)() if(allCanDBus!TS) {
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] typeSigArr(TS...)() if(allCanDBus!TS) {
|
string[] typeSigArr(TS...)()
|
||||||
|
if (allCanDBus!TS) {
|
||||||
string[] sig = [];
|
string[] sig = [];
|
||||||
foreach (i, T; TS) {
|
foreach (i, T; TS) {
|
||||||
sig ~= typeSig!T();
|
sig ~= typeSig!T();
|
||||||
|
@ -200,37 +194,66 @@ string[] typeSigArr(TS...)() if(allCanDBus!TS) {
|
||||||
return sig;
|
return sig;
|
||||||
}
|
}
|
||||||
|
|
||||||
int typeCode(T)() if(canDBus!T) {
|
int typeCode(T)()
|
||||||
|
if (canDBus!T) {
|
||||||
int code = typeSig!T()[0];
|
int code = typeSig!T()[0];
|
||||||
return (code != '(') ? code : 'r';
|
return (code != '(') ? code : 'r';
|
||||||
}
|
}
|
||||||
|
|
||||||
int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) {
|
int typeCode(T)()
|
||||||
|
if (isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) {
|
||||||
return 'e';
|
return 'e';
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest {
|
unittest {
|
||||||
import dunit.toolkit;
|
import dunit.toolkit;
|
||||||
|
|
||||||
// basics
|
// basics
|
||||||
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!(Variant!int)().assertEqual("v");
|
typeSig!(Variant!int)().assertEqual("v");
|
||||||
// enums
|
// enums
|
||||||
enum E : byte { a, b, c }
|
enum E : byte {
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
c
|
||||||
|
}
|
||||||
|
|
||||||
typeSig!E().assertEqual(typeSig!byte());
|
typeSig!E().assertEqual(typeSig!byte());
|
||||||
enum U : string { One = "One", Two = "Two" }
|
enum U : string {
|
||||||
|
One = "One",
|
||||||
|
Two = "Two"
|
||||||
|
}
|
||||||
|
|
||||||
typeSig!U().assertEqual(typeSig!string());
|
typeSig!U().assertEqual(typeSig!string());
|
||||||
// bit flags
|
// bit flags
|
||||||
enum F : uint { a = 1, b = 2, c = 4 }
|
enum F : uint {
|
||||||
|
a = 1,
|
||||||
|
b = 2,
|
||||||
|
c = 4
|
||||||
|
}
|
||||||
|
|
||||||
typeSig!(BitFlags!F)().assertEqual(typeSig!uint());
|
typeSig!(BitFlags!F)().assertEqual(typeSig!uint());
|
||||||
// tuples (represented as structs in DBus)
|
// tuples (represented as structs in DBus)
|
||||||
typeSig!(Tuple!(int, string, string)).assertEqual("(iss)");
|
typeSig!(Tuple!(int, string, string)).assertEqual("(iss)");
|
||||||
typeSig!(Tuple!(int,string,Variant!int,Tuple!(int,"k",double,"x"))).assertEqual("(isv(id))");
|
typeSig!(Tuple!(int, string, Variant!int, Tuple!(int, "k", double, "x"))).assertEqual(
|
||||||
|
"(isv(id))");
|
||||||
// structs
|
// structs
|
||||||
struct S1 { int a; double b; string s; }
|
struct S1 {
|
||||||
|
int a;
|
||||||
|
double b;
|
||||||
|
string s;
|
||||||
|
}
|
||||||
|
|
||||||
typeSig!S1.assertEqual("(ids)");
|
typeSig!S1.assertEqual("(ids)");
|
||||||
struct S2 { Variant!int c; string d; S1 e; uint f; }
|
struct S2 {
|
||||||
|
Variant!int c;
|
||||||
|
string d;
|
||||||
|
S1 e;
|
||||||
|
uint f;
|
||||||
|
}
|
||||||
|
|
||||||
typeSig!S2.assertEqual("(vs(ids)u)");
|
typeSig!S2.assertEqual("(vs(ids)u)");
|
||||||
// arrays
|
// arrays
|
||||||
typeSig!(int[]).assertEqual("ai");
|
typeSig!(int[]).assertEqual("ai");
|
||||||
|
@ -257,11 +280,12 @@ unittest {
|
||||||
sig3.assertEqual("iss");
|
sig3.assertEqual("iss");
|
||||||
}
|
}
|
||||||
|
|
||||||
private template AllowedFieldTypes(S) if (is(S == struct)) {
|
private template AllowedFieldTypes(S)
|
||||||
|
if (is(S == struct)) {
|
||||||
import ddbus.attributes : isAllowedField;
|
import ddbus.attributes : isAllowedField;
|
||||||
import std.meta : Filter, staticMap;
|
import std.meta : Filter, staticMap;
|
||||||
|
|
||||||
static alias TypeOf(alias sym) = typeof(sym);
|
static alias TypeOf(alias sym) = typeof(sym);
|
||||||
|
|
||||||
alias AllowedFieldTypes =
|
alias AllowedFieldTypes = staticMap!(TypeOf, Filter!(isAllowedField, S.tupleof));
|
||||||
staticMap!(TypeOf, Filter!(isAllowedField, S.tupleof));
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue