Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add cython extension for signature #72

Merged
merged 1 commit into from
Oct 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def build(setup_kwargs):
dict(
ext_modules=cythonize(
[
"src/dbus_fast/signature.py",
"src/dbus_fast/unpack.py",
"src/dbus_fast/_private/marshaller.py",
"src/dbus_fast/_private/unmarshaller.py",
Expand Down
12 changes: 9 additions & 3 deletions src/dbus_fast/_private/marshaller.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ cdef class Marshaller:
cdef bytearray _buf
cdef object body


@cython.locals(
offset=cython.ulong,
)
cpdef int align(self, unsigned long n)


@cython.locals(
value_len=cython.uint,
signature_len=cython.uint,
written=cython.uint,
)
Expand All @@ -26,11 +25,13 @@ cdef class Marshaller:
array_len=cython.uint,
written=cython.uint,
array_len_packed=cython.bytes,
i=cython.uint,
)
cpdef write_array(self, object array, object type)

@cython.locals(
written=cython.uint,
i=cython.uint,
)
cpdef write_struct(self, object array, object type)

Expand All @@ -39,9 +40,14 @@ cdef class Marshaller:
)
cpdef write_single(self, object type_, object body)

@cython.locals(
written=cython.uint,
)
cpdef write_dict_entry(self, object type_, object body)

cpdef marshall(self)

@cython.locals(
offset=cython.ulong,
)
cpdef _construct_buffer(self)
cdef _construct_buffer(self)
4 changes: 2 additions & 2 deletions src/dbus_fast/_private/marshaller.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from struct import Struct, error
from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple

from ..signature import SignatureTree, SignatureType, Variant
from ..signature import SignatureType, Variant, get_signature_tree

PACK_UINT32 = Struct("<I").pack

Expand All @@ -13,7 +13,7 @@ class Marshaller:

def __init__(self, signature: str, body: List[Any]) -> None:
"""Marshaller constructor."""
self.signature_tree = SignatureTree._get(signature)
self.signature_tree = get_signature_tree(signature)
self._buf = bytearray()
self.body = body

Expand Down
17 changes: 11 additions & 6 deletions src/dbus_fast/_private/unmarshaller.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ cdef unsigned int BIG_ENDIAN
cdef str UINT32_CAST
cdef object UINT32_SIGNATURE

cdef class MarshallerStreamEndError(Exception):
pass

cdef class Unmarshaller:

cdef object _unix_fds
Expand All @@ -33,18 +36,20 @@ cdef class Unmarshaller:

cpdef reset(self)

cdef read_sock(self, unsigned long length)

@cython.locals(
start_len=cython.ulong,
missing_bytes=cython.ulong
)
cpdef read_to_pos(self, unsigned long pos)
cdef read_to_pos(self, unsigned long pos)

cpdef read_uint32_cast(self, object type_)

@cython.locals(
buf_bytes=cython.bytearray,
)
cpdef read_string_cast(self, type_ = *)
cpdef read_string_cast(self, object type_)

@cython.locals(
beginning_pos=cython.ulong,
Expand All @@ -56,16 +61,16 @@ cdef class Unmarshaller:
o=cython.ulong,
signature_len=cython.uint,
)
cpdef read_signature(self, type_ = *)
cpdef read_signature(self, object type_)

@cython.locals(
endian=cython.uint,
protocol_version=cython.uint,
can_cast=cython.bint
)
cpdef _read_header(self)
cdef _read_header(self)

cpdef _read_body(self)
cdef _read_body(self)

cpdef unmarshall(self)

Expand All @@ -74,4 +79,4 @@ cdef class Unmarshaller:
o=cython.ulong,
signature_len=cython.uint,
)
cpdef header_fields(self, unsigned int header_length)
cdef header_fields(self, unsigned int header_length)
28 changes: 14 additions & 14 deletions src/dbus_fast/_private/unmarshaller.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import socket
import sys
from struct import Struct
from typing import Any, Callable, Dict, List, Optional, Tuple
from typing import Any, Callable, Dict, List, Tuple

from ..constants import MESSAGE_FLAG_MAP, MESSAGE_TYPE_MAP, MessageFlag, MessageType
from ..constants import MESSAGE_FLAG_MAP, MESSAGE_TYPE_MAP
from ..errors import InvalidMessageError
from ..message import Message
from ..signature import SignatureTree, SignatureType, Variant
from ..signature import SignatureType, Variant, get_signature_tree
from .constants import (
BIG_ENDIAN,
HEADER_NAME_MAP,
Expand All @@ -28,7 +28,7 @@
UINT32_CAST = "I"
UINT32_SIZE = 4
UINT32_DBUS_TYPE = "u"
UINT32_SIGNATURE = SignatureTree._get(UINT32_DBUS_TYPE).types[0]
UINT32_SIGNATURE = get_signature_tree(UINT32_DBUS_TYPE).types[0]

DBUS_TO_CTYPE = {
"y": ("B", 1), # byte
Expand Down Expand Up @@ -236,14 +236,14 @@ def read_to_pos(self, pos) -> None:
if len(data) + start_len != pos:
raise MarshallerStreamEndError()

def read_uint32_cast(self, signature: SignatureType) -> Any:
def read_uint32_cast(self, type_: SignatureType) -> Any:
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
return self._view[self._pos - UINT32_SIZE : self._pos].cast(UINT32_CAST)[0]

def read_boolean(self, type_=None) -> bool:
def read_boolean(self, type_: SignatureType) -> bool:
return bool(self._readers[UINT32_SIGNATURE.token](self, UINT32_SIGNATURE))

def read_string_cast(self, type_=None) -> str:
def read_string_cast(self, type_: SignatureType) -> str:
"""Read a string using cast."""
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
str_start = self._pos
Expand All @@ -252,29 +252,29 @@ def read_string_cast(self, type_=None) -> str:
self._pos += self._view[start_pos : self._pos].cast(UINT32_CAST)[0] + 1
return self._buf[str_start : self._pos - 1].decode()

def read_string_unpack(self, type_=None) -> str:
def read_string_unpack(self, type_: SignatureType) -> str:
"""Read a string using unpack."""
self._pos += UINT32_SIZE + (-self._pos & (UINT32_SIZE - 1)) # align
str_start = self._pos
# read terminating '\0' byte as well (str_length + 1)
self._pos += self._uint32_unpack(self._view, str_start - UINT32_SIZE)[0] + 1
return self._buf[str_start : self._pos - 1].decode()

def read_signature(self, type_=None) -> str:
def read_signature(self, type_: SignatureType) -> str:
signature_len = self._view[self._pos] # byte
o = self._pos + 1
# read terminating '\0' byte as well (str_length + 1)
self._pos = o + signature_len + 1
return self._buf[o : o + signature_len].decode()

def read_variant(self, type_=None) -> Variant:
tree = SignatureTree._get(self.read_signature())
def read_variant(self, type_: SignatureType) -> Variant:
tree = get_signature_tree(self.read_signature(type_))
# verify in Variant is only useful on construction not unmarshalling
return Variant(
tree, self._readers[tree.types[0].token](self, tree.types[0]), verify=False
)

def read_struct(self, type_=None) -> List[Any]:
def read_struct(self, type_: SignatureType) -> List[Any]:
self._pos += -self._pos & 7 # align 8
readers = self._readers
return [
Expand Down Expand Up @@ -344,7 +344,7 @@ def header_fields(self, header_length) -> Dict[str, Any]:
signature_len = self._view[self._pos] # byte
o = self._pos + 1
self._pos += signature_len + 2 # one for the byte, one for the '\0'
tree = SignatureTree._get(self._buf[o : o + signature_len].decode())
tree = get_signature_tree(self._buf[o : o + signature_len].decode())
headers[HEADER_NAME_MAP[field_0]] = self._readers[tree.types[0].token](
self, tree.types[0]
)
Expand Down Expand Up @@ -391,7 +391,7 @@ def _read_body(self):
self._pos = HEADER_ARRAY_OF_STRUCT_SIGNATURE_POSITION
header_fields = self.header_fields(self._header_len)
self._pos += -self._pos & 7 # align 8
tree = SignatureTree._get(header_fields.get(HeaderField.SIGNATURE.name, ""))
tree = get_signature_tree(header_fields.get(HeaderField.SIGNATURE.name, ""))
self._message = Message(
destination=header_fields.get(HEADER_DESTINATION),
path=header_fields.get(HEADER_PATH),
Expand Down
8 changes: 4 additions & 4 deletions src/dbus_fast/_private/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import inspect
from typing import Any, List, Union

from ..signature import SignatureTree, Variant
from ..signature import SignatureTree, Variant, get_signature_tree


def signature_contains_type(
Expand All @@ -11,7 +11,7 @@ def signature_contains_type(
"""For a given signature and body, check to see if it contains any members
with the given token"""
if type(signature) is str:
signature = SignatureTree._get(signature)
signature = get_signature_tree(signature)

queue = []
contains_variants = False
Expand Down Expand Up @@ -56,7 +56,7 @@ def replace_fds_with_idx(
an index and return the corresponding list of unix fds that can be set on
the Message"""
if type(signature) is str:
signature = SignatureTree._get(signature)
signature = get_signature_tree(signature)

if not signature_contains_type(signature, body, "h"):
return body, []
Expand All @@ -82,7 +82,7 @@ def replace_idx_with_fds(
Type 'h' refers to an index in the unix_fds array. Replace those with the
actual file descriptor or `None` if one does not exist."""
if type(signature) is str:
signature = SignatureTree._get(signature)
signature = get_signature_tree(signature)

if not signature_contains_type(signature, body, "h"):
return body
Expand Down
6 changes: 3 additions & 3 deletions src/dbus_fast/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from .constants import ArgDirection, PropertyAccess
from .errors import InvalidIntrospectionError
from .signature import SignatureTree, SignatureType
from .signature import SignatureType, get_signature_tree
from .validators import assert_interface_name_valid, assert_member_name_valid

# https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
Expand Down Expand Up @@ -42,7 +42,7 @@ def __init__(
type_ = signature
signature = signature.signature
else:
tree = SignatureTree._get(signature)
tree = get_signature_tree(signature)
if len(tree.types) != 1:
raise InvalidIntrospectionError(
f"an argument must have a single complete type. (has {len(tree.types)} types)"
Expand Down Expand Up @@ -248,7 +248,7 @@ def __init__(
):
assert_member_name_valid(name)

tree = SignatureTree._get(signature)
tree = get_signature_tree(signature)
if len(tree.types) != 1:
raise InvalidIntrospectionError(
f"properties must have a single complete type. (has {len(tree.types)} types)"
Expand Down
11 changes: 2 additions & 9 deletions src/dbus_fast/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from ._private.marshaller import Marshaller
from .constants import ErrorType, MessageFlag, MessageType
from .errors import InvalidMessageError
from .signature import SignatureTree, Variant
from .signature import SignatureTree, Variant, get_signature_tree
from .validators import (
assert_bus_name_valid,
assert_interface_name_valid,
Expand Down Expand Up @@ -129,7 +129,7 @@ def __init__(
self.signature_tree = signature
else:
self.signature = signature
self.signature_tree = SignatureTree._get(signature)
self.signature_tree = get_signature_tree(signature)
self.body = body
self.serial = serial

Expand Down Expand Up @@ -255,13 +255,6 @@ def new_signal(
unix_fds=unix_fds,
)

def _matches(self, **kwargs):
for attr, val in kwargs.items():
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is dead code

if getattr(self, attr) != val:
return False

return True

def _marshall(self, negotiate_unix_fd=False):
# TODO maximum message size is 134217728 (128 MiB)
body_block = Marshaller(self.signature, self.body)
Expand Down
14 changes: 7 additions & 7 deletions src/dbus_fast/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
)
from .constants import PropertyAccess
from .errors import SignalDisabledError
from .signature import SignatureBodyMismatchError, SignatureTree, Variant
from .signature import SignatureBodyMismatchError, Variant, get_signature_tree


class _Method:
Expand All @@ -39,7 +39,7 @@ def __init__(self, fn, name, disabled=False):
out_args = []
out_signature = parse_annotation(inspection.return_annotation)
if out_signature:
for type_ in SignatureTree._get(out_signature).types:
for type_ in get_signature_tree(out_signature).types:
out_args.append(intr.Arg(type_, intr.ArgDirection.OUT))

self.name = name
Expand All @@ -48,8 +48,8 @@ def __init__(self, fn, name, disabled=False):
self.introspection = intr.Method(name, in_args, out_args)
self.in_signature = in_signature
self.out_signature = out_signature
self.in_signature_tree = SignatureTree._get(in_signature)
self.out_signature_tree = SignatureTree._get(out_signature)
self.in_signature_tree = get_signature_tree(in_signature)
self.out_signature_tree = get_signature_tree(out_signature)


def method(name: str = None, disabled: bool = False):
Expand Down Expand Up @@ -116,12 +116,12 @@ def __init__(self, fn, name, disabled=False):

if return_annotation:
signature = return_annotation
signature_tree = SignatureTree._get(signature)
signature_tree = get_signature_tree(signature)
for type_ in signature_tree.types:
args.append(intr.Arg(type_, intr.ArgDirection.OUT))
else:
signature = ""
signature_tree = SignatureTree._get("")
signature_tree = get_signature_tree("")

self.signature = signature
self.signature_tree = signature_tree
Expand Down Expand Up @@ -226,7 +226,7 @@ def __init__(self, fn, *args, **kwargs):
)

self.signature = return_annotation
tree = SignatureTree._get(return_annotation)
tree = get_signature_tree(return_annotation)

if len(tree.types) != 1:
raise ValueError("the property signature must be a single complete type")
Expand Down
16 changes: 16 additions & 0 deletions src/dbus_fast/signature.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""cdefs for signature.py"""

import cython


cdef class SignatureType:

cdef public str token
cdef public list children
cdef str _signature


cdef class SignatureTree:

cdef public str signature
cdef public list types
Loading