diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e4d239a --- /dev/null +++ b/.editorconfig @@ -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 diff --git a/source/ddbus/attributes.d b/source/ddbus/attributes.d index 1658be5..b61b2ed 100644 --- a/source/ddbus/attributes.d +++ b/source/ddbus/attributes.d @@ -10,17 +10,23 @@ import std.typecons : BitFlags, Flag; Default is to include public fields only +/ enum MarshalingFlag : ubyte { - includePrivateFields = 1 << 0, /// Automatically include private fields - manualOnly = 1 << 7 /// Only include fields with explicit - /// `@Yes.DBusMarshal`. This overrides any - /// `include` flags. + /++ + Automatically include private fields + +/ + includePrivateFields = 1 << 0, + + /++ + Only include fields with explicit `@Yes.DBusMarshal`. This overrides any + `include` flags. + +/ + manualOnly = 1 << 7 } /++ UDA for specifying DBus marshaling options on structs +/ -auto dbusMarshaling(Args)(Args args ...) - if (allSatisfy!(isMarshalingFlag, Args)) { +auto dbusMarshaling(Args)(Args args...) + if (allSatisfy!(isMarshalingFlag, Args)) { return BitFlags!MarshalingFlag(args); } @@ -29,37 +35,40 @@ package(ddbus) template isAllowedField(alias field) { private alias getUDAs!(field, Flag!"DBusMarshal") UDAs; static if (UDAs.length != 0) { - static assert (UDAs.length == 1, - "Only one UDA of type Flag!\"DBusMarshal\" allowed on struct field."); - static assert (is(typeof(UDAs[0]) == Flag!"DBusMarshal"), - "Did you intend to add UDA Yes.DBusMarshal or No.DBusMarshal?"); + static assert(UDAs.length == 1, + "Only one UDA of type Flag!\"DBusMarshal\" allowed on struct field."); + + static assert(is(typeof(UDAs[0]) == Flag!"DBusMarshal"), + "Did you intend to add UDA Yes.DBusMarshal or No.DBusMarshal?"); + enum isAllowedField = cast(bool) UDAs[0]; } else static if (!(flags & MarshalingFlag.manualOnly)) { - static if (__traits(getProtection, field) == "public") + static if (__traits(getProtection, field) == "public") { enum isAllowedField = true; - else static if (cast(bool) (flags & MarshalingFlag.includePrivateFields)) + } else static if (cast(bool)(flags & MarshalingFlag.includePrivateFields)) { enum isAllowedField = true; - else + } else { enum isAllowedField = false; - } else + } + } else { enum isAllowedField = false; + } } private template isMarshalingFlag(T) { 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; - static if (UDAs.length == 0) + static if (UDAs.length == 0) { enum marshalingFlags = BitFlags!MarshalingFlag.init; - else { - static assert (UDAs.length == 1, - "Only one @dbusMarshaling UDA allowed on type."); - static assert (is(typeof(UDAs[0]) == BitFlags!MarshalingFlag), - "Huh? Did you intend to use @dbusMarshaling UDA?"); + } else { + static assert(UDAs.length == 1, "Only one @dbusMarshaling UDA allowed on type."); + static assert(is(typeof(UDAs[0]) == BitFlags!MarshalingFlag), + "Huh? Did you intend to use @dbusMarshaling UDA?"); enum marshalingFlags = UDAs[0]; } } - diff --git a/source/ddbus/bus.d b/source/ddbus/bus.d index 7712590..9d500d2 100644 --- a/source/ddbus/bus.d +++ b/source/ddbus/bus.d @@ -10,16 +10,18 @@ enum BusPath = "/org/freedesktop/DBus"; enum BusInterface = "org.freedesktop.DBus"; enum NameFlags { - AllowReplace = 1, ReplaceExisting = 2, NoQueue = 4 + AllowReplace = 1, + ReplaceExisting = 2, + NoQueue = 4 } /// Requests a DBus well-known name. /// returns if the name is owned after the call. /// Involves blocking call on a DBus method, may throw an exception on failure. bool requestName(Connection conn, string name, - NameFlags flags = NameFlags.NoQueue | NameFlags.AllowReplace) { - auto msg = Message(BusService,BusPath,BusInterface,"RequestName"); - msg.build(name,cast(uint)(flags)); + NameFlags flags = NameFlags.NoQueue | NameFlags.AllowReplace) { + auto msg = Message(BusService, BusPath, BusInterface, "RequestName"); + msg.build(name, cast(uint)(flags)); auto res = conn.sendWithReplyBlocking(msg).to!uint; return (res == 1) || (res == 4); } @@ -28,7 +30,8 @@ bool requestName(Connection conn, string name, /// and isn't guaranteed to work with other tasks and threads. /// Use only for apps that only do DBus triggered things. 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 @@ -39,7 +42,7 @@ bool tick(Connection conn) { unittest { import dunit.toolkit; + Connection conn = connectToBus(); conn.requestName("ca.thume.ddbus.testing").assertTrue(); } - diff --git a/source/ddbus/c_lib.d b/source/ddbus/c_lib.d index a3ee5bf..71240bf 100644 --- a/source/ddbus/c_lib.d +++ b/source/ddbus/c_lib.d @@ -1,6 +1,10 @@ module ddbus.c_lib; + import core.stdc.config; import core.stdc.stdarg; + +// dfmt off + extern (C): // START dbus/dbus-arch-deps.d alias c_long dbus_int64_t; diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index ebc7aa2..1fa16db 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -7,36 +7,37 @@ import ddbus.util; import ddbus.thin; import std.exception : enforce; -import std.meta: allSatisfy; +import std.meta : allSatisfy; import std.string; import std.typecons; import std.range; import std.traits; import std.variant : VariantN; -void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { - foreach(index, arg; args) { +void buildIter(TS...)(DBusMessageIter* iter, TS args) + if (allCanDBus!TS) { + foreach (index, arg; args) { alias TS[index] T; - static if(is(T == string)) { + static if (is(T == string)) { immutable(char)* cStr = arg.toStringz(); - dbus_message_iter_append_basic(iter,typeCode!T,&cStr); - } else static if(is(T == ObjectPath)) { + dbus_message_iter_append_basic(iter, typeCode!T, &cStr); + } else static if (is(T == ObjectPath)) { immutable(char)* cStr = arg.toString().toStringz(); - dbus_message_iter_append_basic(iter,typeCode!T,&cStr); - } else static if(is(T==bool)) { + dbus_message_iter_append_basic(iter, typeCode!T, &cStr); + } else static if (is(T == bool)) { dbus_bool_t longerBool = arg; // dbus bools are ints - dbus_message_iter_append_basic(iter,typeCode!T,&longerBool); - } else static if(isTuple!T) { + dbus_message_iter_append_basic(iter, typeCode!T, &longerBool); + } else static if (isTuple!T) { DBusMessageIter sub; dbus_message_iter_open_container(iter, 'r', null, &sub); buildIter(&sub, arg.expand); dbus_message_iter_close_container(iter, &sub); - } else static if(isInputRange!T) { + } else static if (isInputRange!T) { DBusMessageIter sub; const(char)* subSig = (typeSig!(ElementType!T)()).toStringz(); dbus_message_iter_open_container(iter, 'a', subSig, &sub); - foreach(x; arg) { - static if(isInstanceOf!(DictionaryEntry, typeof(x))) { + foreach (x; arg) { + static if (isInstanceOf!(DictionaryEntry, typeof(x))) { DBusMessageIter entry; dbus_message_iter_open_container(&sub, 'e', null, &entry); buildIter(&entry, x.key); @@ -47,11 +48,11 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { } } dbus_message_iter_close_container(iter, &sub); - } else static if(isAssociativeArray!T) { + } else static if (isAssociativeArray!T) { DBusMessageIter sub; - const(char)* subSig = typeSig!T[1..$].toStringz(); + const(char)* subSig = typeSig!T[1 .. $].toStringz(); dbus_message_iter_open_container(iter, 'a', subSig, &sub); - foreach(k, v; arg) { + foreach (k, v; arg) { DBusMessageIter entry; dbus_message_iter_open_container(&sub, 'e', null, &entry); buildIter(&entry, k); @@ -59,12 +60,11 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { dbus_message_iter_close_container(&sub, &entry); } dbus_message_iter_close_container(iter, &sub); - } else static if(isInstanceOf!(VariantN, T)) { - enforce(arg.hasValue, - new InvalidValueException(arg, "dbus:" ~ cast(char) typeCode!T)); + } else static if (isInstanceOf!(VariantN, T)) { + enforce(arg.hasValue, new InvalidValueException(arg, "dbus:" ~ cast(char) typeCode!T)); DBusMessageIter sub; - foreach(AT; T.AllowedTypes) { + foreach (AT; T.AllowedTypes) { if (arg.peek!AT) { dbus_message_iter_open_container(iter, 'v', typeSig!AT.ptr, &sub); buildIter(&sub, arg.get!AT); @@ -72,8 +72,8 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { break; } } - } else static if(is(T == DBusAny) || is(T == Variant!DBusAny)) { - static if(is(T == Variant!DBusAny)) { + } else static if (is(T == DBusAny) || is(T == Variant!DBusAny)) { + static if (is(T == Variant!DBusAny)) { auto val = arg.data; val.explicitVariant = true; } else { @@ -81,66 +81,81 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { } DBusMessageIter subStore; DBusMessageIter* sub = &subStore; - const(char)[] sig = [ cast(char) val.type ]; - if(val.type == 'a') + const(char)[] sig = [cast(char) val.type]; + if (val.type == 'a') { sig ~= val.signature; - else if(val.type == 'r') + } else if (val.type == 'r') { sig = val.signature; + } + sig ~= '\0'; - if (!val.explicitVariant) + + if (!val.explicitVariant) { sub = iter; - else + } else { dbus_message_iter_open_container(iter, 'v', sig.ptr, sub); - if(val.type == 's') { + } + + if (val.type == 's') { buildIter(sub, val.str); - } else if(val.type == 'o') { + } else if (val.type == 'o') { buildIter(sub, val.obj); - } else if(val.type == 'b') { - buildIter(sub,val.boolean); - } else if(dbus_type_is_basic(val.type)) { - dbus_message_iter_append_basic(sub,val.type,&val.int64); - } else if(val.type == 'a') { + } else if (val.type == 'b') { + buildIter(sub, val.boolean); + } else if (dbus_type_is_basic(val.type)) { + dbus_message_iter_append_basic(sub, val.type, &val.int64); + } else if (val.type == 'a') { DBusMessageIter 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); - else - foreach(item; val.array) + } + } else { + foreach (item; val.array) { buildIter(&arr, item); + } + } + dbus_message_iter_close_container(sub, &arr); - } else if(val.type == 'r') { + } else if (val.type == 'r') { DBusMessageIter arr; dbus_message_iter_open_container(sub, 'r', null, &arr); - foreach(item; val.tuple) + + foreach (item; val.tuple) { buildIter(&arr, item); + } + dbus_message_iter_close_container(sub, &arr); - } else if(val.type == 'e') { + } else if (val.type == 'e') { DBusMessageIter entry; dbus_message_iter_open_container(sub, 'e', null, &entry); buildIter(&entry, val.entry.key); buildIter(&entry, val.entry.value); dbus_message_iter_close_container(sub, &entry); } - if(val.explicitVariant) + + if (val.explicitVariant) { dbus_message_iter_close_container(iter, sub); - } else static if(isInstanceOf!(Variant, T)) { + } + } else static if (isInstanceOf!(Variant, T)) { DBusMessageIter sub; const(char)* subSig = typeSig!(VariantType!T).toStringz(); dbus_message_iter_open_container(iter, 'v', subSig, &sub); buildIter(&sub, arg.data); dbus_message_iter_close_container(iter, &sub); - } else static if(is(T == struct)) { + } else static if (is(T == struct)) { DBusMessageIter sub; dbus_message_iter_open_container(iter, 'r', null, &sub); // Following failed because of missing 'this' for members of arg. // That sucks. It worked without Filter. // Reported: https://issues.dlang.org/show_bug.cgi?id=17692 -// buildIter(&sub, Filter!(isAllowedField, arg.tupleof)); + // buildIter(&sub, Filter!(isAllowedField, arg.tupleof)); // Using foreach to work around the issue - foreach(i, member; arg.tupleof) { + foreach (i, member; arg.tupleof) { // Ugly, but we need to use tupleof again in the condition, because when // we use `member`, isAllowedField will fail because it'll find this // nice `buildIter` function instead of T when it looks up the parent @@ -150,55 +165,52 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { } dbus_message_iter_close_container(iter, &sub); - } else static if(basicDBus!T) { - dbus_message_iter_append_basic(iter,typeCode!T,&arg); + } else static if (basicDBus!T) { + dbus_message_iter_append_basic(iter, typeCode!T, &arg); } } } -T readIter(T)(DBusMessageIter *iter) if (is(T == enum)) { +T readIter(T)(DBusMessageIter* iter) + if (is(T == enum)) { import std.algorithm.searching : canFind; alias OriginalType!T B; B value = readIter!B(iter); - enforce( - only(EnumMembers!T).canFind(value), - new InvalidValueException(value, T.stringof) - ); + enforce(only(EnumMembers!T).canFind(value), new InvalidValueException(value, T.stringof)); 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; alias TemplateArgsOf!T[0] E; alias OriginalType!E B; - 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); - enforce( - !(value & ~mask), - new InvalidValueException(value, T.stringof) - ); + enforce(!(value & ~mask), new InvalidValueException(value, T.stringof)); 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); T ret; - static if(!isInstanceOf!(Variant, T) || is(T == Variant!DBusAny)) { - if(argType == 'v') { + static if (!isInstanceOf!(Variant, T) || is(T == Variant!DBusAny)) { + if (argType == 'v') { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); - static if(is(T == Variant!DBusAny)) { + static if (is(T == Variant!DBusAny)) { ret = variant(readIter!DBusAny(&sub)); } else { ret = readIter!T(&sub); - static if(is(T == DBusAny)) + static if (is(T == DBusAny)) ret.explicitVariant = true; } dbus_message_iter_next(iter); @@ -206,36 +218,35 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla } } - static if( - !is(T == DBusAny) - && !is(T == Variant!DBusAny) - && !isInstanceOf!(VariantN, T) - ) { - enforce(argType == typeCode!T(), - new TypeMismatchException(typeCode!T(), argType)); + static if (!is(T == DBusAny) && !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; dbus_message_iter_get_basic(iter, &cStr); string str = cStr.fromStringz().idup; // copy string - static if(is(T==string)) + static if (is(T == string)) { ret = str; - else + } else { ret = ObjectPath(str); - } else static if(is(T==bool)) { + } + } else static if (is(T == bool)) { dbus_bool_t longerBool; dbus_message_iter_get_basic(iter, &longerBool); - ret = cast(bool)longerBool; - } else static if(isTuple!T) { + ret = cast(bool) longerBool; + } else static if (isTuple!T) { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); 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); + 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)) { + + while (dbus_message_iter_get_arg_type(&sub) != 0) { + static if (is(U == DictionaryEntry!(K, V), K, V)) { DBusMessageIter entry; dbus_message_iter_recurse(&sub, &entry); ret ~= U(readIter!K(&entry), readIter!V(&entry)); @@ -244,17 +255,16 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla ret ~= readIter!U(&sub); } } - } else static if(isInstanceOf!(Variant, T)) { + } else static if (isInstanceOf!(Variant, T)) { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); ret.data = readIter!(VariantType!T)(&sub); - } else static if(isInstanceOf!(VariantN, T)) { - scope const(char)[] argSig = - dbus_message_iter_get_signature(iter).fromStringz(); - scope(exit) + } else static if (isInstanceOf!(VariantN, T)) { + scope const(char)[] argSig = dbus_message_iter_get_signature(iter).fromStringz(); + scope (exit) dbus_free(cast(void*) argSig.ptr); - foreach(AT; T.AllowedTypes) { + foreach (AT; T.AllowedTypes) { // We have to compare the full signature here, not just the typecode. // Otherwise, in case of container types, we might select the wrong one. // We would then be calling an incorrect instance of readIter, which would @@ -267,10 +277,11 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla // If no value is in ret, apparently none of the types matched. enforce(ret.hasValue, new TypeMismatchException(typeCode!T, argType)); - } else static if(isAssociativeArray!T) { + } else static if (isAssociativeArray!T) { DBusMessageIter sub; 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; dbus_message_iter_recurse(&sub, &entry); auto k = readIter!(KeyType!T)(&entry); @@ -278,59 +289,64 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla ret[k] = v; dbus_message_iter_next(&sub); } - } else static if(is(T == DBusAny)) { + } else static if (is(T == DBusAny)) { ret.type = argType; ret.explicitVariant = false; - if(ret.type == 's') { + + if (ret.type == 's') { ret.str = readIter!string(iter); return ret; - } else if(ret.type == 'o') { + } else if (ret.type == 'o') { ret.obj = readIter!ObjectPath(iter); return ret; - } else if(ret.type == 'b') { + } else if (ret.type == 'b') { ret.boolean = readIter!bool(iter); return ret; - } else if(dbus_type_is_basic(ret.type)) { + } else if (dbus_type_is_basic(ret.type)) { dbus_message_iter_get_basic(iter, &ret.int64); - } else if(ret.type == 'a') { + } else if (ret.type == 'a') { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); auto sig = dbus_message_iter_get_signature(&sub); ret.signature = sig.fromStringz.dup; dbus_free(sig); - if (ret.signature == ['y']) - while(dbus_message_iter_get_arg_type(&sub) != 0) { + if (ret.signature == ['y']) { + while (dbus_message_iter_get_arg_type(&sub) != 0) { ubyte b; assert(dbus_message_iter_get_arg_type(&sub) == 'y'); dbus_message_iter_get_basic(&sub, &b); dbus_message_iter_next(&sub); ret.binaryData ~= b; } - else - while(dbus_message_iter_get_arg_type(&sub) != 0) { + } else { + while (dbus_message_iter_get_arg_type(&sub) != 0) { ret.array ~= readIter!DBusAny(&sub); } - } else if(ret.type == 'r') { + } + } else if (ret.type == 'r') { auto sig = dbus_message_iter_get_signature(iter); ret.signature = sig.fromStringz.dup; dbus_free(sig); + DBusMessageIter 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); } - } else if(ret.type == 'e') { + } else if (ret.type == 'e') { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); + ret.entry = new DictionaryEntry!(DBusAny, DBusAny); ret.entry.key = readIter!DBusAny(&sub); ret.entry.value = readIter!DBusAny(&sub); } - } else static if(is(T == struct)) { + } else static if (is(T == struct)) { DBusMessageIter sub; dbus_message_iter_recurse(iter, &sub); readIterStruct!T(&sub, ret); - } else static if(basicDBus!T) { + } else static if (basicDBus!T) { dbus_message_iter_get_basic(iter, &ret); } @@ -338,15 +354,16 @@ T readIter(T)(DBusMessageIter *iter) if (!is(T == enum) && !isInstanceOf!(BitFla return ret; } -void readIterTuple(Tup)(DBusMessageIter *iter, ref Tup tuple) if(isTuple!Tup && allCanDBus!(Tup.Types)) { - foreach(index, T; Tup.Types) { +void readIterTuple(Tup)(DBusMessageIter* iter, ref Tup tuple) + if (isTuple!Tup && allCanDBus!(Tup.Types)) { + foreach (index, T; Tup.Types) { tuple[index] = readIter!T(iter); } } -void readIterStruct(S)(DBusMessageIter *iter, ref S s) if(is(S == struct) && canDBus!S) -{ - foreach(index, T; Fields!S) { +void readIterStruct(S)(DBusMessageIter* iter, ref S s) + if (is(S == struct) && canDBus!S) { + foreach (index, T; Fields!S) { static if (isAllowedField!(s.tupleof[index])) { s.tupleof[index] = readIter!T(iter); } @@ -356,8 +373,12 @@ void readIterStruct(S)(DBusMessageIter *iter, ref S s) if(is(S == struct) && can unittest { import dunit.toolkit; import ddbus.thin; - Variant!T var(T)(T data){ return Variant!T(data); } - Message msg = Message("org.example.wow","/wut","org.test.iface","meth"); + + Variant!T var(T)(T data) { + return Variant!T(data); + } + + Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth"); bool[] emptyB; string[string] map; map["hello"] = "world"; @@ -365,24 +386,24 @@ unittest { anyVar.type.assertEqual('t'); anyVar.uint64.assertEqual(1561); anyVar.explicitVariant.assertEqual(false); - auto tupleMember = DBusAny(tuple(Variant!int(45), Variant!ushort(5), 32, [1, 2], tuple(variant(4), 5), map)); - Variant!DBusAny complexVar = variant(DBusAny([ - "hello world": variant(DBusAny(1337)), - "array value": variant(DBusAny([42, 64])), - "tuple value": variant(tupleMember), - "optimized binary data": variant(DBusAny(cast(ubyte[]) [1, 2, 3, 4, 5, 6])) - ])); + auto tupleMember = DBusAny(tuple(Variant!int(45), Variant!ushort(5), 32, + [1, 2], tuple(variant(4), 5), map)); + Variant!DBusAny complexVar = variant(DBusAny(["hello world" : variant(DBusAny(1337)), + "array value" : variant(DBusAny([42, 64])), "tuple value" + : variant(tupleMember), "optimized binary data" + : variant(DBusAny(cast(ubyte[])[1, 2, 3, 4, 5, 6]))])); complexVar.data.type.assertEqual('a'); complexVar.data.signature.assertEqual("{sv}".dup); 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.signature().assertEqual("ibsvai(diaasabv)a{ss}tv"); msg.read!string().assertThrow!TypeMismatchException(); msg.readTuple!(Tuple!(int, bool, double)).assertThrow!TypeMismatchException(); - msg.readTuple!(Tuple!(int, bool, string, double)).assertEqual(tuple(5,true,"wow", 5.9)); + msg.readTuple!(Tuple!(int, bool, string, double)).assertEqual(tuple(5, true, "wow", 5.9)); msg.readTuple!(typeof(args))().assertEqual(args); DBusMessageIter iter; @@ -391,13 +412,14 @@ unittest { readIter!bool(&iter).assertEqual(true); readIter!string(&iter).assertEqual("wow"); readIter!double(&iter).assertEqual(5.9); - 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!(int[])(&iter).assertEqual([6, 5]); + 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. auto iter2 = iter; - readIter!(string[string])(&iter).assertEqual(["hello": "world"]); - auto dict = readIter!(DictionaryEntry!(string,string)[])(&iter2); + readIter!(string[string])(&iter).assertEqual(["hello" : "world"]); + auto dict = readIter!(DictionaryEntry!(string, string)[])(&iter2); dict.length.assertEqual(1); dict[0].key.assertEqual("hello"); dict[0].value.assertEqual("world"); @@ -412,8 +434,18 @@ unittest { import std.variant : Algebraic; - enum E : int { a, b, c } - enum F : uint { x = 1, y = 2, z = 4 } + enum E : int { + a, + b, + c + } + + enum F : uint { + x = 1, + y = 2, + z = 4 + } + alias V = Algebraic!(byte, short, int, long, string); Message msg = Message("org.example.wow", "/wut", "org.test.iface", "meth2"); @@ -437,4 +469,3 @@ unittest { readIter!V(&iter).assertEqual(v1); readIter!short(&iter).assertEqual(v2.get!short); } - diff --git a/source/ddbus/exception.d b/source/ddbus/exception.d index 1ce45e9..99713a6 100644 --- a/source/ddbus/exception.d +++ b/source/ddbus/exception.d @@ -2,16 +2,12 @@ module ddbus.exception; import ddbus.c_lib; -package T wrapErrors(T)( - T delegate(DBusError *err) del, - string file = __FILE__, - size_t line = __LINE__, - Throwable next = null -) { +package T wrapErrors(T)(T delegate(DBusError* err) del, string file = __FILE__, + size_t line = __LINE__, Throwable next = null) { DBusError error; dbus_error_init(&error); T ret = del(&error); - if(dbus_error_is_set(&error)) { + if (dbus_error_is_set(&error)) { auto ex = new DBusException(&error, file, line, next); dbus_error_free(&error); throw ex; @@ -23,12 +19,8 @@ package T wrapErrors(T)( Thrown when a DBus error code was returned by libdbus. +/ class DBusException : Exception { - private this( - scope DBusError *err, - string file = __FILE__, - size_t line = __LINE__, - Throwable next = null - ) pure nothrow { + private this(scope DBusError* err, string file = __FILE__, + size_t line = __LINE__, Throwable next = null) pure nothrow { import std.string : fromStringz; super(err.message.fromStringz().idup, file, line, next); @@ -41,37 +33,27 @@ class DBusException : Exception { of its actual value. +/ class TypeMismatchException : Exception { - package this( - int expectedType, - int actualType, - string file = __FILE__, - size_t line = __LINE__, - Throwable next = null - ) pure nothrow @safe { + package this(int expectedType, int actualType, string file = __FILE__, + size_t line = __LINE__, Throwable next = null) pure nothrow @safe { string message; + // dfmt off if (expectedType == 'v') { message = "The type of value at the current position in the message is" - ~ " incompatible to the target variant type." - ~ " Type code of the value: '" ~ cast(char) actualType ~ '\''; + ~ " incompatible to the target variant type." ~ " Type code of the value: '" + ~ cast(char) actualType ~ '\''; } else { message = "The type of value at the current position in the message does" - ~ " not match the type of value to be read." - ~ " Expected: '" ~ cast(char) expectedType ~ "'," - ~ " Got: '" ~ cast(char) actualType ~ '\''; + ~ " not match the type of value to be read." ~ " Expected: '" + ~ cast(char) expectedType ~ "'," ~ " Got: '" ~ cast(char) actualType ~ '\''; } + // dfmt on this(message, expectedType, actualType, file, line, next); } - this( - string message, - int expectedType, - int actualType, - string file = __FILE__, - size_t line = __LINE__, - Throwable next = null - ) pure nothrow @safe { + this(string message, int expectedType, int actualType, string file = __FILE__, + size_t line = __LINE__, Throwable next = null) pure nothrow @safe { _expectedType = expectedType; _actualType = actualType; super(message, file, line, next); @@ -85,7 +67,7 @@ class TypeMismatchException : Exception { return _actualType; } - private: +private: int _expectedType; int _actualType; } @@ -98,19 +80,15 @@ class TypeMismatchException : Exception { that have a constrained value set, such as Enums. +/ class InvalidValueException : Exception { - package this(Source)( - Source value, - string targetType, - string file = __FILE__, - size_t line = __LINE__, - Throwable next = null - ) { + package this(Source)(Source value, string targetType, string file = __FILE__, + size_t line = __LINE__, Throwable next = null) { import std.conv : to; - static if(__traits(compiles, value.to!string)) + static if (__traits(compiles, value.to!string)) { string valueString = value.to!string; - else + } else { string valueString = "(unprintable)"; + } super("Value " ~ valueString ~ " cannot be represented in type " ~ targetType); } diff --git a/source/ddbus/router.d b/source/ddbus/router.d index e107963..d4017a1 100644 --- a/source/ddbus/router.d +++ b/source/ddbus/router.d @@ -36,19 +36,20 @@ struct MessagePattern { hash += stringHash(&path); hash += stringHash(&iface); hash += stringHash(&method); - hash += (signal?1:0); + hash += (signal ? 1 : 0); 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); } } unittest { import dunit.toolkit; - auto msg = Message("org.example.test", "/test","org.example.testing","testMethod"); - auto patt= new MessagePattern(msg); + + auto msg = Message("org.example.test", "/test", "org.example.testing", "testMethod"); + auto patt = new MessagePattern(msg); patt.assertEqual(patt); patt.signal.assertFalse(); patt.path.assertEqual("/test"); @@ -66,30 +67,34 @@ class MessageRouter { bool handle(Message msg, Connection conn) { MessageType type = msg.type(); - if(type != MessageType.Call && type != MessageType.Signal) + if (type != MessageType.Call && type != MessageType.Signal) { return false; + } + auto pattern = MessagePattern(msg); // import std.stdio; debug writeln("Handling ", pattern); - if(pattern.iface == "org.freedesktop.DBus.Introspectable" && - pattern.method == "Introspect" && !pattern.signal) { + if (pattern.iface == "org.freedesktop.DBus.Introspectable" + && pattern.method == "Introspect" && !pattern.signal) { handleIntrospect(pattern.path, msg, conn); return true; } MessageHandler* handler = (pattern in callTable); - if(handler is null) return false; + if (handler is null) { + return false; + } // Check for matching argument types - version(DDBusNoChecking) { + version (DDBusNoChecking) { } else { - if(!equal(join(handler.argSig), msg.signature())) { + if (!equal(join(handler.argSig), msg.signature())) { return false; } } - handler.func(msg,conn); + handler.func(msg, conn); return true; } @@ -97,25 +102,39 @@ class MessageRouter { void handlerWrapper(Message call, Connection conn) { Tuple!Args args = call.readTuple!(Tuple!Args)(); auto retMsg = call.createReturn(); - static if(!is(Ret == void)) { + + static if (!is(Ret == void)) { Ret ret = handler(args.expand); - static if (is(Ret == Tuple!T, T...)) + static if (is(Ret == Tuple!T, T...)) { retMsg.build!T(ret.expand); - else + } else { retMsg.build(ret); + } } else { handler(args.expand); } - if(!patt.signal) + + if (!patt.signal) { conn.send(retMsg); + } } + static string[] args = typeSigArr!Args; - static if(is(Ret==void)) { + + static if (is(Ret == void)) { static string[] ret = []; } else { 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; } @@ -123,38 +142,50 @@ class MessageRouter { `; string introspectXML(string path) { - auto methods = callTable.byKey().filter!(a => (a.path == path) && !a.signal)().array() - // .schwartzSort!((a) => a.iface, "a a.iface < b.iface)(); + // dfmt off + auto methods = callTable + .byKey() + .filter!(a => (a.path == path) && !a.signal) + .array + .sort!((a, b) => a.iface < b.iface)(); + // dfmt on + auto ifaces = methods.groupBy(); auto app = appender!string; - formattedWrite(app,introspectHeader,path); - foreach(iface; ifaces) { - formattedWrite(app,``,iface.front.iface); - foreach(methodPatt; iface.array()) { - formattedWrite(app,``,methodPatt.method); + formattedWrite(app, introspectHeader, path); + foreach (iface; ifaces) { + formattedWrite(app, ``, iface.front.iface); + + foreach (methodPatt; iface.array()) { + formattedWrite(app, ``, methodPatt.method); auto handler = callTable[methodPatt]; - foreach(arg; handler.argSig) { - formattedWrite(app,``,arg); + + foreach (arg; handler.argSig) { + formattedWrite(app, ``, arg); } - foreach(arg; handler.retSig) { - formattedWrite(app,``,arg); + + foreach (arg; handler.retSig) { + formattedWrite(app, ``, arg); } + app.put(""); } + app.put(""); } string childPath = path; - if(!childPath.endsWith("/")) { + if (!childPath.endsWith("/")) { childPath ~= "/"; } - auto children = callTable.byKey().filter!(a => (a.path.startsWith(childPath)) && !a.signal)() - .map!((s) => s.path.chompPrefix(childPath)) - .map!((s) => s.splitter('/').front) - .array().sort().uniq(); - foreach(child; children) { - formattedWrite(app,``,child); + + auto children = callTable.byKey() + .filter!(a => (a.path.startsWith(childPath)) && !a.signal)().map!( + (s) => s.path.chompPrefix(childPath)).map!((s) => s.splitter('/') + .front).array().sort().uniq(); + + foreach (child; children) { + formattedWrite(app, ``, child); } app.put(""); @@ -168,31 +199,33 @@ class MessageRouter { } } -extern(C) private DBusHandlerResult filterFunc(DBusConnection *dConn, DBusMessage *dMsg, void *routerP) { - MessageRouter router = cast(MessageRouter)routerP; +extern (C) private DBusHandlerResult filterFunc(DBusConnection* dConn, + DBusMessage* dMsg, void* routerP) { + MessageRouter router = cast(MessageRouter) routerP; dbus_message_ref(dMsg); Message msg = Message(dMsg); dbus_connection_ref(dConn); Connection conn = Connection(dConn); bool handled = router.handle(msg, conn); - if(handled) { + + if (handled) { return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED; } else { return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } } -extern(C) private void unrootUserData(void *userdata) { +extern (C) private void unrootUserData(void* userdata) { GC.removeRoot(userdata); } void registerRouter(Connection conn, MessageRouter router) { - void *routerP = cast(void*)router; + void* routerP = cast(void*) router; GC.addRoot(routerP); dbus_connection_add_filter(conn.conn, &filterFunc, routerP, &unrootUserData); } -unittest{ +unittest { import dunit.toolkit; import std.typecons : BitFlags; @@ -200,31 +233,53 @@ unittest{ auto router = new MessageRouter(); // set up test messages - MessagePattern patt = MessagePattern("/root","ca.thume.test","test"); - router.setHandler!(int,int)(patt,(int p) {return 6;}); - patt = MessagePattern("/root","ca.thume.tester","lolwut"); - router.setHandler!(void,int,string)(patt,(int p, string p2) {}); - patt = MessagePattern("/root/wat","ca.thume.tester","lolwut"); - router.setHandler!(int,int)(patt,(int p) {return 6;}); - patt = MessagePattern("/root/bar","ca.thume.tester","lolwut"); - router.setHandler!(Variant!DBusAny,int)(patt,(int p) {return variant(DBusAny(p));}); - 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;}); - patt = MessagePattern("/troll","ca.thume.tester","wow"); - router.setHandler!(void)(patt,{return;}); + MessagePattern patt = MessagePattern("/root", "ca.thume.test", "test"); + router.setHandler!(int, int)(patt, (int p) { return 6; }); + patt = MessagePattern("/root", "ca.thume.tester", "lolwut"); + router.setHandler!(void, int, string)(patt, (int p, string p2) { }); + patt = MessagePattern("/root/wat", "ca.thume.tester", "lolwut"); + router.setHandler!(int, int)(patt, (int p) { return 6; }); + patt = MessagePattern("/root/bar", "ca.thume.tester", "lolwut"); + router.setHandler!(Variant!DBusAny, int)(patt, (int p) { + return variant(DBusAny(p)); + }); + 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; + }); + patt = MessagePattern("/troll", "ca.thume.tester", "wow"); + router.setHandler!(void)(patt, { return; }); + + patt = MessagePattern("/root/fancy", "ca.thume.tester", "crazyTest"); + enum F : ushort { + a = 1, + b = 8, + c = 16 + } + + struct S { + byte b; + ulong ul; + F f; + } - patt = MessagePattern("/root/fancy","ca.thume.tester","crazyTest"); - enum F : ushort { a = 1, b = 8, c = 16 } - struct S { byte b; ulong ul; F f; } router.setHandler!(int)(patt, (Algebraic!(ushort, BitFlags!F, S) v) { if (v.type is typeid(ushort) || v.type is typeid(BitFlags!F)) { return v.coerce!int; } else if (v.type is typeid(S)) { auto s = v.get!S; final switch (s.f) { - case F.a: return s.b; - case F.b: return cast(int) s.ul; - case F.c: return cast(int) s.ul + s.b; + case F.a: + return s.b; + case F.b: + return cast(int) s.ul; + case F.c: + return cast(int) s.ul + s.b; } } @@ -232,9 +287,9 @@ unittest{ }); static assert(!__traits(compiles, { - patt = MessagePattern("/root/bar","ca.thume.tester","lolwut"); - router.setHandler!(void, DBusAny)(patt,(DBusAny wrongUsage){return;}); - })); + patt = MessagePattern("/root/bar", "ca.thume.tester", "lolwut"); + router.setHandler!(void, DBusAny)(patt, (DBusAny wrongUsage) { return; }); + })); // TODO: these tests rely on nondeterministic hash map ordering static string introspectResult = ` @@ -246,5 +301,6 @@ unittest{ static string introspectResult3 = ` `; router.introspectXML("/root/fancy").assertEqual(introspectResult3); - router.introspectXML("/").assertEndsWith(``); + router.introspectXML("/") + .assertEndsWith(``); } diff --git a/source/ddbus/simple.d b/source/ddbus/simple.d index d58ac12..b602390 100644 --- a/source/ddbus/simple.d +++ b/source/ddbus/simple.d @@ -19,15 +19,16 @@ class PathIface { this.iface = iface.toStringz(); } - 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())); + 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())); msg.build(args); Message ret = conn.sendWithReplyBlocking(msg); return ret.read!Ret(); } Message opDispatch(string meth, Args...)(Args args) { - 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); return conn.sendWithReplyBlocking(msg); } @@ -40,12 +41,13 @@ class PathIface { unittest { import dunit.toolkit; + Connection conn = connectToBus(); - PathIface obj = new PathIface(conn, "org.freedesktop.DBus","/org/freedesktop/DBus", - "org.freedesktop.DBus"); + PathIface obj = new PathIface(conn, "org.freedesktop.DBus", + "/org/freedesktop/DBus", "org.freedesktop.DBus"); auto names = obj.GetNameOwner("org.freedesktop.DBus").to!string(); 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"); } enum SignalMethod; @@ -63,30 +65,39 @@ enum SignalMethod; could be instantiated with any object efficiently and placed in the router table with minimal duplication. */ void registerMethods(T : Object)(MessageRouter router, string path, string iface, T obj) { - MessagePattern patt = MessagePattern(path,iface,"",false); - foreach(member; __traits(allMembers, T)) { + MessagePattern patt = MessagePattern(path, iface, "", false); + foreach (member; __traits(allMembers, T)) { + // dfmt off static if (__traits(compiles, __traits(getOverloads, obj, member)) - && __traits(getOverloads, obj, member).length > 0 - && __traits(compiles, router.setHandler(patt, &__traits(getOverloads,obj,member)[0]))) { + && __traits(getOverloads, obj, member).length > 0 + && __traits(compiles, router.setHandler(patt, &__traits(getOverloads, obj, member)[0]))) { patt.method = member; - patt.signal = hasUDA!(__traits(getOverloads,obj,member)[0], SignalMethod); - router.setHandler(patt, &__traits(getOverloads,obj,member)[0]); + patt.signal = hasUDA!(__traits(getOverloads, obj, member)[0], SignalMethod); + router.setHandler(patt, &__traits(getOverloads, obj, member)[0]); } + // dfmt on } } unittest { import dunit.toolkit; + class Tester { - int lol(int x, string s, string[string] map, Variant!DBusAny any) {return 5;} - void wat() {} - @SignalMethod - void signalRecv() {} + int lol(int x, string s, string[string] map, Variant!DBusAny any) { + return 5; + } + + void wat() { + } + + @SignalMethod void signalRecv() { + } } + auto o = new Tester; auto router = new MessageRouter; - registerMethods(router, "/","ca.thume.test",o); - MessagePattern patt = MessagePattern("/","ca.thume.test","wat"); + registerMethods(router, "/", "ca.thume.test", o); + MessagePattern patt = MessagePattern("/", "ca.thume.test", "wat"); router.callTable.assertHasKey(patt); patt.method = "signalRecv"; patt.signal = true; @@ -95,6 +106,6 @@ unittest { patt.signal = false; router.callTable.assertHasKey(patt); auto res = router.callTable[patt]; - res.argSig.assertEqual(["i","s","a{ss}","v"]); + res.argSig.assertEqual(["i", "s", "a{ss}", "v"]); res.retSig.assertEqual(["i"]); } diff --git a/source/ddbus/thin.d b/source/ddbus/thin.d index 1425b18..8fd7e85 100644 --- a/source/ddbus/thin.d +++ b/source/ddbus/thin.d @@ -48,24 +48,28 @@ struct ObjectPath { } ObjectPath opBinary(string op : "~")(string rhs) const pure @safe { - if (!rhs.startsWith("/")) + if (!rhs.startsWith("/")) { return opBinary!"~"(ObjectPath("/" ~ rhs)); - else + } else { return opBinary!"~"(ObjectPath(rhs)); + } } ObjectPath opBinary(string op : "~")(ObjectPath rhs) const pure @safe in { assert(ObjectPath.isValid(_value) && ObjectPath.isValid(rhs._value)); - } out (v) { + } + out (v) { assert(ObjectPath.isValid(v._value)); - } body { + } + body { ObjectPath ret; - if (_value == "/") + if (_value == "/") { ret._value = rhs._value; - else + } else { ret._value = _value ~ rhs._value; + } return ret; } @@ -85,20 +89,21 @@ struct ObjectPath { static bool isValid(string objPath) pure @nogc nothrow @safe { import std.ascii : isAlphaNum; - if (!objPath.length) + if (!objPath.length) { return false; - if (objPath == "/") + } + + if (objPath == "/") { return true; - if (objPath[0] != '/' || objPath[$ - 1] == '/') + } + + if (objPath[0] != '/' || objPath[$ - 1] == '/') { return false; + } + // .representation to avoid unicode exceptions -> @nogc & nothrow - return objPath.representation.splitter('/').drop(1) - .all!(a => - a.length && - a.all!(c => - c.isAlphaNum || c == '_' - ) - ); + return objPath.representation.splitter('/').drop(1).all!(a => 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. bool explicitVariant; - union - { + union { /// byte int8; /// @@ -181,107 +185,125 @@ struct DBusAny { /// Automatically creates a DBusAny object with fitting parameters from a D type or Variant!T. /// Pass a `Variant!T` to make this an explicit variant. this(T)(T value) { - static if(is(T == byte) || is(T == ubyte)) { + static if (is(T == byte) || is(T == ubyte)) { this(typeCode!byte, null, false); int8 = cast(byte) value; - } else static if(is(T == short)) { + } else static if (is(T == short)) { this(typeCode!short, null, false); int16 = cast(short) value; - } else static if(is(T == ushort)) { + } else static if (is(T == ushort)) { this(typeCode!ushort, null, false); uint16 = cast(ushort) value; - } else static if(is(T == int)) { + } else static if (is(T == int)) { this(typeCode!int, null, false); int32 = cast(int) value; - } else static if(is(T == uint)) { + } else static if (is(T == uint)) { this(typeCode!uint, null, false); uint32 = cast(uint) value; - } else static if(is(T == long)) { + } else static if (is(T == long)) { this(typeCode!long, null, false); int64 = cast(long) value; - } else static if(is(T == ulong)) { + } else static if (is(T == ulong)) { this(typeCode!ulong, null, false); uint64 = cast(ulong) value; - } else static if(is(T == double)) { + } else static if (is(T == double)) { this(typeCode!double, null, false); float64 = cast(double) value; - } else static if(isSomeString!T) { + } else static if (isSomeString!T) { this(typeCode!string, null, false); str = value.to!string; - } else static if(is(T == bool)) { + } else static if (is(T == bool)) { this(typeCode!bool, null, false); boolean = cast(bool) value; - } else static if(is(T == ObjectPath)) { + } else static if (is(T == ObjectPath)) { this(typeCode!ObjectPath, null, false); obj = value; - } else static if(is(T == Variant!R, R)) { - static if(is(R == DBusAny)) { + } else static if (is(T == Variant!R, R)) { + static if (is(R == DBusAny)) { type = value.data.type; signature = value.data.signature; explicitVariant = true; - if(type == 'a' || type == 'r') { - if(signature == ['y']) + if (type == 'a' || type == 'r') { + if (signature == ['y']) { binaryData = value.data.binaryData; - else + } else { array = value.data.array; - } else if(type == 's') + } + } else if (type == 's') { str = value.data.str; - else if(type == 'e') + } else if (type == 'e') { entry = value.data.entry; - else + } else { uint64 = value.data.uint64; + } } else { this(value.data); explicitVariant = true; } - } else static if(is(T : DictionaryEntry!(K, V), K, V)) { + } else static if (is(T : DictionaryEntry!(K, V), K, V)) { this('e', null, false); entry = new DictionaryEntry!(DBusAny, DBusAny)(); - static if(is(K == DBusAny)) + static if (is(K == DBusAny)) { entry.key = value.key; - else + } else { entry.key = DBusAny(value.key); - static if(is(V == DBusAny)) + } + static if (is(V == DBusAny)) { entry.value = value.value; - else + } else { 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); binaryData = cast(ubyte[]) value; - } else static if(isInputRange!T) { + } else static if (isInputRange!T) { 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"); + this.signature = .typeSig!(ElementType!T); this.explicitVariant = false; - foreach(elem; value) + + foreach (elem; value) { array ~= DBusAny(elem); - } else static if(isTuple!T) { + } + } else static if (isTuple!T) { this.type = 'r'; this.signature = ['(']; this.explicitVariant = false; - foreach(index, R; value.Types) { + + foreach (index, R; value.Types) { auto var = DBusAny(value[index]); tuple ~= var; - if(var.explicitVariant) + + if (var.explicitVariant) { this.signature ~= 'v'; - else { - if (var.type != 'r') + } else { + if (var.type != 'r') { 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 ~= ')'; - } else static if(isAssociativeArray!T) { + } else static if (isAssociativeArray!T) { 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"); + } } /// string toString() const { string valueStr; - switch(type) { + switch (type) { case typeCode!byte: valueStr = int8.to!string; break; @@ -318,10 +340,12 @@ struct DBusAny { case 'a': import std.digest.digest : toHexString; - if(signature == ['y']) + if (signature == ['y']) { valueStr = "binary(" ~ binaryData.toHexString ~ ')'; - else + } else { valueStr = '[' ~ array.map!(a => a.toString).join(", ") ~ ']'; + } + break; case 'r': valueStr = '(' ~ tuple.map!(a => a.toString).join(", ") ~ ')'; @@ -333,10 +357,9 @@ struct DBusAny { valueStr = "unknown"; break; } - return "DBusAny(" ~ cast(char) type - ~ ", \"" ~ signature.idup - ~ "\", " ~ (explicitVariant ? "explicit" : "implicit") - ~ ", " ~ valueStr ~ ")"; + + return "DBusAny(" ~ cast(char) type ~ ", \"" ~ signature.idup ~ "\", " ~ (explicitVariant + ? "explicit" : "implicit") ~ ", " ~ valueStr ~ ")"; } /++ @@ -354,24 +377,21 @@ struct DBusAny { DBusAny object is not the same as the DBus type used to represent T. +/ T get(T)() @property const - if(staticIndexOf!(T, BasicTypes) >= 0) - { - enforce(type == typeCode!T, - new TypeMismatchException( - "Cannot get a " ~ T.stringof ~ " from a DBusAny with" - ~ " a value of DBus type '" ~ typeSig ~ "'.", typeCode!T, type)); + if (staticIndexOf!(T, BasicTypes) >= 0) { + 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; + static if (isIntegral!T) { + enum memberName = (isUnsigned!T ? "uint" : "int") ~ (T.sizeof * 8).to!string; return __traits(getMember, this, memberName); - } else static if(is(T == double)) { + } else static if (is(T == double)) { return float64; - } else static if(is(T == string)) { + } else static if (is(T == string)) { return str; - } else static if(is(T == ObjectPath)) { + } else static if (is(T == ObjectPath)) { return obj; - } else static if(is(T == bool)) { + } else static if (is(T == bool)) { return boolean; } else { static assert(false); @@ -380,12 +400,9 @@ struct DBusAny { /// ditto T get(T)() @property const - if(is(T == const(DBusAny)[])) - { - enforce((type == 'a' && signature != "y") || type == 'r', - new TypeMismatchException( - "Cannot get a " ~ T.stringof ~ " from a DBusAny with" - ~ " a value of DBus type '" ~ this.typeSig ~ "'.", + if (is(T == const(DBusAny)[])) { + enforce((type == 'a' && signature != "y") || type == 'r', new TypeMismatchException( + "Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ this.typeSig ~ "'.", typeCode!T, type)); return array; @@ -393,12 +410,9 @@ struct DBusAny { /// ditto T get(T)() @property const - if (is(T == const(ubyte)[])) - { - enforce(type == 'a' && signature == "y", - new TypeMismatchException( - "Cannot get a " ~ T.stringof ~ " from a DBusAny with" - ~ " a value of DBus type '" ~ this.typeSig ~ "'.", + if (is(T == const(ubyte)[])) { + enforce(type == 'a' && signature == "y", new TypeMismatchException( + "Cannot get a " ~ T.stringof ~ " from a DBusAny with" ~ " a value of DBus type '" ~ this.typeSig ~ "'.", typeCode!T, type)); return binaryData; @@ -408,10 +422,12 @@ struct DBusAny { DBusAny[DBusAny] toAA() { enforce(type == 'a' && signature && signature[0] == '{'); DBusAny[DBusAny] aa; - foreach(val; array) { + + foreach (val; array) { enforce(val.type == 'e'); aa[val.entry.key] = val.entry.value; } + return aa; } @@ -421,34 +437,34 @@ struct DBusAny { Returns: The type signature of the value stored in this DBusAny object. +/ - string typeSig() @property const pure nothrow @safe - { - if(type == 'a') { + string typeSig() @property const pure nothrow @safe { + if (type == 'a') { return "a" ~ signature; - } else if(type == 'r') { + } else if (type == 'r') { return signature; - } else if(type == 'e') { - return () @trusted { + } else if (type == 'e') { + return () @trusted{ return "{" ~ entry.key.signature ~ entry.value.signature ~ "}"; - } (); + }(); } else { - return [ cast(char) type ]; + return [cast(char) type]; } } /// Converts a basic type, a tuple or an array to the D type with type checking. Tuples can get converted to an array too. T to(T)() { - static if(is(T == Variant!R, R)) { - static if(is(R == DBusAny)) { + static if (is(T == Variant!R, R)) { + static if (is(R == DBusAny)) { auto v = to!R; v.explicitVariant = false; return Variant!R(v); - } else + } else { return Variant!R(to!R); - } else static if(is(T == DBusAny)) { + } + } else static if (is(T == DBusAny)) { return this; - } else static if(isIntegral!T || isFloatingPoint!T) { - switch(type) { + } else static if (isIntegral!T || isFloatingPoint!T) { + switch (type) { case typeCode!byte: return cast(T) int8; case typeCode!short: @@ -468,79 +484,106 @@ struct DBusAny { default: throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); } - } else static if(is(T == bool)) { - if(type == 'b') + } else static if (is(T == bool)) { + if (type == 'b') { return boolean; - else + } else { throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); - } else static if(isSomeString!T) { - if(type == 's') + } + } else static if (isSomeString!T) { + if (type == 's') { return str.to!T; - else if(type == 'o') + } else if (type == 'o') { return obj.toString(); - else + } else { throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); - } else static if(is(T == ObjectPath)) { - if(type == 'o') + } + } else static if (is(T == ObjectPath)) { + if (type == 'o') { return obj; - else + } else { throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); - } else static if(isDynamicArray!T) { - if(type != 'a' && type != 'r') + } + } else static if (isDynamicArray!T) { + if (type != 'a' && type != 'r') { throw new Exception("Can't convert type " ~ cast(char) type ~ " to an array"); + } + T ret; - if(signature == ['y']) { - static if(isIntegral!(ElementType!T)) - foreach(elem; binaryData) + if (signature == ['y']) { + static if (isIntegral!(ElementType!T)) { + foreach (elem; binaryData) { ret ~= elem.to!(ElementType!T); - } else - foreach(elem; array) + } + } + } else { + foreach (elem; array) { ret ~= elem.to!(ElementType!T); + } + } + return ret; - } else static if(isTuple!T) { - if(type != 'r') + } else static if (isTuple!T) { + if (type != 'r') { throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); + } + T ret; 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; + } + return ret; - } else static if(isAssociativeArray!T) { - if(type != 'a' || !signature || signature[0] != '{') + } else static if (isAssociativeArray!T) { + if (type != 'a' || !signature || signature[0] != '{') { throw new Exception("Can't convert type " ~ cast(char) type ~ " to " ~ T.stringof); + } + T ret; - foreach(pair; array) { + foreach (pair; array) { enforce(pair.type == 'e'); ret[pair.entry.key.to!(KeyType!T)] = pair.entry.value.to!(ValueType!T); } + 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 { - if(b.type != type || b.explicitVariant != explicitVariant) + if (b.type != type || b.explicitVariant != explicitVariant) { return false; - if((type == 'a' || type == 'r') && b.signature != signature) + } + + if ((type == 'a' || type == 'r') && b.signature != signature) { return false; - if(type == 'a' && signature == ['y']) + } + + if (type == 'a' && signature == ['y']) { return binaryData == b.binaryData; - if(type == 'a') + } + + if (type == 'a') { return array == b.array; - else if(type == 'r') + } else if (type == 'r') { return tuple == b.tuple; - else if(type == 's') + } else if (type == 's') { return str == b.str; - else if(type == 'o') + } else if (type == 'o') { return obj == b.obj; - else if(type == 'e') + } else if (type == 'e') { return entry == b.entry || (entry && b.entry && *entry == *b.entry); - else + } else { return uint64 == b.uint64; + } } } unittest { import dunit.toolkit; + DBusAny set(string member, T)(DBusAny v, T value) { mixin("v." ~ member ~ " = value;"); return v; @@ -549,12 +592,14 @@ unittest { void test(T)(T value, DBusAny b) { assertEqual(DBusAny(value), b); - static if(is(T == Variant!R, R)) { - static if(__traits(compiles, b.get!R)) + static if (is(T == Variant!R, R)) { + static if (__traits(compiles, b.get!R)) { assertEqual(b.get!R, value.data); + } } else { - static if(__traits(compiles, b.get!T)) + static if (__traits(compiles, b.get!T)) { assertEqual(b.get!T, value); + } } assertEqual(b.to!T, value); @@ -569,7 +614,8 @@ unittest { 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(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(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(ulong) 184), set!"uint64"(DBusAny('t', null, true), cast(ulong) 184)); 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([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", variant(4), variant([1, 2])), set!"tuple"(DBusAny('r', "(svv)", false), [DBusAny("a"), DBusAny(variant(4)), DBusAny(variant([1, 2]))])); + test(tuple("a", 4, [1, 2]), set!"tuple"(DBusAny('r', "(siai)".dup, false), + [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([variant("a"): 4], set!"array"(DBusAny('a', "{vi}", false), [DBusAny(DictionaryEntry!(DBusAny, DBusAny)(DBusAny(variant("a")), DBusAny(4)))])); + test(["a" : "b"], set!"array"(DBusAny('a', "{ss}", false), + [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 @@ -605,17 +657,21 @@ Variant!T variant(T)(T data) { enum MessageType { Invalid = 0, - Call, Return, Error, Signal + Call, + Return, + Error, + Signal } struct Message { - DBusMessage *msg; + DBusMessage* msg; 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) { msg = m; } @@ -627,7 +683,8 @@ struct Message { dbus_message_unref(msg); } - void build(TS...)(TS args) if(allCanDBus!TS) { + void build(TS...)(TS args) + if (allCanDBus!TS) { DBusMessageIter iter; dbus_message_iter_init_append(msg, &iter); buildIter(&iter, args); @@ -639,14 +696,17 @@ struct Message { read the first argument. This is suitable for single item returns. To read multiple arguments use readTuple. */ - T read(T)() if(canDBus!T) { + T read(T)() + if (canDBus!T) { DBusMessageIter iter; dbus_message_iter_init(msg, &iter); return readIter!T(&iter); } + alias read to; - Tup readTuple(Tup)() if(isTuple!Tup && allCanDBus!(Tup.Types)) { + Tup readTuple(Tup)() + if (isTuple!Tup && allCanDBus!(Tup.Types)) { DBusMessageIter iter; dbus_message_iter_init(msg, &iter); Tup ret; @@ -659,7 +719,7 @@ struct Message { } MessageType type() { - return cast(MessageType)dbus_message_get_type(msg); + return cast(MessageType) dbus_message_get_type(msg); } bool isCall() { @@ -673,21 +733,25 @@ struct Message { assert(cStr != null); return cStr.fromStringz().idup; } + string path() { const(char)* cStr = dbus_message_get_path(msg); assert(cStr != null); return cStr.fromStringz().idup; } + string iface() { const(char)* cStr = dbus_message_get_interface(msg); assert(cStr != null); return cStr.fromStringz().idup; } + string member() { const(char)* cStr = dbus_message_get_member(msg); assert(cStr != null); return cStr.fromStringz().idup; } + string sender() { const(char)* cStr = dbus_message_get_sender(msg); assert(cStr != null); @@ -697,13 +761,14 @@ struct Message { unittest { 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"); } struct Connection { - DBusConnection *conn; - this(DBusConnection *connection) { + DBusConnection* conn; + this(DBusConnection* connection) { conn = connection; } @@ -720,7 +785,7 @@ struct Connection { } void send(Message msg) { - dbus_connection_send(conn,msg.msg, null); + dbus_connection_send(conn, msg.msg, null); } void sendBlocking(Message msg) { @@ -729,13 +794,13 @@ struct Connection { } Message sendWithReplyBlocking(Message msg, int timeout = -1) { - DBusMessage *dbusMsg = msg.msg; + DBusMessage* dbusMsg = msg.msg; dbus_message_ref(dbusMsg); - DBusMessage *reply = wrapErrors((err) { - auto ret = dbus_connection_send_with_reply_and_block(conn,dbusMsg,timeout,err); - dbus_message_unref(dbusMsg); - return ret; - }); + DBusMessage* reply = wrapErrors((err) { + auto ret = dbus_connection_send_with_reply_and_block(conn, dbusMsg, timeout, err); + dbus_message_unref(dbusMsg); + return ret; + }); return Message(reply); } @@ -758,7 +823,7 @@ unittest { struct S2 { int h, i; @(Yes.DBusMarshal) int j, k; - int *p; + int* p; } @dbusMarshaling(MarshalingFlag.includePrivateFields) @@ -774,40 +839,32 @@ unittest { __gshared int dummy; - enum testStruct = S3( - variant(5), "blah", - S1(-7, 63.5, "test"), - S2(84, -123, 78, 432, &dummy), - 16 - ); + enum testStruct = S3(variant(5), "blah", S1(-7, 63.5, "test"), S2(84, -123, + 78, 432, &dummy), 16); msg.build(testStruct); // Non-marshaled fields should appear as freshly initialized - enum expectedResult = S3( - variant(5), "blah", - S1(int.init, 63.5, "test"), - S2(int.init, int.init, 78, 432, null), - uint.init - ); + enum expectedResult = S3(variant(5), "blah", S1(int.init, 63.5, "test"), + S2(int.init, int.init, 78, 432, null), uint.init); msg.read!S3().assertEqual(expectedResult); - } Connection connectToBus(DBusBusType bus = DBusBusType.DBUS_BUS_SESSION) { - DBusConnection *conn = wrapErrors((err) { return dbus_bus_get(bus,err); }); + DBusConnection* conn = wrapErrors((err) { return dbus_bus_get(bus, err); }); return Connection(conn); } unittest { import dunit.toolkit; + // This test will only pass if DBus is installed. Connection conn = connectToBus(); conn.conn.assertTruthy(); // We can only count on no system bus on OSX - version(OSX) { + version (OSX) { connectToBus(DBusBusType.DBUS_BUS_SYSTEM).assertThrow!DBusException(); } } diff --git a/source/ddbus/util.d b/source/ddbus/util.d index 4254a19..7ffc108 100644 --- a/source/ddbus/util.d +++ b/source/ddbus/util.d @@ -26,12 +26,10 @@ auto byDictionaryEntries(K, V)(V[K] aa) { Its meaning became unclear when support for Phobos-style variants was added. It seemed best to remove it at that point. +/ -deprecated("Use std.traits.isInstanceOf instead.") -template isVariant(T) { - static if(isBasicType!T || isInputRange!T) { +deprecated("Use std.traits.isInstanceOf instead.") template isVariant(T) { + static if (isBasicType!T || isInputRange!T) { enum isVariant = false; - } else static if(__traits(compiles, TemplateOf!T) - && __traits(isSame, TemplateOf!T, Variant)) { + } else static if (__traits(compiles, TemplateOf!T) && __traits(isSame, TemplateOf!T, Variant)) { enum isVariant = true; } else { enum isVariant = false; @@ -44,38 +42,27 @@ template VariantType(T) { template allCanDBus(TS...) { static if (TS.length == 0) { - enum allCanDBus = true; - } else static if(!canDBus!(TS[0])) { + enum allCanDBus = true; + } else static if (!canDBus!(TS[0])) { enum allCanDBus = false; } else { - enum allCanDBus = allCanDBus!(TS[1..$]); + enum allCanDBus = allCanDBus!(TS[1 .. $]); } } /++ 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 -alias BasicTypes = AliasSeq!( - bool, - byte, - short, - ushort, - int, - uint, - long, - ulong, - double, - string, - ObjectPath -); +package // Don't add to the API yet, 'cause I intend to move it later +alias BasicTypes = AliasSeq!(bool, byte, short, ushort, int, uint, long, ulong, + double, string, ObjectPath); template basicDBus(T) { - static if(staticIndexOf!(T, BasicTypes) >= 0) { + static if (staticIndexOf!(T, BasicTypes) >= 0) { enum basicDBus = true; - } else static if(is(T B == enum)) { + } else static if (is(T B == enum)) { enum basicDBus = basicDBus!B; - } else static if(isInstanceOf!(BitFlags, T)) { + } else static if (isInstanceOf!(BitFlags, T)) { alias TemplateArgsOf!T[0] E; enum basicDBus = basicDBus!E; } else { @@ -84,24 +71,24 @@ template basicDBus(T) { } template canDBus(T) { - static if(basicDBus!T || is(T == DBusAny)) { + static if (basicDBus!T || is(T == DBusAny)) { enum canDBus = true; - } else static if(isInstanceOf!(Variant, T)) { + } else static if (isInstanceOf!(Variant, T)) { enum canDBus = canDBus!(VariantType!T); - } else static if(isInstanceOf!(VariantN, T)) { + } else static if (isInstanceOf!(VariantN, T)) { // Phobos-style variants are supported if limited to DBus compatible types. enum canDBus = (T.AllowedTypes.length > 0) && allCanDBus!(T.AllowedTypes); - } else static if(isTuple!T) { + } else static if (isTuple!T) { enum canDBus = allCanDBus!(T.Types); - } else static if(isInputRange!T) { - static if(is(ElementType!T == DictionaryEntry!(K, V), K, V)) { + } else static if (isInputRange!T) { + static if (is(ElementType!T == DictionaryEntry!(K, V), K, V)) { enum canDBus = basicDBus!K && canDBus!V; } else { enum canDBus = canDBus!(ElementType!T); } - } else static if(isAssociativeArray!T) { + } else static if (isAssociativeArray!T) { enum canDBus = basicDBus!(KeyType!T) && canDBus!(ValueType!T); - } else static if(is(T == struct) && !isInstanceOf!(DictionaryEntry, T)) { + } else static if (is(T == struct) && !isInstanceOf!(DictionaryEntry, T)) { enum canDBus = allCanDBus!(AllowedFieldTypes!T); } else { enum canDBus = false; @@ -110,60 +97,63 @@ template canDBus(T) { unittest { import dunit.toolkit; + (canDBus!int).assertTrue(); (canDBus!(int[])).assertTrue(); - (allCanDBus!(int,string,bool)).assertTrue(); - (canDBus!(Tuple!(int[],bool,Variant!short))).assertTrue(); - (canDBus!(Tuple!(int[],int[string]))).assertTrue(); + (allCanDBus!(int, string, bool)).assertTrue(); + (canDBus!(Tuple!(int[], bool, Variant!short))).assertTrue(); + (canDBus!(Tuple!(int[], int[string]))).assertTrue(); (canDBus!(int[string])).assertTrue(); } -string typeSig(T)() if(canDBus!T) { - static if(is(T == byte)) { +string typeSig(T)() + if (canDBus!T) { + static if (is(T == byte)) { return "y"; - } else static if(is(T == bool)) { + } else static if (is(T == bool)) { return "b"; - } else static if(is(T == short)) { + } else static if (is(T == short)) { return "n"; - } else static if(is(T == ushort)) { + } else static if (is(T == ushort)) { return "q"; - } else static if(is(T == int)) { + } else static if (is(T == int)) { return "i"; - } else static if(is(T == uint)) { + } else static if (is(T == uint)) { return "u"; - } else static if(is(T == long)) { + } else static if (is(T == long)) { return "x"; - } else static if(is(T == ulong)) { + } else static if (is(T == ulong)) { return "t"; - } else static if(is(T == double)) { + } else static if (is(T == double)) { return "d"; - } else static if(is(T == string)) { + } else static if (is(T == string)) { return "s"; - } else static if(is(T == ObjectPath)) { + } else static if (is(T == ObjectPath)) { return "o"; - } else static if(isInstanceOf!(Variant, T) || isInstanceOf!(VariantN, T)) { + } else static if (isInstanceOf!(Variant, T) || isInstanceOf!(VariantN, T)) { return "v"; - } else static if(is(T B == enum)) { + } else static if (is(T B == enum)) { return typeSig!B; - } else static if(isInstanceOf!(BitFlags, T)) { + } else static if (isInstanceOf!(BitFlags, T)) { alias TemplateArgsOf!T[0] E; return typeSig!E; - } else static if(is(T == DBusAny)) { - 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 (is(T == DBusAny)) { + static assert(false, + "Cannot determine type signature of DBusAny. Change to Variant!DBusAny if a variant was desired."); + } else static if (isTuple!T) { string sig = "("; - foreach(i, S; T.Types) { + foreach (i, S; T.Types) { sig ~= typeSig!S(); - } + } sig ~= ")"; return sig; - } else static if(isInputRange!T) { + } else static if (isInputRange!T) { return "a" ~ typeSig!(ElementType!T)(); - } else static if(isAssociativeArray!T) { + } else static if (isAssociativeArray!T) { return "a{" ~ typeSig!(KeyType!T) ~ typeSig!(ValueType!T) ~ "}"; - } else static if(is(T == struct)) { + } else static if (is(T == struct)) { string sig = "("; - foreach(i, S; AllowedFieldTypes!T) { + foreach (i, S; AllowedFieldTypes!T) { sig ~= typeSig!S(); } sig ~= ")"; @@ -171,66 +161,99 @@ 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.value) V; return "{" ~ typeSig!K ~ typeSig!V ~ '}'; } -string[] typeSigReturn(T)() if(canDBus!T) { - static if(is(T == Tuple!TS, TS...)) +string[] typeSigReturn(T)() + if (canDBus!T) { + static if (is(T == Tuple!TS, TS...)) return typeSigArr!TS; else return [typeSig!T]; } -string typeSigAll(TS...)() if(allCanDBus!TS) { +string typeSigAll(TS...)() + if (allCanDBus!TS) { string sig = ""; - foreach(i,T; TS) { + foreach (i, T; TS) { sig ~= typeSig!T(); } return sig; } -string[] typeSigArr(TS...)() if(allCanDBus!TS) { +string[] typeSigArr(TS...)() + if (allCanDBus!TS) { string[] sig = []; - foreach(i,T; TS) { + foreach (i, T; TS) { sig ~= typeSig!T(); } return sig; } -int typeCode(T)() if(canDBus!T) { +int typeCode(T)() + if (canDBus!T) { int code = typeSig!T()[0]; return (code != '(') ? code : 'r'; } -int typeCode(T)() if(isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) { +int typeCode(T)() + if (isInstanceOf!(DictionaryEntry, T) && canDBus!(T[])) { return 'e'; } unittest { import dunit.toolkit; + // basics typeSig!int().assertEqual("i"); typeSig!bool().assertEqual("b"); typeSig!string().assertEqual("s"); typeSig!(Variant!int)().assertEqual("v"); // enums - enum E : byte { a, b, c } + enum E : byte { + a, + b, + c + } + typeSig!E().assertEqual(typeSig!byte()); - enum U : string { One = "One", Two = "Two" } + enum U : string { + One = "One", + Two = "Two" + } + typeSig!U().assertEqual(typeSig!string()); // 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()); // tuples (represented as structs in DBus) - 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, string)).assertEqual("(iss)"); + typeSig!(Tuple!(int, string, Variant!int, Tuple!(int, "k", double, "x"))).assertEqual( + "(isv(id))"); // structs - struct S1 { int a; double b; string s; } + struct S1 { + int a; + double b; + string s; + } + 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)"); // arrays typeSig!(int[]).assertEqual("ai"); @@ -240,7 +263,7 @@ unittest { typeSig!(int[string]).assertEqual("a{si}"); typeSig!(DictionaryEntry!(string, int)[]).assertEqual("a{si}"); // multiple arguments - typeSigAll!(int,bool).assertEqual("ib"); + typeSigAll!(int, bool).assertEqual("ib"); // Phobos-style variants canDBus!(std.variant.Variant).assertFalse(); typeSig!(std.variant.Algebraic!(int, double, string)).assertEqual("v"); @@ -251,17 +274,18 @@ unittest { // ctfe-capable static string sig = typeSig!ulong(); sig.assertEqual("t"); - static string sig2 = typeSig!(Tuple!(int,string,string)); - sig2.assertEqual("(iss)"); - static string sig3 = typeSigAll!(int,string,string); - sig3.assertEqual("iss"); + static string sig2 = typeSig!(Tuple!(int, string, string)); + sig2.assertEqual("(iss)"); + static string sig3 = typeSigAll!(int, string, string); + sig3.assertEqual("iss"); } -private template AllowedFieldTypes(S) if (is(S == struct)) { +private template AllowedFieldTypes(S) + if (is(S == struct)) { import ddbus.attributes : isAllowedField; import std.meta : Filter, staticMap; + static alias TypeOf(alias sym) = typeof(sym); - alias AllowedFieldTypes = - staticMap!(TypeOf, Filter!(isAllowedField, S.tupleof)); + alias AllowedFieldTypes = staticMap!(TypeOf, Filter!(isAllowedField, S.tupleof)); }