diff --git a/source/ddbus/conv.d b/source/ddbus/conv.d index b2e346a..08acb2e 100644 --- a/source/ddbus/conv.d +++ b/source/ddbus/conv.d @@ -61,8 +61,12 @@ void buildIter(TS...)(DBusMessageIter *iter, TS args) if(allCanDBus!TS) { } else if(val.type == 'a') { DBusMessageIter arr; dbus_message_iter_open_container(sub, 'a', sig[1 .. $].ptr, &arr); - foreach(item; val.array) - buildIter(&arr, item); + if (val.signature == ['y']) + foreach (item; val.binaryData) + dbus_message_iter_append_basic(&arr, 'y', &item); + else + foreach(item; val.array) + buildIter(&arr, item); dbus_message_iter_close_container(sub, &arr); } else if(val.type == 'r') { DBusMessageIter arr; @@ -175,9 +179,18 @@ T readIter(T)(DBusMessageIter *iter) if (canDBus!T) { auto sig = dbus_message_iter_get_signature(&sub); ret.signature = sig.fromStringz.dup; dbus_free(sig); - while(dbus_message_iter_get_arg_type(&sub) != 0) { - ret.array ~= readIter!DBusAny(&sub); - } + 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) { + ret.array ~= readIter!DBusAny(&sub); + } } else if(ret.type == 'r') { auto sig = dbus_message_iter_get_signature(iter); ret.signature = sig.fromStringz.dup; @@ -223,7 +236,8 @@ unittest { Variant!DBusAny complexVar = variant(DBusAny([ "hello world": variant(DBusAny(1337)), "array value": variant(DBusAny([42, 64])), - "tuple value": variant(tupleMember) + "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); diff --git a/source/ddbus/thin.d b/source/ddbus/thin.d index f6e64f7..59a6e50 100644 --- a/source/ddbus/thin.d +++ b/source/ddbus/thin.d @@ -68,6 +68,8 @@ struct DBusAny { DBusAny[] tuple; /// DictionaryEntry!(DBusAny, DBusAny)* entry; + /// + ubyte[] binaryData; } /// Manually creates a DBusAny object using a type, signature and implicit specifier. @@ -115,9 +117,12 @@ struct DBusAny { type = value.data.type; signature = value.data.signature; explicitVariant = true; - if(type == 'a' || type == 'r') - array = value.data.array; - if(type == 's') + if(type == 'a' || type == 'r') { + if(signature == ['y']) + binaryData = value.data.binaryData; + else + array = value.data.array; + } else if(type == 's') str = value.data.str; else if(type == 'e') entry = value.data.entry; @@ -138,9 +143,13 @@ struct DBusAny { entry.value = value.value; else entry.value = DBusAny(value.value); + } else static if(is(T == ubyte[]) || is(T == byte[])) { + this('a', ['y'], false); + binaryData = cast(ubyte[]) value; } 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(typeSig!(ElementType!T) != "y"); this.signature = typeSig!(ElementType!T).dup; this.explicitVariant = false; foreach(elem; value) @@ -202,7 +211,12 @@ struct DBusAny { valueStr = boolean ? "true" : "false"; break; case 'a': - valueStr = '[' ~ array.map!(a => a.toString).join(", ") ~ ']'; + import std.digest.digest : toHexString; + + if(signature == ['y']) + valueStr = "binary(" ~ binaryData.toHexString ~ ')'; + else + valueStr = '[' ~ array.map!(a => a.toString).join(", ") ~ ']'; break; case 'r': valueStr = '(' ~ array.map!(a => a.toString).join(", ") ~ ')'; @@ -277,8 +291,13 @@ struct DBusAny { if(type != 'a' && type != 'r') throw new Exception("Can't convert type " ~ cast(char) type ~ " to an array"); T ret; - foreach(elem; array) - ret ~= elem.to!(ElementType!T); + if(signature == ['y']) { + static if(isIntegral!(ElementType!T)) + foreach(elem; binaryData) + ret ~= elem.to!(ElementType!T); + } else + foreach(elem; array) + ret ~= elem.to!(ElementType!T); return ret; } else static if(isTuple!T) { if(type != 'r') @@ -303,6 +322,8 @@ struct DBusAny { return false; if((type == 'a' || type == 'r') && b.signature != signature) return false; + if(type == 'a' && signature == ['y']) + return binaryData == b.binaryData; if(type == 'a') return array == b.array; else if(type == 'r') @@ -337,6 +358,7 @@ 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(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)); @@ -346,6 +368,7 @@ 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(DBusAny(5)), set!"int32"(DBusAny('i', null, true), 5));