diff --git a/bench/unmarshall_interfaces_removed.py b/bench/unmarshall_interfaces_removed.py new file mode 100644 index 0000000..d3f4fb7 --- /dev/null +++ b/bench/unmarshall_interfaces_removed.py @@ -0,0 +1,31 @@ +import io +import timeit + +from dbus_fast._private.unmarshaller import Unmarshaller + +# cythonize -X language_level=3 -a -i src/dbus_fast/_private/unmarshaller.py + + +bluez_interfaces_removed_message = ( + b'l\4\1\1\222\0\0\0\377@-\0~\0\0\0\1\1o\0\1\0\0\0/\0\0\0\0\0\0\0\2\1s\0"\0\0\0' + b"org.freedesktop.DBus.ObjectManager\0\0\0\0\0\0\3\1s\0\21\0\0\0InterfacesRemoved" + b"\0\0\0\0\0\0\0\10\1g\0\3oas\0\0\0\0\0\0\0\0\7\1s\0\5\0\0\0:1.12\0\0\0%\0\0\0" + b"/org/bluez/hci0/dev_5F_13_47_38_26_55\0\0\0b\0\0\0\37\0\0\0org.freedesktop.DBus" + b".Properties\0#\0\0\0org.freedesktop.DBus.Introspectable\0\21\0\0\0org.bluez.Dev" + b"ice1\0" +) + + +stream = io.BytesIO(bluez_interfaces_removed_message) +unmarshaller = Unmarshaller(stream) + + +def unmarshall_interfaces_removed_message(): + stream.seek(0) + unmarshaller.reset() + unmarshaller.unmarshall() + + +count = 3000000 +time = timeit.Timer(unmarshall_interfaces_removed_message).timeit(count) +print(f"Unmarshalling {count} bluetooth InterfacesRemoved messages took {time} seconds") diff --git a/src/dbus_fast/_private/unmarshaller.pxd b/src/dbus_fast/_private/unmarshaller.pxd index 2cf713e..93dc5fe 100644 --- a/src/dbus_fast/_private/unmarshaller.pxd +++ b/src/dbus_fast/_private/unmarshaller.pxd @@ -52,6 +52,8 @@ cdef object SIGNATURE_TREE_A_SV_TYPES_0 cdef object SIGNATURE_TREE_SA_SV_AS cdef object SIGNATURE_TREE_SA_SV_AS_TYPES_1 cdef object SIGNATURE_TREE_SA_SV_AS_TYPES_2 +cdef object SIGNATURE_TREE_OAS +cdef object SIGNATURE_TREE_OAS_TYPES_1 cdef object SIGNATURE_TREE_OA_SA_SV cdef object SIGNATURE_TREE_OA_SA_SV_TYPES_1 cdef object SIGNATURE_TREE_AY diff --git a/src/dbus_fast/_private/unmarshaller.py b/src/dbus_fast/_private/unmarshaller.py index 41a9bf6..24fb3d0 100644 --- a/src/dbus_fast/_private/unmarshaller.py +++ b/src/dbus_fast/_private/unmarshaller.py @@ -70,6 +70,9 @@ SIGNATURE_TREE_AS_TYPES_0 = SIGNATURE_TREE_AS.types[0] SIGNATURE_TREE_A_SV = get_signature_tree("a{sv}") SIGNATURE_TREE_A_SV_TYPES_0 = SIGNATURE_TREE_A_SV.types[0] +SIGNATURE_TREE_OAS = get_signature_tree("oas") +SIGNATURE_TREE_OAS_TYPES_1 = SIGNATURE_TREE_OAS.types[1] + SIGNATURE_TREE_AY_TYPES_0 = SIGNATURE_TREE_AY.types[0] SIGNATURE_TREE_A_QV = get_signature_tree("a{qv}") SIGNATURE_TREE_A_QV_TYPES_0 = SIGNATURE_TREE_A_QV.types[0] @@ -417,8 +420,9 @@ class Unmarshaller: if token == "{": result_dict = {} beginning_pos = self._pos - child_0 = child_type.children[0] - child_1 = child_type.children[1] + children = child_type.children + child_0 = children[0] + child_1 = children[1] child_0_token = child_0.token child_1_token = child_1.token # Strings with variant values are the most common case @@ -442,7 +446,6 @@ class Unmarshaller: else: reader_1 = self._readers[child_1_token] reader_0 = self._readers[child_0_token] - while self._pos - beginning_pos < array_length: self._pos += -self._pos & 7 # align 8 key = reader_0(self, child_0) @@ -455,7 +458,11 @@ class Unmarshaller: result_list = [] beginning_pos = self._pos - reader = self._readers[child_type.token] + if token in "os": + while self._pos - beginning_pos < array_length: + result_list.append(self._read_string_unpack()) + return result_list + reader = self._readers[token] while self._pos - beginning_pos < array_length: result_list.append(reader(self, child_type)) return result_list @@ -568,6 +575,12 @@ class Unmarshaller: self._read_string_unpack(), self._read_array(SIGNATURE_TREE_OA_SA_SV_TYPES_1), ] + elif signature == "oas": + tree = SIGNATURE_TREE_OAS + body = [ + self._read_string_unpack(), + self._read_array(SIGNATURE_TREE_OAS_TYPES_1), + ] else: tree = get_signature_tree(signature) body = [self._readers[t.token](self, t) for t in tree.types] diff --git a/tests/test_marshaller.py b/tests/test_marshaller.py index 091e149..58fa311 100644 --- a/tests/test_marshaller.py +++ b/tests/test_marshaller.py @@ -321,6 +321,49 @@ def test_unmarshall_bluez_interfaces_added_message(): ] +def test_unmarshall_bluez_interfaces_removed_message(): + bluez_interfaces_removed_message = ( + b'l\4\1\1\222\0\0\0\377@-\0~\0\0\0\1\1o\0\1\0\0\0/\0\0\0\0\0\0\0\2\1s\0"\0\0\0' + b"org.freedesktop.DBus.ObjectManager\0\0\0\0\0\0\3\1s\0\21\0\0\0InterfacesRemoved" + b"\0\0\0\0\0\0\0\10\1g\0\3oas\0\0\0\0\0\0\0\0\7\1s\0\5\0\0\0:1.12\0\0\0%\0\0\0" + b"/org/bluez/hci0/dev_5F_13_47_38_26_55\0\0\0b\0\0\0\37\0\0\0org.freedesktop.DBus" + b".Properties\0#\0\0\0org.freedesktop.DBus.Introspectable\0\21\0\0\0org.bluez.Dev" + b"ice1\0" + ) + + stream = io.BytesIO(bluez_interfaces_removed_message) + unmarshaller = Unmarshaller(stream) + assert unmarshaller.unmarshall() + message = unmarshaller.message + assert message is not None + assert message.body == [ + "/org/bluez/hci0/dev_5F_13_47_38_26_55", + [ + "org.freedesktop.DBus.Properties", + "org.freedesktop.DBus.Introspectable", + "org.bluez.Device1", + ], + ] + assert message.sender == ":1.12" + assert message.path == "/" + assert message.interface == "org.freedesktop.DBus.ObjectManager" + assert message.member == "InterfacesRemoved" + assert message.signature == "oas" + assert message.message_type == MessageType.SIGNAL + assert message.flags == MessageFlag.NO_REPLY_EXPECTED + assert message.serial == 2965759 + assert message.destination is None + unpacked = unpack_variants(message.body) + assert unpacked == [ + "/org/bluez/hci0/dev_5F_13_47_38_26_55", + [ + "org.freedesktop.DBus.Properties", + "org.freedesktop.DBus.Introspectable", + "org.bluez.Device1", + ], + ] + + def test_ay_buffer(): body = [bytes(10000)] msg = Message(path="/test", member="test", signature="ay", body=body)