feat: speed up marshalling headers (#142)

This commit is contained in:
J. Nick Koston
2022-11-03 11:11:40 +01:00
committed by GitHub
parent b8aa178e19
commit 7d6fb63dc0
2 changed files with 52 additions and 33 deletions

View File

@@ -15,19 +15,28 @@ cdef class Marshaller:
cdef bytearray _buf cdef bytearray _buf
cdef object body cdef object body
cpdef unsigned int align(self, unsigned int n) cpdef align(self, unsigned int n)
@cython.locals( @cython.locals(
offset=cython.ulong, offset=cython.ulong,
) )
cdef unsigned int _align(self, unsigned int n) cdef unsigned int _align(self, unsigned int n)
cpdef write_boolean(self, object boolean, object _type)
@cython.locals(
written=cython.uint,
)
cdef unsigned int _write_boolean(self, object boolean)
cpdef write_string(self, str value, object _type)
@cython.locals( @cython.locals(
value_len=cython.uint, value_len=cython.uint,
signature_len=cython.uint, signature_len=cython.uint,
written=cython.uint, written=cython.uint,
) )
cpdef write_string(self, str value, object _type) cdef unsigned int _write_string(self, str value)
@cython.locals( @cython.locals(
signature_len=cython.uint, signature_len=cython.uint,
@@ -57,12 +66,14 @@ cdef class Marshaller:
) )
cdef unsigned int _write_struct(self, object array, object type) cdef unsigned int _write_struct(self, object array, object type)
cpdef write_variant(self, object variant, object type)
@cython.locals( @cython.locals(
written=cython.uint, written=cython.uint,
signature=cython.str, signature=cython.str,
signature_bytes=cython.bytes, signature_bytes=cython.bytes,
) )
cpdef write_variant(self, object variant, object type) cdef unsigned int _write_variant(self, object variant, object type)
@cython.locals( @cython.locals(
written=cython.uint, written=cython.uint,

View File

@@ -36,6 +36,9 @@ class Marshaller:
return offset return offset
def write_boolean(self, boolean: bool, type_: SignatureType) -> int: def write_boolean(self, boolean: bool, type_: SignatureType) -> int:
return self._write_boolean(boolean)
def _write_boolean(self, boolean: bool) -> int:
written = self._align(4) written = self._align(4)
self._buf += PACKED_BOOL_TRUE if boolean else PACKED_BOOL_FALSE self._buf += PACKED_BOOL_TRUE if boolean else PACKED_BOOL_FALSE
return written + 4 return written + 4
@@ -47,23 +50,29 @@ class Marshaller:
signature_len = len(signature_bytes) signature_len = len(signature_bytes)
buf = self._buf buf = self._buf
buf.append(signature_len) buf.append(signature_len)
buf.extend(signature_bytes) buf += signature_bytes
buf.append(0) buf.append(0)
return signature_len + 2 return signature_len + 2
def write_string(self, value, type_: SignatureType) -> int: def write_string(self, value, type_: SignatureType) -> int:
return self._write_string(value)
def _write_string(self, value) -> int:
value_bytes = value.encode() value_bytes = value.encode()
value_len = len(value) value_len = len(value)
written = self._align(4) + 4 written = self._align(4) + 4
buf = self._buf buf = self._buf
buf.extend(PACK_UINT32(value_len)) buf += PACK_UINT32(value_len)
buf.extend(value_bytes) buf += value_bytes
written += value_len written += value_len
buf.append(0) buf.append(0)
written += 1 written += 1
return written return written
def write_variant(self, variant: Variant, type_: SignatureType) -> int: def write_variant(self, variant: Variant, type_: SignatureType) -> int:
return self._write_variant(variant, type_)
def _write_variant(self, variant: Variant, type_: SignatureType) -> int:
signature = variant.signature signature = variant.signature
signature_bytes = signature.encode() signature_bytes = signature.encode()
written = self._write_signature(signature_bytes) written = self._write_signature(signature_bytes)
@@ -84,7 +93,7 @@ class Marshaller:
buf = self._buf buf = self._buf
offset = len(buf) offset = len(buf)
written += self._align(4) + 4 written += self._align(4) + 4
buf.extend(PACKED_UINT32_ZERO) buf += PACKED_UINT32_ZERO
child_type = type_.children[0] child_type = type_.children[0]
token = child_type.token token = child_type.token
@@ -98,7 +107,7 @@ class Marshaller:
array_len += self.write_dict_entry([key, value], child_type) array_len += self.write_dict_entry([key, value], child_type)
elif token == "y": elif token == "y":
array_len = len(array) array_len = len(array)
buf.extend(array) buf += array
elif token == "(": elif token == "(":
for value in array: for value in array:
array_len += self._write_struct(value, child_type) array_len += self._write_struct(value, child_type)
@@ -107,7 +116,7 @@ class Marshaller:
if not writer: if not writer:
for value in array: for value in array:
array_len += self._align(size) + size array_len += self._align(size) + size
buf.extend(packer(value)) # type: ignore[misc] buf += packer(value) # type: ignore[misc]
else: else:
for value in array: for value in array:
array_len += writer(self, value, child_type) array_len += writer(self, value, child_type)
@@ -135,12 +144,28 @@ class Marshaller:
def _write_single(self, type_: SignatureType, body: Any) -> int: def _write_single(self, type_: SignatureType, body: Any) -> int:
t = type_.token t = type_.token
writer, packer, size = self._writers[t] if t == "y":
if not writer: self._buf.append(body)
written = self._align(size) return 1
self._buf.extend(packer(body)) # type: ignore[misc] elif t == "u":
return written + size written = self._align(4)
return writer(self, body, type_) self._buf += PACK_UINT32(body)
return written + 4
elif t == "a":
return self._write_array(body, type_)
elif t == "s" or t == "o":
return self._write_string(body)
elif t == "v":
return self._write_variant(body, type_)
elif t == "b":
return self._write_boolean(body)
else:
writer, packer, size = self._writers[t]
if not writer:
written = self._align(size)
self._buf += packer(body) # type: ignore[misc]
return written + size
return writer(self, body, type_)
def marshall(self) -> bytearray: def marshall(self) -> bytearray:
"""Marshalls the body into a byte array""" """Marshalls the body into a byte array"""
@@ -154,26 +179,9 @@ class Marshaller:
def _construct_buffer(self) -> None: def _construct_buffer(self) -> None:
self._buf.clear() self._buf.clear()
writers = self._writers
body = self.body body = self.body
buf = self._buf
for i, type_ in enumerate(self.signature_tree.types): for i, type_ in enumerate(self.signature_tree.types):
t = type_.token self._write_single(type_, body[i])
if t == "y":
buf.append(body[i])
elif t == "u":
self._align(4)
buf.extend(PACK_UINT32(body[i]))
elif t == "a":
self._write_array(body[i], type_)
else:
writer, packer, size = writers[t]
if not writer:
if size != 1:
self._align(size)
buf.extend(packer(body[i])) # type: ignore[misc]
else:
writer(self, body[i], type_)
_writers: Dict[ _writers: Dict[
str, str,