# This file was autogenerated by some hot garbage in the `uniffi` crate.
# Trust me, you don't want to mess with it!

# Tell mypy (a type checker) to ignore all errors from this file.
# See https://mypy.readthedocs.io/en/stable/config_file.html?highlight=ignore-errors#confval-ignore_errors
# mypy: ignore-errors

# Common helper code.
#
# Ideally this would live in a separate .py file where it can be unittested etc
# in isolation, and perhaps even published as a re-useable package.
#
# However, it's important that the details of how this helper code works (e.g. the
# way that different builtin types are passed across the FFI) exactly match what's
# expected by the rust code on the other side of the interface. In practice right
# now that means coming from the exact some version of `uniffi` that was used to
# compile the rust component. The easiest way to ensure this is to bundle the Python
# helpers directly inline like we're doing here.

import os
import sys
import ctypes
import enum
import struct
import contextlib
import datetime

# Used for default argument values
DEFAULT = object()


class RustBuffer(ctypes.Structure):
    _fields_ = [
        ("capacity", ctypes.c_int32),
        ("len", ctypes.c_int32),
        ("data", ctypes.POINTER(ctypes.c_char)),
    ]

    @staticmethod
    def alloc(size):
        return rust_call(_UniFFILib.ffi_cryptatools_ac35_rustbuffer_alloc, size)

    @staticmethod
    def reserve(rbuf, additional):
        return rust_call(_UniFFILib.ffi_cryptatools_ac35_rustbuffer_reserve, rbuf, additional)

    def free(self):
        return rust_call(_UniFFILib.ffi_cryptatools_ac35_rustbuffer_free, self)

    def __str__(self):
        return "RustBuffer(capacity={}, len={}, data={})".format(
            self.capacity,
            self.len,
            self.data[0:self.len]
        )

    @contextlib.contextmanager
    def allocWithBuilder():
        """Context-manger to allocate a buffer using a RustBufferBuilder.

        The allocated buffer will be automatically freed if an error occurs, ensuring that
        we don't accidentally leak it.
        """
        builder = RustBufferBuilder()
        try:
            yield builder
        except:
            builder.discard()
            raise

    @contextlib.contextmanager
    def consumeWithStream(self):
        """Context-manager to consume a buffer using a RustBufferStream.

        The RustBuffer will be freed once the context-manager exits, ensuring that we don't
        leak it even if an error occurs.
        """
        try:
            s = RustBufferStream(self)
            yield s
            if s.remaining() != 0:
                raise RuntimeError("junk data left in buffer after consuming")
        finally:
            self.free()


class ForeignBytes(ctypes.Structure):
    _fields_ = [
        ("len", ctypes.c_int32),
        ("data", ctypes.POINTER(ctypes.c_char)),
    ]

    def __str__(self):
        return "ForeignBytes(len={}, data={})".format(self.len, self.data[0:self.len])


class RustBufferStream(object):
    """
    Helper for structured reading of bytes from a RustBuffer
    """

    def __init__(self, rbuf):
        self.rbuf = rbuf
        self.offset = 0

    def remaining(self):
        return self.rbuf.len - self.offset

    def _unpack_from(self, size, format):
        if self.offset + size > self.rbuf.len:
            raise InternalError("read past end of rust buffer")
        value = struct.unpack(format, self.rbuf.data[self.offset:self.offset+size])[0]
        self.offset += size
        return value

    def read(self, size):
        if self.offset + size > self.rbuf.len:
            raise InternalError("read past end of rust buffer")
        data = self.rbuf.data[self.offset:self.offset+size]
        self.offset += size
        return data

    def readI8(self):
        return self._unpack_from(1, ">b")

    def readU8(self):
        return self._unpack_from(1, ">B")

    def readI16(self):
        return self._unpack_from(2, ">h")

    def readU16(self):
        return self._unpack_from(2, ">H")

    def readI32(self):
        return self._unpack_from(4, ">i")

    def readU32(self):
        return self._unpack_from(4, ">I")

    def readI64(self):
        return self._unpack_from(8, ">q")

    def readU64(self):
        return self._unpack_from(8, ">Q")

    def readFloat(self):
        v = self._unpack_from(4, ">f")
        return v

    def readDouble(self):
        return self._unpack_from(8, ">d")


class RustBufferBuilder(object):
    """
    Helper for structured writing of bytes into a RustBuffer.
    """

    def __init__(self):
        self.rbuf = RustBuffer.alloc(16)
        self.rbuf.len = 0

    def finalize(self):
        rbuf = self.rbuf
        self.rbuf = None
        return rbuf

    def discard(self):
        if self.rbuf is not None:
            rbuf = self.finalize()
            rbuf.free()

    @contextlib.contextmanager
    def _reserve(self, numBytes):
        if self.rbuf.len + numBytes > self.rbuf.capacity:
            self.rbuf = RustBuffer.reserve(self.rbuf, numBytes)
        yield None
        self.rbuf.len += numBytes

    def _pack_into(self, size, format, value):
        with self._reserve(size):
            # XXX TODO: I feel like I should be able to use `struct.pack_into` here but can't figure it out.
            for i, byte in enumerate(struct.pack(format, value)):
                self.rbuf.data[self.rbuf.len + i] = byte

    def write(self, value):
        with self._reserve(len(value)):
            for i, byte in enumerate(value):
                self.rbuf.data[self.rbuf.len + i] = byte

    def writeI8(self, v):
        self._pack_into(1, ">b", v)

    def writeU8(self, v):
        self._pack_into(1, ">B", v)

    def writeI16(self, v):
        self._pack_into(2, ">h", v)

    def writeU16(self, v):
        self._pack_into(2, ">H", v)

    def writeI32(self, v):
        self._pack_into(4, ">i", v)

    def writeU32(self, v):
        self._pack_into(4, ">I", v)

    def writeI64(self, v):
        self._pack_into(8, ">q", v)

    def writeU64(self, v):
        self._pack_into(8, ">Q", v)

    def writeFloat(self, v):
        self._pack_into(4, ">f", v)

    def writeDouble(self, v):
        self._pack_into(8, ">d", v)
# A handful of classes and functions to support the generated data structures.
# This would be a good candidate for isolating in its own ffi-support lib.

class InternalError(Exception):
    pass

class RustCallStatus(ctypes.Structure):
    """
    Error runtime.
    """
    _fields_ = [
        ("code", ctypes.c_int8),
        ("error_buf", RustBuffer),
    ]

    # These match the values from the uniffi::rustcalls module
    CALL_SUCCESS = 0
    CALL_ERROR = 1
    CALL_PANIC = 2

    def __str__(self):
        if self.code == RustCallStatus.CALL_SUCCESS:
            return "RustCallStatus(CALL_SUCCESS)"
        elif self.code == RustCallStatus.CALL_ERROR:
            return "RustCallStatus(CALL_ERROR)"
        elif self.code == RustCallStatus.CALL_PANIC:
            return "RustCallStatus(CALL_PANIC)"
        else:
            return "RustCallStatus(<invalid code>)"

def rust_call(fn, *args):
    # Call a rust function
    return rust_call_with_error(None, fn, *args)

def rust_call_with_error(error_ffi_converter, fn, *args):
    # Call a rust function and handle any errors
    #
    # This function is used for rust calls that return Result<> and therefore can set the CALL_ERROR status code.
    # error_ffi_converter must be set to the FFIConverter for the error class that corresponds to the result.
    call_status = RustCallStatus(code=RustCallStatus.CALL_SUCCESS, error_buf=RustBuffer(0, 0, None))

    args_with_error = args + (ctypes.byref(call_status),)
    result = fn(*args_with_error)
    if call_status.code == RustCallStatus.CALL_SUCCESS:
        return result
    elif call_status.code == RustCallStatus.CALL_ERROR:
        if error_ffi_converter is None:
            call_status.err_buf.contents.free()
            raise InternalError("rust_call_with_error: CALL_ERROR, but error_ffi_converter is None")
        else:
            raise error_ffi_converter.lift(call_status.error_buf)
    elif call_status.code == RustCallStatus.CALL_PANIC:
        # When the rust code sees a panic, it tries to construct a RustBuffer
        # with the message.  But if that code panics, then it just sends back
        # an empty buffer.
        if call_status.error_buf.len > 0:
            msg = FfiConverterString.lift(call_status.error_buf)
        else:
            msg = "Unknown rust panic"
        raise InternalError(msg)
    else:
        raise InternalError("Invalid RustCallStatus code: {}".format(
            call_status.code))

# A function pointer for a callback as defined by UniFFI.
# Rust definition `fn(handle: u64, method: u32, args: RustBuffer, buf_ptr: *mut RustBuffer) -> int`
FOREIGN_CALLBACK_T = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_ulonglong, ctypes.c_ulong, RustBuffer, ctypes.POINTER(RustBuffer))
# Types conforming to `FfiConverterPrimitive` pass themselves directly over the FFI.
class FfiConverterPrimitive:
    @classmethod
    def lift(cls, value):
        return value

    @classmethod
    def lower(cls, value):
        return value

# Helper class for wrapper types that will always go through a RustBuffer.
# Classes should inherit from this and implement the `read` and `write` static methods.
class FfiConverterRustBuffer:
    @classmethod
    def lift(cls, rbuf):
        with rbuf.consumeWithStream() as stream:
            return cls.read(stream)

    @classmethod
    def lower(cls, value):
        with RustBuffer.allocWithBuilder() as builder:
            cls.write(value, builder)
            return builder.finalize()

# Contains loading, initialization code,
# and the FFI Function declarations in a com.sun.jna.Library.
# This is how we find and load the dynamic library provided by the component.
# For now we just look it up by name.
#
# XXX TODO: This will probably grow some magic for resolving megazording in future.
# E.g. we might start by looking for the named component in `libuniffi.so` and if
# that fails, fall back to loading it separately from `lib${componentName}.so`.

from pathlib import Path

def loadIndirect():
    if sys.platform == "darwin":
        libname = "lib{}.dylib"
    elif sys.platform.startswith("win"):
        # As of python3.8, ctypes does not seem to search $PATH when loading DLLs.
        # We could use `os.add_dll_directory` to configure the search path, but
        # it doesn't feel right to mess with application-wide settings. Let's
        # assume that the `.dll` is next to the `.py` file and load by full path.
        libname = os.path.join(
            os.path.dirname(__file__),
            "{}.dll",
        )
    else:
        # Anything else must be an ELF platform - Linux, *BSD, Solaris/illumos
        libname = "lib{}.so"

    lib = libname.format("uniffi_cryptatools")
    path = str(Path(__file__).parent / lib)
    return ctypes.cdll.LoadLibrary(path)

# A ctypes library to expose the extern-C FFI definitions.
# This is an implementation detail which will be called internally by the public API.

_UniFFILib = loadIndirect()
_UniFFILib.ffi_cryptatools_ac35_Alphabet_object_free.argtypes = (
    ctypes.c_void_p,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.ffi_cryptatools_ac35_Alphabet_object_free.restype = None
_UniFFILib.cryptatools_ac35_Alphabet_new.argtypes = (
    RustBuffer,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_Alphabet_new.restype = ctypes.c_void_p
_UniFFILib.cryptatools_ac35_Alphabet_new_empty.argtypes = (
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_Alphabet_new_empty.restype = ctypes.c_void_p
_UniFFILib.cryptatools_ac35_Alphabet_get_encoding.argtypes = (
    ctypes.c_void_p,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_Alphabet_get_encoding.restype = RustBuffer
_UniFFILib.ffi_cryptatools_ac35_CaesarNumberAlgorithm_object_free.argtypes = (
    ctypes.c_void_p,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.ffi_cryptatools_ac35_CaesarNumberAlgorithm_object_free.restype = None
_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_new.argtypes = (
    ctypes.c_void_p,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_new.restype = ctypes.c_void_p
_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_encrypt_by_opcode_shift.argtypes = (
    ctypes.c_void_p,
    RustBuffer,
    ctypes.c_uint32,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_encrypt_by_opcode_shift.restype = RustBuffer
_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_encrypt_by_alphabet_shift.argtypes = (
    ctypes.c_void_p,
    RustBuffer,
    ctypes.c_uint32,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_encrypt_by_alphabet_shift.restype = RustBuffer
_UniFFILib.ffi_cryptatools_ac35_ColumnarTranspositionAlgorithm_object_free.argtypes = (
    ctypes.c_void_p,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.ffi_cryptatools_ac35_ColumnarTranspositionAlgorithm_object_free.restype = None
_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_new.argtypes = (
    ctypes.c_void_p,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_new.restype = ctypes.c_void_p
_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_encrypt.argtypes = (
    ctypes.c_void_p,
    RustBuffer,
    ctypes.c_uint32,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_encrypt.restype = RustBuffer
_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_decrypt.argtypes = (
    ctypes.c_void_p,
    RustBuffer,
    ctypes.c_uint32,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_decrypt.restype = RustBuffer
_UniFFILib.cryptatools_ac35_split_bytes_by_characters_representation.argtypes = (
    ctypes.c_void_p,
    RustBuffer,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_split_bytes_by_characters_representation.restype = RustBuffer
_UniFFILib.cryptatools_ac35_uniffy_opcode_group.argtypes = (
    RustBuffer,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.cryptatools_ac35_uniffy_opcode_group.restype = RustBuffer
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_alloc.argtypes = (
    ctypes.c_int32,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_alloc.restype = RustBuffer
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_from_bytes.argtypes = (
    ForeignBytes,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_from_bytes.restype = RustBuffer
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_free.argtypes = (
    RustBuffer,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_free.restype = None
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_reserve.argtypes = (
    RustBuffer,
    ctypes.c_int32,
    ctypes.POINTER(RustCallStatus),
)
_UniFFILib.ffi_cryptatools_ac35_rustbuffer_reserve.restype = RustBuffer

# Public interface members begin here.


class FfiConverterUInt8(FfiConverterPrimitive):
    @staticmethod
    def read(buf):
        return buf.readU8()

    @staticmethod
    def write(value, buf):
        buf.writeU8(value)

class FfiConverterUInt32(FfiConverterPrimitive):
    @staticmethod
    def read(buf):
        return buf.readU32()

    @staticmethod
    def write(value, buf):
        buf.writeU32(value)

class FfiConverterString:
    @staticmethod
    def read(buf):
        size = buf.readI32()
        if size < 0:
            raise InternalError("Unexpected negative string length")
        utf8Bytes = buf.read(size)
        return utf8Bytes.decode("utf-8")

    @staticmethod
    def write(value, buf):
        utf8Bytes = value.encode("utf-8")
        buf.writeI32(len(utf8Bytes))
        buf.write(utf8Bytes)

    @staticmethod
    def lift(buf):
        with buf.consumeWithStream() as stream:
            return stream.read(stream.remaining()).decode("utf-8")

    @staticmethod
    def lower(value):
        with RustBuffer.allocWithBuilder() as builder:
            builder.write(value.encode("utf-8"))
            return builder.finalize()



class Alphabet(object):
    def __init__(self, encoding):
        encoding = list(x for x in encoding)
        
        self._pointer = rust_call(_UniFFILib.cryptatools_ac35_Alphabet_new,
        FfiConverterSequenceTypeEncoding.lower(encoding))

    def __del__(self):
        # In case of partial initialization of instances.
        pointer = getattr(self, "_pointer", None)
        if pointer is not None:
            rust_call(_UniFFILib.ffi_cryptatools_ac35_Alphabet_object_free, pointer)

    # Used by alternative constructors or any methods which return this type.
    @classmethod
    def _make_instance_(cls, pointer):
        # Lightly yucky way to bypass the usual __init__ logic
        # and just create a new instance with the required pointer.
        inst = cls.__new__(cls)
        inst._pointer = pointer
        return inst

    @classmethod
    def new_empty(cls, ):
        # Call the (fallible) function before creating any half-baked object instances.
        pointer = rust_call(_UniFFILib.cryptatools_ac35_Alphabet_new_empty,)
        return cls._make_instance_(pointer)
    

    def get_encoding(self, ):
        return FfiConverterSequenceTypeEncoding.lift(
            rust_call(_UniFFILib.cryptatools_ac35_Alphabet_get_encoding,self._pointer,)
        )
    


class FfiConverterTypeAlphabet:
    @classmethod
    def read(cls, buf):
        ptr = buf.readU64()
        if ptr == 0:
            raise InternalError("Raw pointer value was null")
        return cls.lift(ptr)

    @classmethod
    def write(cls, value, buf):
        if not isinstance(value, Alphabet):
            raise TypeError("Expected Alphabet instance, {} found".format(value.__class__.__name__))
        buf.writeU64(cls.lower(value))

    @staticmethod
    def lift(value):
        return Alphabet._make_instance_(value)

    @staticmethod
    def lower(value):
        return value._pointer



class CaesarNumberAlgorithm(object):
    def __init__(self, alphabet):
        alphabet = alphabet
        
        self._pointer = rust_call(_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_new,
        FfiConverterTypeAlphabet.lower(alphabet))

    def __del__(self):
        # In case of partial initialization of instances.
        pointer = getattr(self, "_pointer", None)
        if pointer is not None:
            rust_call(_UniFFILib.ffi_cryptatools_ac35_CaesarNumberAlgorithm_object_free, pointer)

    # Used by alternative constructors or any methods which return this type.
    @classmethod
    def _make_instance_(cls, pointer):
        # Lightly yucky way to bypass the usual __init__ logic
        # and just create a new instance with the required pointer.
        inst = cls.__new__(cls)
        inst._pointer = pointer
        return inst

    

    def encrypt_by_opcode_shift(self, plain_text,key):
        plain_text = list(int(x) for x in plain_text)
        
        key = int(key)
        
        return FfiConverterSequenceUInt8.lift(
            rust_call(_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_encrypt_by_opcode_shift,self._pointer,
        FfiConverterSequenceUInt8.lower(plain_text),
        FfiConverterUInt32.lower(key))
        )
    def encrypt_by_alphabet_shift(self, plain_text,key):
        plain_text = list(int(x) for x in plain_text)
        
        key = int(key)
        
        return FfiConverterSequenceUInt8.lift(
            rust_call(_UniFFILib.cryptatools_ac35_CaesarNumberAlgorithm_encrypt_by_alphabet_shift,self._pointer,
        FfiConverterSequenceUInt8.lower(plain_text),
        FfiConverterUInt32.lower(key))
        )
    


class FfiConverterTypeCaesarNumberAlgorithm:
    @classmethod
    def read(cls, buf):
        ptr = buf.readU64()
        if ptr == 0:
            raise InternalError("Raw pointer value was null")
        return cls.lift(ptr)

    @classmethod
    def write(cls, value, buf):
        if not isinstance(value, CaesarNumberAlgorithm):
            raise TypeError("Expected CaesarNumberAlgorithm instance, {} found".format(value.__class__.__name__))
        buf.writeU64(cls.lower(value))

    @staticmethod
    def lift(value):
        return CaesarNumberAlgorithm._make_instance_(value)

    @staticmethod
    def lower(value):
        return value._pointer



class ColumnarTranspositionAlgorithm(object):
    def __init__(self, alphabet):
        alphabet = alphabet
        
        self._pointer = rust_call(_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_new,
        FfiConverterTypeAlphabet.lower(alphabet))

    def __del__(self):
        # In case of partial initialization of instances.
        pointer = getattr(self, "_pointer", None)
        if pointer is not None:
            rust_call(_UniFFILib.ffi_cryptatools_ac35_ColumnarTranspositionAlgorithm_object_free, pointer)

    # Used by alternative constructors or any methods which return this type.
    @classmethod
    def _make_instance_(cls, pointer):
        # Lightly yucky way to bypass the usual __init__ logic
        # and just create a new instance with the required pointer.
        inst = cls.__new__(cls)
        inst._pointer = pointer
        return inst

    

    def encrypt(self, plain_text,key):
        plain_text = list(int(x) for x in plain_text)
        
        key = int(key)
        
        return FfiConverterSequenceUInt8.lift(
            rust_call(_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_encrypt,self._pointer,
        FfiConverterSequenceUInt8.lower(plain_text),
        FfiConverterUInt32.lower(key))
        )
    def decrypt(self, cipher_text,key):
        cipher_text = list(int(x) for x in cipher_text)
        
        key = int(key)
        
        return FfiConverterSequenceUInt8.lift(
            rust_call(_UniFFILib.cryptatools_ac35_ColumnarTranspositionAlgorithm_decrypt,self._pointer,
        FfiConverterSequenceUInt8.lower(cipher_text),
        FfiConverterUInt32.lower(key))
        )
    


class FfiConverterTypeColumnarTranspositionAlgorithm:
    @classmethod
    def read(cls, buf):
        ptr = buf.readU64()
        if ptr == 0:
            raise InternalError("Raw pointer value was null")
        return cls.lift(ptr)

    @classmethod
    def write(cls, value, buf):
        if not isinstance(value, ColumnarTranspositionAlgorithm):
            raise TypeError("Expected ColumnarTranspositionAlgorithm instance, {} found".format(value.__class__.__name__))
        buf.writeU64(cls.lower(value))

    @staticmethod
    def lift(value):
        return ColumnarTranspositionAlgorithm._make_instance_(value)

    @staticmethod
    def lower(value):
        return value._pointer


class Encoding:

    def __init__(self, str, bytes):
        self.str = str
        self.bytes = bytes

    def __str__(self):
        return "Encoding(str={}, bytes={})".format(self.str, self.bytes)

    def __eq__(self, other):
        if self.str != other.str:
            return False
        if self.bytes != other.bytes:
            return False
        return True

class FfiConverterTypeEncoding(FfiConverterRustBuffer):
    @staticmethod
    def read(buf):
        return Encoding(
            str=FfiConverterString.read(buf),
            bytes=FfiConverterSequenceUInt8.read(buf),
        )

    @staticmethod
    def write(value, buf):
        FfiConverterString.write(value.str, buf)
        FfiConverterSequenceUInt8.write(value.bytes, buf)



class FfiConverterSequenceUInt8(FfiConverterRustBuffer):
    @classmethod
    def write(cls, value, buf):
        items = len(value)
        buf.writeI32(items)
        for item in value:
            FfiConverterUInt8.write(item, buf)

    @classmethod
    def read(cls, buf):
        count = buf.readI32()
        if count < 0:
            raise InternalError("Unexpected negative sequence length")

        return [
            FfiConverterUInt8.read(buf) for i in range(count)
        ]



class FfiConverterSequenceTypeEncoding(FfiConverterRustBuffer):
    @classmethod
    def write(cls, value, buf):
        items = len(value)
        buf.writeI32(items)
        for item in value:
            FfiConverterTypeEncoding.write(item, buf)

    @classmethod
    def read(cls, buf):
        count = buf.readI32()
        if count < 0:
            raise InternalError("Unexpected negative sequence length")

        return [
            FfiConverterTypeEncoding.read(buf) for i in range(count)
        ]



class FfiConverterSequenceSequenceUInt8(FfiConverterRustBuffer):
    @classmethod
    def write(cls, value, buf):
        items = len(value)
        buf.writeI32(items)
        for item in value:
            FfiConverterSequenceUInt8.write(item, buf)

    @classmethod
    def read(cls, buf):
        count = buf.readI32()
        if count < 0:
            raise InternalError("Unexpected negative sequence length")

        return [
            FfiConverterSequenceUInt8.read(buf) for i in range(count)
        ]

def split_bytes_by_characters_representation(encoding,text):
    encoding = encoding
    
    text = list(int(x) for x in text)
    
    return FfiConverterSequenceSequenceUInt8.lift(rust_call(_UniFFILib.cryptatools_ac35_split_bytes_by_characters_representation,
        FfiConverterTypeAlphabet.lower(encoding),
        FfiConverterSequenceUInt8.lower(text)))



def uniffy_opcode_group(text):
    text = list(list(int(x) for x in x) for x in text)
    
    return FfiConverterSequenceUInt8.lift(rust_call(_UniFFILib.cryptatools_ac35_uniffy_opcode_group,
        FfiConverterSequenceSequenceUInt8.lower(text)))



__all__ = [
    "InternalError",
    "Encoding",
    "split_bytes_by_characters_representation",
    "uniffy_opcode_group",
    "Alphabet",
    "CaesarNumberAlgorithm",
    "ColumnarTranspositionAlgorithm",
]

