pylibrlp

Python3 wrapper for librlp
git clone git://git.defalsify.org/pylibrlp.git
Log | Files | Refs | LICENSE

commit 9869ada1b8523222e5ea50034da5e838ff82aae0
parent df88f8fb248331da05cfe7ba3dac3740c4a3ca8b
Author: nolash <dev@holbrook.no>
Date:   Tue, 13 Apr 2021 10:44:43 +0200

Rename project

Diffstat:
Apylibrlp/encoder.py | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Drlpstream/__init__.py | 28----------------------------
Drlpstream/encode.py | 121-------------------------------------------------------------------------------
Msetup.cfg | 4++--
Mtests/test_rlp_decoder.py | 2+-
Mtests/test_rlp_encoder.py | 2+-
6 files changed, 125 insertions(+), 153 deletions(-)

diff --git a/pylibrlp/encoder.py b/pylibrlp/encoder.py @@ -0,0 +1,121 @@ +# standard imports +import sys +import logging +import ctypes +import enum + +# local imports +from . import ( + LIBRLP_RLP_MAX_LIST_DEPTH, + librlp, + ) + +logg = logging.getLogger().getChild(__name__) + + +class RLPState(enum.IntEnum): + RLP_DECODE=0, + RLP_ENCODE=1, + RLP_LIST_ASCEND=2, + RLP_LIST_DESCEND=3, + RLP_STRING=4, + RLP_END=5, + + +class RLPEncoder: + + __nullptr = ctypes.POINTER(ctypes.c_void_p)() + + def __init__(self, buffer_size): + + class RLPEncoderBackend(ctypes.Structure): + + _fields_ = [ + ('buf', ctypes.POINTER(ctypes.c_char * buffer_size)), + ('alloc', ctypes.c_char), + ('depth', ctypes.c_int), + ('size', ctypes.c_int), + ('state', ctypes.c_int), + ('list_ptr', ctypes.POINTER(ctypes.POINTER(ctypes.c_char)) * LIBRLP_RLP_MAX_LIST_DEPTH), + ('ptr', ctypes.POINTER(ctypes.c_char)), + ] + + self.buffer_size = buffer_size + self.backend = RLPEncoderBackend() + self.encoder = ctypes.pointer(self.backend) + + # decoder specific + self.zl = ctypes.pointer(ctypes.c_int()) + self.buf = None + + + def __del__(self): + logg.debug('free') + librlp.rlp_free(self.encoder) + + + def encode_item(self, v): + if isinstance(v, list): + librlp.rlp_descend(self.encoder) + for e in v: + self.encode_item(e) + librlp.rlp_ascend(self.encoder) + + else: + b = (ctypes.c_char * len(v))(*v) + librlp.rlp_add(self.encoder, len(v), b) + + return self.backend.size + + + def encode(self, v): + librlp.rlp_init(self.encoder, self.buffer_size, self.__nullptr) + r = self.encode_item(v) + + return bytes(self.backend.buf.contents[:r]) + + + def decode_item(self, frame, stack): + logg.debug('frame {} stack {} depth {}'.format(frame, stack, self.backend.depth)) + r = librlp.rlp_next(self.encoder, self.zl, ctypes.pointer(self.buf)) + + if self.backend.state == RLPState.RLP_LIST_DESCEND: + stack.append(frame) + frame = [] + + elif self.backend.state == RLPState.RLP_LIST_ASCEND: + raise ValueError() + frame.append(stack.append(frame)) + + elif self.backend.state == RLPState.RLP_STRING: + l = int(self.zl.contents.value) + b = self.buf.contents[:l] + logg.debug('v {}'.format(b)) + frame.append(b) + + elif self.backend.state == RLPState.RLP_END: + stack = None + + else: + raise AttributeError('unexpected state {}'.format(self.backend.state)) + + return (frame, stack) + + def decode(self, v, size_hint=None): + if size_hint == None: + size_hint = sys.getsizeof(v) + + in_buffer = ctypes.c_char * len(v) + in_buffer_p = in_buffer.from_buffer(bytearray(v)) + librlp.rlp_init(self.encoder, len(v), in_buffer_p) + + self.zl = ctypes.pointer(ctypes.c_int()) + self.buf = ctypes.pointer((ctypes.c_char * size_hint)()) + + frame = [] + stack = [] + while stack != None: + (frame, stack) = self.decode_item(frame, stack) + l = self.backend.depth + + return frame[0] diff --git a/rlpstream/__init__.py b/rlpstream/__init__.py @@ -1,28 +0,0 @@ -# standard imports -import sys -import re -import os -import ctypes -import ctypes.util - - -LIBRLP_RLP_MAX_LIST_DEPTH = 1024 - - -__path_librlp = ctypes.util.find_library('rlp') - - -if __path_librlp == None: - v = sys.version_info - re_so = r'^rlp.cpython-' + str(v[0]) + str(v[1]) + '.*\.so$' - script_dir = os.path.dirname(__file__) - root_dir = os.path.join(script_dir, '..') - for f in os.listdir(root_dir): - if re.match(re_so, f): - __path_librlp = os.path.join(root_dir, f) - break - -if __path_librlp == None: - raise ImportError('missing librlp shared library') - -librlp = ctypes.CDLL(__path_librlp) diff --git a/rlpstream/encode.py b/rlpstream/encode.py @@ -1,121 +0,0 @@ -# standard imports -import sys -import logging -import ctypes -import enum - -# local imports -from . import ( - LIBRLP_RLP_MAX_LIST_DEPTH, - librlp, - ) - -logg = logging.getLogger().getChild(__name__) - - -class RLPState(enum.IntEnum): - RLP_DECODE=0, - RLP_ENCODE=1, - RLP_LIST_ASCEND=2, - RLP_LIST_DESCEND=3, - RLP_STRING=4, - RLP_END=5, - - -class RLPEncoder: - - __nullptr = ctypes.POINTER(ctypes.c_void_p)() - - def __init__(self, buffer_size): - - class RLPEncoderBackend(ctypes.Structure): - - _fields_ = [ - ('buf', ctypes.POINTER(ctypes.c_char * buffer_size)), - ('alloc', ctypes.c_char), - ('depth', ctypes.c_int), - ('size', ctypes.c_int), - ('state', ctypes.c_int), - ('list_ptr', ctypes.POINTER(ctypes.POINTER(ctypes.c_char)) * LIBRLP_RLP_MAX_LIST_DEPTH), - ('ptr', ctypes.POINTER(ctypes.c_char)), - ] - - self.buffer_size = buffer_size - self.backend = RLPEncoderBackend() - self.encoder = ctypes.pointer(self.backend) - - # decoder specific - self.zl = ctypes.pointer(ctypes.c_int()) - self.buf = None - - - def __del__(self): - logg.debug('free') - librlp.rlp_free(self.encoder) - - - def encode_item(self, v): - if isinstance(v, list): - librlp.rlp_descend(self.encoder) - for e in v: - self.encode_item(e) - librlp.rlp_ascend(self.encoder) - - else: - b = (ctypes.c_char * len(v))(*v) - librlp.rlp_add(self.encoder, len(v), b) - - return self.backend.size - - - def encode(self, v): - librlp.rlp_init(self.encoder, self.buffer_size, self.__nullptr) - r = self.encode_item(v) - - return bytes(self.backend.buf.contents[:r]) - - - def decode_item(self, frame, stack): - logg.debug('frame {} stack {} depth {}'.format(frame, stack, self.backend.depth)) - r = librlp.rlp_next(self.encoder, self.zl, ctypes.pointer(self.buf)) - - if self.backend.state == RLPState.RLP_LIST_DESCEND: - stack.append(frame) - frame = [] - - elif self.backend.state == RLPState.RLP_LIST_ASCEND: - raise ValueError() - frame.append(stack.append(frame)) - - elif self.backend.state == RLPState.RLP_STRING: - l = int(self.zl.contents.value) - b = self.buf.contents[:l] - logg.debug('v {}'.format(b)) - frame.append(b) - - elif self.backend.state == RLPState.RLP_END: - stack = None - - else: - raise AttributeError('unexpected state {}'.format(self.backend.state)) - - return (frame, stack) - - def decode(self, v, size_hint=None): - if size_hint == None: - size_hint = sys.getsizeof(v) - - in_buffer = ctypes.c_char * len(v) - in_buffer_p = in_buffer.from_buffer(bytearray(v)) - librlp.rlp_init(self.encoder, len(v), in_buffer_p) - - self.zl = ctypes.pointer(ctypes.c_int()) - self.buf = ctypes.pointer((ctypes.c_char * size_hint)()) - - frame = [] - stack = [] - while stack != None: - (frame, stack) = self.decode_item(frame, stack) - l = self.backend.depth - - return frame diff --git a/setup.cfg b/setup.cfg @@ -1,5 +1,5 @@ [metadata] -name = rlpstream +name = pylibrlp version = 0.0.01a1 description = Python wrapper for librlp author = Louis Holbrook @@ -23,4 +23,4 @@ licence_files = python_requires = >= 3.8 packages = - rlpstream + pylibrlp diff --git a/tests/test_rlp_decoder.py b/tests/test_rlp_decoder.py @@ -5,7 +5,7 @@ import logging import ctypes # local imports -from rlpstream.encode import RLPEncoder +from pylibrlp import RLPEncoder logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger() diff --git a/tests/test_rlp_encoder.py b/tests/test_rlp_encoder.py @@ -5,7 +5,7 @@ import logging import ctypes # local imports -from rlpstream.encode import RLPEncoder +from pylibrlp import RLPEncoder logging.basicConfig(level=logging.DEBUG) logg = logging.getLogger()