#include <Python.h>
#include <float.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

{% if module.uses_owned_buffer_returns() %}
typedef struct FfiBuf_u8 { uint8_t* ptr; size_t len; size_t cap; size_t align; } FfiBuf_u8;
typedef void (*boltffi_python_free_buf_fn)(FfiBuf_u8);
static boltffi_python_free_buf_fn boltffi_python_free_buf_symbol = NULL;
{% endif %}
{% if module.uses_records() %}
{% for record in module.records %}
static PyObject *{{ record.type_ref.type_object_name() }} = NULL;
{% endfor %}
{% endif %}
{% if module.uses_c_style_enums() %}
typedef struct boltffi_python_c_style_enum_registration {
    PyObject *type_object;
    Py_ssize_t member_count;
    PyObject **members_by_wire_tag;
} boltffi_python_c_style_enum_registration;

{% for enumeration in module.enums %}
static PyObject *{{ enumeration.type_ref.member_cache_name() }}[{{ enumeration.variants.len() }}] = {NULL};
static const char *{{ enumeration.type_ref.member_name_table_name() }}[{{ enumeration.variants.len() }}] = {
{% for variant in enumeration.variants %}
    "{{ variant.member_name }}"{% if !loop.last %}, {% endif %}
{% endfor %}
};
static const {{ enumeration.type_ref.tag_type.c_type_name() }} {{ enumeration.type_ref.member_native_value_table_name() }}[{{ enumeration.variants.len() }}] = {
{% for variant in enumeration.variants %}
    {{ variant.native_c_literal }}{% if !loop.last %}, {% endif %}
{% endfor %}
};
static boltffi_python_c_style_enum_registration {{ enumeration.type_ref.registration_name() }} = {
    NULL,
    {{ enumeration.variants.len() }},
    {{ enumeration.type_ref.member_cache_name() }},
};
{% endfor %}
{% endif %}
{% if module.uses_records() %}
{% for record in module.records %}
typedef struct {
{% for field in record.fields.iter() %}
    {{ field.primitive.c_type_name() }} {{ field.native_name }};
{% endfor %}
} {{ record.type_ref.c_type_name }};
{% endfor %}
{% endif %}
{% for binding in module.native_callables() %}
typedef {{ binding.callable.return_type.c_type_name() }} (*{{ binding.callable.function_pointer_typedef_name() }})({% if binding.callable.takes_no_parameters() %}void{% else %}{% for ffi_argument in binding.callable.ffi_arguments() %}{{ ffi_argument.c_type_name }}{% if !loop.last %}, {% endif %}{% endfor %}{% endif %});
static {{ binding.callable.function_pointer_typedef_name() }} {{ binding.callable.function_pointer_name() }} = NULL;
{% endfor %}
{% if module.has_native_callables() %}
#ifdef _WIN32
static HMODULE boltffi_python_library_handle = NULL;
#else
static void *boltffi_python_library_handle = NULL;
#endif

static void boltffi_python_unload_library(void) {
{% for binding in module.native_callables() %}
    {{ binding.callable.function_pointer_name() }} = NULL;
{% endfor %}
{% if module.uses_owned_buffer_returns() %}
    boltffi_python_free_buf_symbol = NULL;
{% endif %}
    if (boltffi_python_library_handle == NULL) {
        return;
    }
#ifdef _WIN32
    FreeLibrary(boltffi_python_library_handle);
#else
    dlclose(boltffi_python_library_handle);
#endif
    boltffi_python_library_handle = NULL;
}

static int boltffi_python_load_library(PyObject *library_path) {
#ifdef _WIN32
    wchar_t *wide_library_path = NULL;
#else
    const char *utf8_library_path = NULL;
    const char *loader_error = NULL;
#endif
    if (!PyUnicode_Check(library_path)) {
        PyErr_SetString(PyExc_TypeError, "expected str library path");
        return 0;
    }
#ifdef _WIN32
    wide_library_path = PyUnicode_AsWideCharString(library_path, NULL);
    if (wide_library_path == NULL) {
        return 0;
    }
    boltffi_python_library_handle = LoadLibraryW(wide_library_path);
    PyMem_Free(wide_library_path);
    if (boltffi_python_library_handle == NULL) {
        PyErr_Format(PyExc_ImportError, "failed to load native library from %S", library_path);
        return 0;
    }
#else
    utf8_library_path = PyUnicode_AsUTF8(library_path);
    if (utf8_library_path == NULL) {
        return 0;
    }
    dlerror();
    boltffi_python_library_handle = dlopen(utf8_library_path, RTLD_NOW | RTLD_LOCAL);
    if (boltffi_python_library_handle == NULL) {
        loader_error = dlerror();
        if (loader_error == NULL) {
            PyErr_Format(PyExc_ImportError, "failed to load native library from %S", library_path);
        } else {
            PyErr_Format(PyExc_ImportError, "failed to load native library from %S: %s", library_path, loader_error);
        }
        return 0;
    }
#endif
    return 1;
}

static int boltffi_python_bind_symbols(void) {
{% if module.uses_owned_buffer_returns() %}
#ifdef _WIN32
    boltffi_python_free_buf_symbol = (boltffi_python_free_buf_fn)GetProcAddress(boltffi_python_library_handle, "{{ module.free_buffer_symbol }}");
#else
    boltffi_python_free_buf_symbol = (boltffi_python_free_buf_fn)dlsym(boltffi_python_library_handle, "{{ module.free_buffer_symbol }}");
#endif
    if (boltffi_python_free_buf_symbol == NULL) {
        boltffi_python_unload_library();
        PyErr_SetString(PyExc_ImportError, "failed to resolve native symbol {{ module.free_buffer_symbol }}");
        return 0;
    }
{% endif %}
{% for binding in module.native_callables() %}
#ifdef _WIN32
    {{ binding.callable.function_pointer_name() }} = ({{ binding.callable.function_pointer_typedef_name() }})GetProcAddress(boltffi_python_library_handle, "{{ binding.callable.ffi_symbol }}");
#else
    {{ binding.callable.function_pointer_name() }} = ({{ binding.callable.function_pointer_typedef_name() }})dlsym(boltffi_python_library_handle, "{{ binding.callable.ffi_symbol }}");
#endif
    if ({{ binding.callable.function_pointer_name() }} == NULL) {
        boltffi_python_unload_library();
        PyErr_SetString(PyExc_ImportError, "failed to resolve native symbol {{ binding.callable.ffi_symbol }}");
        return 0;
    }
{% endfor %}
    return 1;
}

static PyObject *boltffi_python_initialize_loader(PyObject *self, PyObject *library_path) {
    (void)self;
    if (boltffi_python_library_handle != NULL) {
        Py_RETURN_NONE;
    }
    if (!boltffi_python_load_library(library_path)) {
        return NULL;
    }
    if (!boltffi_python_bind_symbols()) {
        return NULL;
    }
    Py_RETURN_NONE;
}
{% endif %}
{% if module.uses_string_parameters() %}

typedef struct boltffi_python_utf8_input {
    const uint8_t *ptr;
    uintptr_t len;
} boltffi_python_utf8_input;

static int boltffi_python_parse_string(PyObject *value, boltffi_python_utf8_input *out) {
    const char *utf8_data = NULL;
    Py_ssize_t utf8_length = 0;
    if (!PyUnicode_Check(value)) {
        PyErr_SetString(PyExc_TypeError, "expected str");
        return 0;
    }
    utf8_data = PyUnicode_AsUTF8AndSize(value, &utf8_length);
    if (utf8_data == NULL) {
        return 0;
    }
    out->ptr = (const uint8_t *)utf8_data;
    out->len = (uintptr_t)utf8_length;
    return 1;
}
{% endif %}
{% if module.uses_buffer_input_parameters() %}

typedef struct boltffi_python_buffer_input {
    const void *ptr;
    uintptr_t len;
    Py_buffer view;
    void *owned_copy;
    int has_view;
} boltffi_python_buffer_input;

static void boltffi_python_init_buffer_input(boltffi_python_buffer_input *input) {
    input->ptr = NULL;
    input->len = 0;
    input->owned_copy = NULL;
    input->has_view = 0;
    memset(&input->view, 0, sizeof(Py_buffer));
}

static void boltffi_python_release_buffer_input(boltffi_python_buffer_input *input) {
    if (input->has_view) {
        PyBuffer_Release(&input->view);
    }
    if (input->owned_copy != NULL) {
        PyMem_Free(input->owned_copy);
    }
    boltffi_python_init_buffer_input(input);
}

static const char *boltffi_python_skip_native_buffer_format_prefix(const char *format) {
    if (format == NULL) {
        return NULL;
    }
    while (*format == '@' || *format == '=') {
        format += 1;
    }
    return format;
}

static int boltffi_python_try_parse_bytes_like_buffer(
    PyObject *value,
    boltffi_python_buffer_input *out
) {
    if (PyObject_GetBuffer(value, &out->view, PyBUF_CONTIG_RO) != 0) {
        return 0;
    }
    if (out->view.ndim != 1 || out->view.itemsize != 1) {
        PyBuffer_Release(&out->view);
        memset(&out->view, 0, sizeof(Py_buffer));
        return 0;
    }
    out->ptr = out->view.buf;
    out->len = (uintptr_t)out->view.len;
    out->has_view = 1;
    return 1;
}

static int boltffi_python_parse_bytes(PyObject *value, boltffi_python_buffer_input *out) {
    boltffi_python_init_buffer_input(out);
    if (!boltffi_python_try_parse_bytes_like_buffer(value, out)) {
        PyErr_Clear();
        PyErr_SetString(PyExc_TypeError, "expected bytes-like object");
        return 0;
    }
    return 1;
}
{% endif %}
{% if !used_primitive_types.is_empty() %}

{% for primitive in used_primitive_types %}
static int {{ primitive.parser_name() }}(PyObject *value, {{ primitive.c_type_name() }} *out) {
{% if primitive.uses_bool_parser() %}
    if (!PyBool_Check(value)) {
        PyErr_SetString(PyExc_TypeError, "expected bool");
        return 0;
    }
    *out = value == Py_True;
    return 1;
{% elif primitive.uses_signed_long_long_parser() %}
    long long parsed = PyLong_AsLongLong(value);
    if (parsed == -1 && PyErr_Occurred()) {
        return 0;
    }
    if (parsed < {{ primitive.signed_min_macro() }} || parsed > {{ primitive.signed_max_macro() }}) {
        PyErr_SetString(PyExc_OverflowError, "{{ primitive.rust_name() }} out of range");
        return 0;
    }
    *out = ({{ primitive.c_type_name() }})parsed;
    return 1;
{% elif primitive.uses_unsigned_long_long_with_range_check() %}
    unsigned long long parsed = PyLong_AsUnsignedLongLong(value);
    if (PyErr_Occurred()) {
        return 0;
    }
    if (parsed > {{ primitive.unsigned_max_macro() }}) {
        PyErr_SetString(PyExc_OverflowError, "{{ primitive.rust_name() }} out of range");
        return 0;
    }
    *out = ({{ primitive.c_type_name() }})parsed;
    return 1;
{% elif primitive.uses_u64_parser() %}
    unsigned long long parsed = PyLong_AsUnsignedLongLong(value);
    if (PyErr_Occurred()) {
        return 0;
    }
    *out = (uint64_t)parsed;
    return 1;
{% elif primitive.uses_isize_parser() %}
    Py_ssize_t parsed = PyLong_AsSsize_t(value);
    if (parsed == -1 && PyErr_Occurred()) {
        return 0;
    }
    *out = (intptr_t)parsed;
    return 1;
{% elif primitive.uses_usize_parser() %}
    size_t parsed = PyLong_AsSize_t(value);
    if (parsed == (size_t)-1 && PyErr_Occurred()) {
        return 0;
    }
    *out = (uintptr_t)parsed;
    return 1;
{% elif primitive.uses_f32_parser() %}
    double parsed = PyFloat_AsDouble(value);
    if (parsed == -1.0 && PyErr_Occurred()) {
        return 0;
    }
    if (parsed < -(double)FLT_MAX || parsed > (double)FLT_MAX) {
        PyErr_SetString(PyExc_OverflowError, "f32 out of range");
        return 0;
    }
    *out = (float)parsed;
    return 1;
{% elif primitive.uses_f64_parser() %}
    double parsed = PyFloat_AsDouble(value);
    if (parsed == -1.0 && PyErr_Occurred()) {
        return 0;
    }
    *out = parsed;
    return 1;
{% endif %}
}

static PyObject *{{ primitive.boxer_name() }}({{ primitive.c_type_name() }} value) {
{% if primitive.boxes_as_bool() %}
    return PyBool_FromLong(value ? 1 : 0);
{% elif primitive.boxes_as_signed_long() %}
    return PyLong_FromLong((long)value);
{% elif primitive.boxes_as_unsigned_long() %}
    return PyLong_FromUnsignedLong((unsigned long)value);
{% elif primitive.boxes_as_signed_long_long() %}
    return PyLong_FromLongLong((long long)value);
{% elif primitive.boxes_as_unsigned_long_long() %}
    return PyLong_FromUnsignedLongLong((unsigned long long)value);
{% elif primitive.boxes_as_ssize() %}
    return PyLong_FromSsize_t((Py_ssize_t)value);
{% elif primitive.boxes_as_size() %}
    return PyLong_FromSize_t((size_t)value);
{% elif primitive.boxes_as_double() %}
    return PyFloat_FromDouble((double)value);
{% endif %}
}

{% endfor %}
{% endif %}
{% if !module.used_primitive_vector_parameter_types().is_empty() %}

typedef enum boltffi_python_buffer_kind {
    BOLTFFI_PY_BUFFER_UNKNOWN = 0,
    BOLTFFI_PY_BUFFER_BOOL,
    BOLTFFI_PY_BUFFER_I8,
    BOLTFFI_PY_BUFFER_U8,
    BOLTFFI_PY_BUFFER_I16,
    BOLTFFI_PY_BUFFER_U16,
    BOLTFFI_PY_BUFFER_I32,
    BOLTFFI_PY_BUFFER_U32,
    BOLTFFI_PY_BUFFER_I64,
    BOLTFFI_PY_BUFFER_U64,
    BOLTFFI_PY_BUFFER_ISIZE,
    BOLTFFI_PY_BUFFER_USIZE,
    BOLTFFI_PY_BUFFER_F32,
    BOLTFFI_PY_BUFFER_F64
} boltffi_python_buffer_kind;

static Py_ssize_t boltffi_python_buffer_kind_item_size(boltffi_python_buffer_kind kind) {
    switch (kind) {
        case BOLTFFI_PY_BUFFER_BOOL:
            return (Py_ssize_t)sizeof(bool);
        case BOLTFFI_PY_BUFFER_I8:
            return (Py_ssize_t)sizeof(int8_t);
        case BOLTFFI_PY_BUFFER_U8:
            return (Py_ssize_t)sizeof(uint8_t);
        case BOLTFFI_PY_BUFFER_I16:
            return (Py_ssize_t)sizeof(int16_t);
        case BOLTFFI_PY_BUFFER_U16:
            return (Py_ssize_t)sizeof(uint16_t);
        case BOLTFFI_PY_BUFFER_I32:
            return (Py_ssize_t)sizeof(int32_t);
        case BOLTFFI_PY_BUFFER_U32:
            return (Py_ssize_t)sizeof(uint32_t);
        case BOLTFFI_PY_BUFFER_I64:
            return (Py_ssize_t)sizeof(int64_t);
        case BOLTFFI_PY_BUFFER_U64:
            return (Py_ssize_t)sizeof(uint64_t);
        case BOLTFFI_PY_BUFFER_ISIZE:
            return (Py_ssize_t)sizeof(intptr_t);
        case BOLTFFI_PY_BUFFER_USIZE:
            return (Py_ssize_t)sizeof(uintptr_t);
        case BOLTFFI_PY_BUFFER_F32:
            return (Py_ssize_t)sizeof(float);
        case BOLTFFI_PY_BUFFER_F64:
            return (Py_ssize_t)sizeof(double);
        case BOLTFFI_PY_BUFFER_UNKNOWN:
        default:
            return -1;
    }
}

static boltffi_python_buffer_kind boltffi_python_parse_buffer_kind(
    const char *format,
    Py_ssize_t item_size
) {
    const char *core = boltffi_python_skip_native_buffer_format_prefix(format);
    if (core == NULL) {
        return BOLTFFI_PY_BUFFER_UNKNOWN;
    }
    if (strcmp(core, "?") == 0 && item_size == (Py_ssize_t)sizeof(bool)) {
        return BOLTFFI_PY_BUFFER_BOOL;
    }
    if (strcmp(core, "b") == 0 && item_size == (Py_ssize_t)sizeof(int8_t)) {
        return BOLTFFI_PY_BUFFER_I8;
    }
    if (strcmp(core, "B") == 0 && item_size == (Py_ssize_t)sizeof(uint8_t)) {
        return BOLTFFI_PY_BUFFER_U8;
    }
    if (strcmp(core, "h") == 0 && item_size == (Py_ssize_t)sizeof(int16_t)) {
        return BOLTFFI_PY_BUFFER_I16;
    }
    if (strcmp(core, "H") == 0 && item_size == (Py_ssize_t)sizeof(uint16_t)) {
        return BOLTFFI_PY_BUFFER_U16;
    }
    if (strcmp(core, "i") == 0 && item_size == (Py_ssize_t)sizeof(int32_t)) {
        return BOLTFFI_PY_BUFFER_I32;
    }
    if (strcmp(core, "I") == 0 && item_size == (Py_ssize_t)sizeof(uint32_t)) {
        return BOLTFFI_PY_BUFFER_U32;
    }
    if (strcmp(core, "q") == 0 && item_size == (Py_ssize_t)sizeof(int64_t)) {
        return BOLTFFI_PY_BUFFER_I64;
    }
    if (strcmp(core, "Q") == 0 && item_size == (Py_ssize_t)sizeof(uint64_t)) {
        return BOLTFFI_PY_BUFFER_U64;
    }
    if (strcmp(core, "n") == 0 && item_size == (Py_ssize_t)sizeof(intptr_t)) {
        return BOLTFFI_PY_BUFFER_ISIZE;
    }
    if (strcmp(core, "N") == 0 && item_size == (Py_ssize_t)sizeof(uintptr_t)) {
        return BOLTFFI_PY_BUFFER_USIZE;
    }
    if (strcmp(core, "f") == 0 && item_size == (Py_ssize_t)sizeof(float)) {
        return BOLTFFI_PY_BUFFER_F32;
    }
    if (strcmp(core, "d") == 0 && item_size == (Py_ssize_t)sizeof(double)) {
        return BOLTFFI_PY_BUFFER_F64;
    }
    if (strcmp(core, "l") == 0) {
        if (item_size == (Py_ssize_t)sizeof(int32_t)) {
            return BOLTFFI_PY_BUFFER_I32;
        }
        if (item_size == (Py_ssize_t)sizeof(int64_t)) {
            return BOLTFFI_PY_BUFFER_I64;
        }
    }
    if (strcmp(core, "L") == 0) {
        if (item_size == (Py_ssize_t)sizeof(uint32_t)) {
            return BOLTFFI_PY_BUFFER_U32;
        }
        if (item_size == (Py_ssize_t)sizeof(uint64_t)) {
            return BOLTFFI_PY_BUFFER_U64;
        }
    }
    return BOLTFFI_PY_BUFFER_UNKNOWN;
}

static int boltffi_python_try_parse_typed_buffer(
    PyObject *value,
    boltffi_python_buffer_input *out,
    boltffi_python_buffer_kind expected_kind,
    int allow_untyped_buffer
) {
    boltffi_python_buffer_kind actual_kind = BOLTFFI_PY_BUFFER_UNKNOWN;
    Py_ssize_t expected_item_size = boltffi_python_buffer_kind_item_size(expected_kind);
    if (PyObject_GetBuffer(value, &out->view, PyBUF_FORMAT | PyBUF_C_CONTIGUOUS) != 0) {
        return 0;
    }
    if (out->view.ndim != 1 || out->view.itemsize != expected_item_size) {
        PyBuffer_Release(&out->view);
        memset(&out->view, 0, sizeof(Py_buffer));
        return 0;
    }
    if (out->view.format != NULL) {
        actual_kind = boltffi_python_parse_buffer_kind(out->view.format, out->view.itemsize);
        if (actual_kind != expected_kind) {
            PyBuffer_Release(&out->view);
            memset(&out->view, 0, sizeof(Py_buffer));
            return 0;
        }
    } else if (!allow_untyped_buffer) {
        PyBuffer_Release(&out->view);
        memset(&out->view, 0, sizeof(Py_buffer));
        return 0;
    }
    out->ptr = out->view.buf;
    out->len = (uintptr_t)((size_t)out->view.len / (size_t)out->view.itemsize);
    out->has_view = 1;
    return 1;
}

{% for primitive in module.used_primitive_vector_parameter_types() %}
static int {{ primitive.vector_parser_name() }}(PyObject *value, boltffi_python_buffer_input *out) {
    PyObject *sequence = NULL;
    Py_ssize_t sequence_length = 0;
    Py_ssize_t index = 0;
    {{ primitive.c_type_name() }} *owned_copy = NULL;
    boltffi_python_init_buffer_input(out);
    if (boltffi_python_try_parse_typed_buffer(
        value,
        out,
        {{ primitive.buffer_kind_constant() }},
        {% if primitive.allows_untyped_vector_buffer() %}1{% else %}0{% endif %}
    )) {
        return 1;
    }
    PyErr_Clear();
    sequence = PySequence_Fast(value, "expected sequence");
    if (sequence == NULL) {
        return 0;
    }
    sequence_length = PySequence_Fast_GET_SIZE(sequence);
    if ((size_t)sequence_length > (size_t)UINTPTR_MAX) {
        Py_DECREF(sequence);
        PyErr_SetString(PyExc_OverflowError, "sequence is too large for Rust");
        return 0;
    }
    if (sequence_length > 0) {
        owned_copy = PyMem_Malloc((size_t)sequence_length * sizeof({{ primitive.c_type_name() }}));
        if (owned_copy == NULL) {
            Py_DECREF(sequence);
            PyErr_NoMemory();
            return 0;
        }
    }
    for (index = 0; index < sequence_length; index += 1) {
        if (!{{ primitive.parser_name() }}(PySequence_Fast_GET_ITEM(sequence, index), &owned_copy[index])) {
            PyMem_Free(owned_copy);
            Py_DECREF(sequence);
            return 0;
        }
    }
    Py_DECREF(sequence);
    out->ptr = owned_copy;
    out->len = (uintptr_t)sequence_length;
    out->owned_copy = owned_copy;
    return 1;
}

{% endfor %}
{% endif %}
{% if module.uses_registered_types() %}

static int boltffi_python_validate_registered_type_object(PyObject *type_object, const char *type_name) {
    if (!PyType_Check(type_object)) {
        PyErr_Format(PyExc_TypeError, "expected type for %s", type_name);
        return 0;
    }
    return 1;
}

static int boltffi_python_store_registered_type(
    PyObject **type_slot,
    PyObject *type_object,
    const char *type_name
) {
    if (!boltffi_python_validate_registered_type_object(type_object, type_name)) {
        return 0;
    }
    Py_INCREF(type_object);
    Py_XDECREF(*type_slot);
    *type_slot = type_object;
    return 1;
}

static int boltffi_python_expect_registered_type(PyObject *type_object, const char *type_name) {
    if (type_object != NULL) {
        return 1;
    }
    PyErr_Format(PyExc_ImportError, "native type %s is not registered", type_name);
    return 0;
}

static int boltffi_python_expect_type_instance(
    PyObject *value,
    PyObject *type_object,
    const char *type_name
) {
    int is_instance = 0;
    if (!boltffi_python_expect_registered_type(type_object, type_name)) {
        return 0;
    }
    is_instance = PyObject_IsInstance(value, type_object);
    if (is_instance < 0) {
        return 0;
    }
    if (is_instance == 0) {
        PyErr_Format(PyExc_TypeError, "expected %s", type_name);
        return 0;
    }
    return 1;
}

{% if module.uses_c_style_enums() %}
typedef PyObject *(*boltffi_python_load_c_style_enum_member_fn)(PyObject *, Py_ssize_t);

static void boltffi_python_release_registered_enum_members(PyObject **members_by_wire_tag, Py_ssize_t member_count) {
    Py_ssize_t member_index = 0;
    for (member_index = 0; member_index < member_count; member_index += 1) {
        Py_XDECREF(members_by_wire_tag[member_index]);
        members_by_wire_tag[member_index] = NULL;
    }
}

static void boltffi_python_clear_c_style_enum_registration(
    boltffi_python_c_style_enum_registration *registration
) {
    Py_XDECREF(registration->type_object);
    registration->type_object = NULL;
    boltffi_python_release_registered_enum_members(
        registration->members_by_wire_tag,
        registration->member_count
    );
}

static PyObject *boltffi_python_load_c_style_enum_member(
    PyObject *type_object,
    const char *enum_name,
    const char *member_name,
    PyObject *native_value
) {
    PyObject *named_member = NULL;
    PyObject *resolved_member = NULL;
    if (native_value == NULL) {
        return NULL;
    }
    named_member = PyObject_GetAttrString(type_object, member_name);
    if (named_member == NULL) {
        return NULL;
    }
    resolved_member = PyObject_CallOneArg(type_object, native_value);
    if (resolved_member == NULL) {
        Py_DECREF(named_member);
        return NULL;
    }
    if (named_member != resolved_member) {
        PyErr_Format(PyExc_ValueError, "native enum %s member %s has the wrong value", enum_name, member_name);
        Py_DECREF(named_member);
        Py_DECREF(resolved_member);
        return NULL;
    }
    Py_DECREF(resolved_member);
    return named_member;
}

static int boltffi_python_store_c_style_enum_registration(
    boltffi_python_c_style_enum_registration *registration,
    PyObject *type_object,
    const char *enum_name,
    boltffi_python_load_c_style_enum_member_fn load_member
) {
    PyObject **loaded_members = NULL;
    Py_ssize_t member_index = 0;
    if (!boltffi_python_validate_registered_type_object(type_object, enum_name)) {
        return 0;
    }
    loaded_members = PyMem_Calloc((size_t)registration->member_count, sizeof(PyObject *));
    if (loaded_members == NULL) {
        PyErr_NoMemory();
        return 0;
    }
    for (member_index = 0; member_index < registration->member_count; member_index += 1) {
        loaded_members[member_index] = load_member(type_object, member_index);
        if (loaded_members[member_index] == NULL) {
            boltffi_python_release_registered_enum_members(loaded_members, registration->member_count);
            PyMem_Free(loaded_members);
            return 0;
        }
    }
    boltffi_python_clear_c_style_enum_registration(registration);
    if (!boltffi_python_store_registered_type(&registration->type_object, type_object, enum_name)) {
        boltffi_python_release_registered_enum_members(loaded_members, registration->member_count);
        PyMem_Free(loaded_members);
        return 0;
    }
    for (member_index = 0; member_index < registration->member_count; member_index += 1) {
        registration->members_by_wire_tag[member_index] = loaded_members[member_index];
    }
    PyMem_Free(loaded_members);
    return 1;
}

static int boltffi_python_expect_enum_instance(
    PyObject *value,
    const boltffi_python_c_style_enum_registration *registration,
    const char *enum_name
) {
    return boltffi_python_expect_type_instance(value, registration->type_object, enum_name);
}
{% endif %}
{% endif %}
{% if module.uses_c_style_enums() %}

static PyObject *boltffi_python_box_registered_enum_member(
    const boltffi_python_c_style_enum_registration *registration,
    Py_ssize_t member_index,
    const char *enum_name
) {
    PyObject *member = NULL;
    if (!boltffi_python_expect_registered_type(registration->type_object, enum_name)) {
        return NULL;
    }
    if (member_index < 0 || member_index >= registration->member_count) {
        PyErr_SetString(PyExc_RuntimeError, "native enum member index is invalid");
        return NULL;
    }
    if (registration->members_by_wire_tag[member_index] == NULL) {
        PyErr_Format(PyExc_ImportError, "native enum %s member cache is not initialized", enum_name);
        return NULL;
    }
    member = registration->members_by_wire_tag[member_index];
    Py_INCREF(member);
    return member;
}

{% for enumeration in module.enums %}
static PyObject *{{ enumeration.type_ref.member_loader_name() }}(PyObject *type_object, Py_ssize_t member_index) {
    PyObject *native_value = NULL;
    PyObject *member = NULL;
    native_value = {{ enumeration.type_ref.tag_type.boxer_name() }}({{ enumeration.type_ref.member_native_value_table_name() }}[member_index]);
    member = boltffi_python_load_c_style_enum_member(
        type_object,
        "{{ enumeration.class_name() }}",
        {{ enumeration.type_ref.member_name_table_name() }}[member_index],
        native_value
    );
    Py_XDECREF(native_value);
    return member;
}

static PyObject *{{ enumeration.type_ref.registration_wrapper_name() }}(PyObject *self, PyObject *const *args, Py_ssize_t nargs) {
    (void)self;
    if (nargs != 1) {
        PyErr_Format(PyExc_TypeError, "{{ enumeration.type_ref.registration_function_name() }}() takes 1 positional argument but %zd were given", nargs);
        return NULL;
    }
    if (!boltffi_python_store_c_style_enum_registration(
        &{{ enumeration.type_ref.registration_name() }},
        args[0],
        "{{ enumeration.class_name() }}",
        {{ enumeration.type_ref.member_loader_name() }}
    )) {
        return NULL;
    }
    Py_RETURN_NONE;
}

static int {{ enumeration.type_ref.parser_name() }}(PyObject *value, {{ enumeration.type_ref.tag_type.c_type_name() }} *out) {
    if (!boltffi_python_expect_enum_instance(value, &{{ enumeration.type_ref.registration_name() }}, "{{ enumeration.class_name() }}")) {
        return 0;
    }
    return {{ enumeration.type_ref.tag_type.parser_name() }}(value, out);
}

static int {{ enumeration.type_ref.native_to_wire_tag_name() }}({{ enumeration.type_ref.tag_type.c_type_name() }} value, int32_t *out) {
    switch (value) {
{% for variant in enumeration.variants %}
        case {{ variant.native_c_literal }}:
            *out = {{ variant.wire_c_literal }};
            return 1;
{% endfor %}
        default:
            PyErr_SetString(PyExc_ValueError, "invalid {{ enumeration.class_name() }} value");
            return 0;
    }
}

static PyObject *{{ enumeration.type_ref.box_from_wire_tag_name() }}(int32_t wire_tag) {
    switch (wire_tag) {
{% for variant in enumeration.variants %}
        case {{ variant.wire_c_literal }}:
            return boltffi_python_box_registered_enum_member(
                &{{ enumeration.type_ref.registration_name() }},
                {{ loop.index0 }},
                "{{ enumeration.class_name() }}"
            );
{% endfor %}
        default:
            PyErr_SetString(PyExc_RuntimeError, "native enum wire tag is invalid");
            return NULL;
    }
}

static PyObject *{{ enumeration.type_ref.boxer_name() }}({{ enumeration.type_ref.tag_type.c_type_name() }} value) {
    int32_t wire_tag = 0;
    if (!{{ enumeration.type_ref.native_to_wire_tag_name() }}(value, &wire_tag)) {
        return NULL;
    }
    return {{ enumeration.type_ref.box_from_wire_tag_name() }}(wire_tag);
}

{% endfor %}
{% endif %}
{% if module.uses_records() %}

static PyObject *boltffi_python_get_record_field(
    PyObject *value,
    const char *record_name,
    const char *field_name
) {
    PyObject *field_value = PyObject_GetAttrString(value, field_name);
    if (field_value == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
        PyErr_Clear();
        PyErr_Format(PyExc_TypeError, "%s is missing field %s", record_name, field_name);
    }
    return field_value;
}

static PyObject *boltffi_python_box_registered_record(
    PyObject *type_object,
    PyObject *constructor_args,
    const char *record_name
) {
    PyObject *record_value = NULL;
    if (constructor_args == NULL) {
        return NULL;
    }
    if (!boltffi_python_expect_registered_type(type_object, record_name)) {
        Py_DECREF(constructor_args);
        return NULL;
    }
    record_value = PyObject_CallObject(type_object, constructor_args);
    Py_DECREF(constructor_args);
    return record_value;
}

{% for record in module.records %}
static PyObject *{{ record.type_ref.registration_wrapper_name() }}(PyObject *self, PyObject *const *args, Py_ssize_t nargs) {
    (void)self;
    if (nargs != 1) {
        PyErr_Format(PyExc_TypeError, "{{ record.type_ref.registration_function_name() }}() takes 1 positional argument but %zd were given", nargs);
        return NULL;
    }
    if (!boltffi_python_store_registered_type(
        &{{ record.type_ref.type_object_name() }},
        args[0],
        "{{ record.class_name() }}"
    )) {
        return NULL;
    }
    Py_RETURN_NONE;
}

static int {{ record.type_ref.parser_name() }}(PyObject *value, {{ record.type_ref.c_type_name }} *out) {
{% for field in record.fields.iter() %}
    PyObject *{{ field.python_name }}_value = NULL;
{% endfor %}
    int parsed = 0;
    if (!boltffi_python_expect_type_instance(value, {{ record.type_ref.type_object_name() }}, "{{ record.class_name() }}")) {
        return 0;
    }
{% for field in record.fields.iter() %}
    {{ field.python_name }}_value = boltffi_python_get_record_field(value, "{{ record.class_name() }}", "{{ field.python_name }}");
    if ({{ field.python_name }}_value == NULL) {
        goto cleanup;
    }
    if (!{{ field.primitive.parser_name() }}({{ field.python_name }}_value, &out->{{ field.native_name }})) {
        goto cleanup;
    }
    Py_DECREF({{ field.python_name }}_value);
    {{ field.python_name }}_value = NULL;
{% endfor %}
    parsed = 1;
cleanup:
{% for field in record.fields.iter() %}
    Py_XDECREF({{ field.python_name }}_value);
{% endfor %}
    return parsed;
}

static PyObject *{{ record.type_ref.boxer_name() }}({{ record.type_ref.c_type_name }} value) {
    PyObject *constructor_args = NULL;
    PyObject *field_value = NULL;
    constructor_args = PyTuple_New({{ record.field_count() }});
    if (constructor_args == NULL) {
        return NULL;
    }
{% for field in record.fields.iter() %}
    field_value = {{ field.primitive.boxer_name() }}(value.{{ field.native_name }});
    if (field_value == NULL) {
        Py_DECREF(constructor_args);
        return NULL;
    }
    PyTuple_SET_ITEM(constructor_args, {{ loop.index0 }}, field_value);
    field_value = NULL;
{% endfor %}
    return boltffi_python_box_registered_record(
        {{ record.type_ref.type_object_name() }},
        constructor_args,
        "{{ record.class_name() }}"
    );
}

{% endfor %}
{% endif %}
{% if !module.used_enum_vector_parameter_types().is_empty() %}

{% for enumeration in module.used_enum_vector_parameter_types() %}
static int {{ enumeration.vector_parser_name() }}(PyObject *value, boltffi_python_buffer_input *out) {
    PyObject *sequence = NULL;
    Py_ssize_t sequence_length = 0;
    Py_ssize_t index = 0;
    uint8_t *encoded_values = NULL;
    {{ enumeration.tag_type.c_type_name() }} native_value = 0;
    int32_t encoded_length = 0;
    int32_t wire_tag = 0;
    size_t encoded_size = 0;
    boltffi_python_init_buffer_input(out);
    sequence = PySequence_Fast(value, "expected sequence");
    if (sequence == NULL) {
        return 0;
    }
    sequence_length = PySequence_Fast_GET_SIZE(sequence);
    if (sequence_length > (Py_ssize_t)INT32_MAX) {
        Py_DECREF(sequence);
        PyErr_SetString(PyExc_OverflowError, "sequence is too large for Rust");
        return 0;
    }
    if ((size_t)sequence_length > ((size_t)UINTPTR_MAX - sizeof(int32_t)) / sizeof(int32_t)) {
        Py_DECREF(sequence);
        PyErr_SetString(PyExc_OverflowError, "sequence is too large for Rust");
        return 0;
    }
    encoded_size = sizeof(int32_t) + ((size_t)sequence_length * sizeof(int32_t));
    encoded_values = PyMem_Malloc(encoded_size);
    if (encoded_values == NULL) {
        Py_DECREF(sequence);
        PyErr_NoMemory();
        return 0;
    }
    encoded_length = (int32_t)sequence_length;
    memcpy(encoded_values, &encoded_length, sizeof(int32_t));
    for (index = 0; index < sequence_length; index += 1) {
        if (!{{ enumeration.parser_name() }}(PySequence_Fast_GET_ITEM(sequence, index), &native_value)) {
            PyMem_Free(encoded_values);
            Py_DECREF(sequence);
            return 0;
        }
        if (!{{ enumeration.native_to_wire_tag_name() }}(native_value, &wire_tag)) {
            PyMem_Free(encoded_values);
            Py_DECREF(sequence);
            return 0;
        }
        memcpy(
            encoded_values + sizeof(int32_t) + ((size_t)index * sizeof(int32_t)),
            &wire_tag,
            sizeof(int32_t)
        );
    }
    Py_DECREF(sequence);
    out->ptr = encoded_values;
    /* Encoded enum vectors cross the ABI as a byte buffer, so len is the encoded byte count here. */
    out->len = (uintptr_t)encoded_size;
    out->owned_copy = encoded_values;
    return 1;
}

{% endfor %}
{% endif %}
{% if module.uses_owned_buffer_returns() %}

static int boltffi_python_validate_owned_buffer(FfiBuf_u8 buffer) {
    if (buffer.ptr == NULL && buffer.len != 0) {
        PyErr_SetString(PyExc_RuntimeError, "native buffer is invalid");
        return 0;
    }
    return 1;
}
{% endif %}
{% if module.uses_string_returns() %}
static PyObject *boltffi_python_decode_owned_utf8(FfiBuf_u8 buffer) {
    PyObject *decoded = NULL;
    uint32_t utf8_length = 0;
    const char *utf8_data = "";
    if (!boltffi_python_validate_owned_buffer(buffer)) {
        boltffi_python_free_buf_symbol(buffer);
        return NULL;
    }
    if (buffer.len < sizeof(uint32_t)) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_RuntimeError, "native string buffer is invalid");
        return NULL;
    }
    memcpy(&utf8_length, buffer.ptr, sizeof(uint32_t));
    if (buffer.len != sizeof(uint32_t) + (size_t)utf8_length) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_RuntimeError, "native string buffer is invalid");
        return NULL;
    }
    if ((size_t)utf8_length > (size_t)PY_SSIZE_T_MAX) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_OverflowError, "string result is too large for Python");
        return NULL;
    }
    if (utf8_length != 0) {
        utf8_data = (const char *)(buffer.ptr + sizeof(uint32_t));
    }
    decoded = PyUnicode_DecodeUTF8(utf8_data, (Py_ssize_t)utf8_length, NULL);
    boltffi_python_free_buf_symbol(buffer);
    return decoded;
}
{% endif %}
{% if module.uses_bytes_returns() %}
static PyObject *boltffi_python_decode_owned_bytes(FfiBuf_u8 buffer) {
    PyObject *decoded = NULL;
    const char *byte_data = "";
    if (!boltffi_python_validate_owned_buffer(buffer)) {
        boltffi_python_free_buf_symbol(buffer);
        return NULL;
    }
    if ((size_t)buffer.len > (size_t)PY_SSIZE_T_MAX) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_OverflowError, "byte result is too large for Python");
        return NULL;
    }
    if (buffer.len != 0) {
        byte_data = (const char *)buffer.ptr;
    }
    decoded = PyBytes_FromStringAndSize(byte_data, (Py_ssize_t)buffer.len);
    boltffi_python_free_buf_symbol(buffer);
    return decoded;
}
{% endif %}
{% for primitive in module.used_primitive_vector_return_types() %}
static PyObject *boltffi_python_decode_owned_vec_{{ primitive.rust_name() }}(FfiBuf_u8 buffer) {
    PyObject *decoded = NULL;
    PyObject *item = NULL;
    Py_ssize_t item_count = 0;
    Py_ssize_t index = 0;
    const {{ primitive.c_type_name() }} *values = NULL;
    if (!boltffi_python_validate_owned_buffer(buffer)) {
        boltffi_python_free_buf_symbol(buffer);
        return NULL;
    }
    if (buffer.len % sizeof({{ primitive.c_type_name() }}) != 0) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_RuntimeError, "native vector buffer is invalid");
        return NULL;
    }
    if (buffer.len / sizeof({{ primitive.c_type_name() }}) > (size_t)PY_SSIZE_T_MAX) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_OverflowError, "vector result is too large for Python");
        return NULL;
    }
    item_count = (Py_ssize_t)(buffer.len / sizeof({{ primitive.c_type_name() }}));
    decoded = PyList_New(item_count);
    if (decoded == NULL) {
        boltffi_python_free_buf_symbol(buffer);
        return NULL;
    }
    values = (const {{ primitive.c_type_name() }} *)buffer.ptr;
    for (index = 0; index < item_count; index += 1) {
        item = {{ primitive.boxer_name() }}(values[index]);
        if (item == NULL) {
            Py_DECREF(decoded);
            boltffi_python_free_buf_symbol(buffer);
            return NULL;
        }
        PyList_SET_ITEM(decoded, index, item);
    }
    boltffi_python_free_buf_symbol(buffer);
    return decoded;
}
{% endfor %}
{% for enumeration in module.used_enum_vector_return_types() %}
static PyObject *{{ enumeration.vector_decoder_name() }}(FfiBuf_u8 buffer) {
    PyObject *decoded = NULL;
    PyObject *item = NULL;
    Py_ssize_t item_count = 0;
    Py_ssize_t index = 0;
    const uint8_t *encoded_values = NULL;
    int32_t encoded_length = 0;
    int32_t wire_tag = 0;
    size_t expected_size = 0;
    if (!boltffi_python_validate_owned_buffer(buffer)) {
        boltffi_python_free_buf_symbol(buffer);
        return NULL;
    }
    if (buffer.len < sizeof(int32_t)) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_RuntimeError, "native vector buffer is invalid");
        return NULL;
    }
    memcpy(&encoded_length, buffer.ptr, sizeof(int32_t));
    if (encoded_length < 0) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_RuntimeError, "native vector buffer is invalid");
        return NULL;
    }
    if ((size_t)encoded_length > ((size_t)SIZE_MAX - sizeof(int32_t)) / sizeof(int32_t)) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_RuntimeError, "native vector buffer is invalid");
        return NULL;
    }
    expected_size = sizeof(int32_t) + ((size_t)encoded_length * sizeof(int32_t));
    if (buffer.len != expected_size) {
        boltffi_python_free_buf_symbol(buffer);
        PyErr_SetString(PyExc_RuntimeError, "native vector buffer is invalid");
        return NULL;
    }
    item_count = (Py_ssize_t)encoded_length;
    decoded = PyList_New(item_count);
    if (decoded == NULL) {
        boltffi_python_free_buf_symbol(buffer);
        return NULL;
    }
    encoded_values = buffer.ptr;
    for (index = 0; index < item_count; index += 1) {
        memcpy(
            &wire_tag,
            encoded_values + sizeof(int32_t) + ((size_t)index * sizeof(int32_t)),
            sizeof(int32_t)
        );
        item = {{ enumeration.box_from_wire_tag_name() }}(wire_tag);
        if (item == NULL) {
            Py_DECREF(decoded);
            boltffi_python_free_buf_symbol(buffer);
            return NULL;
        }
        PyList_SET_ITEM(decoded, index, item);
    }
    boltffi_python_free_buf_symbol(buffer);
    return decoded;
}
{% endfor %}
{% for binding in module.native_callables() %}
static PyObject *{{ binding.callable.wrapper_name() }}(PyObject *self, PyObject *const *args, Py_ssize_t nargs) {
{% for parameter in binding.callable.parameters %}
{% for local_binding in parameter.local_bindings() %}
    {{ local_binding.c_type_name }} {{ local_binding.name }};
{% endfor %}
{% endfor %}
{% if !binding.callable.returns_void() %}
    {{ binding.callable.return_type.c_type_name() }} result;
{% endif %}
    PyObject *python_result = NULL;
    (void)self;
    if (nargs != {{ binding.callable.parameter_count() }}) {
        PyErr_Format(PyExc_TypeError, "{{ binding.module_attribute_name }}() takes {{ binding.callable.parameter_count() }} positional arguments but %zd were given", nargs);
        return NULL;
    }
    if ({{ binding.callable.function_pointer_name() }} == NULL) {
        PyErr_SetString(PyExc_ImportError, "native library is not initialized");
        return NULL;
    }
{% for parameter in binding.callable.parameters %}
{% if parameter.uses_buffer_input() %}
    boltffi_python_init_buffer_input(&{{ parameter.parser_state_name() }});
{% endif %}
    if (!{{ parameter.parser_name() }}(args[{{ loop.index0 }}], {% for parser_output in parameter.parser_output_arguments() %}{{ parser_output }}{% if !loop.last %}, {% endif %}{% endfor %})) {
        goto cleanup;
    }
{% endfor %}
{% if binding.callable.returns_void() %}
    {{ binding.callable.function_pointer_name() }}({% for ffi_argument in binding.callable.call_argument_expressions() %}{{ ffi_argument }}{% if !loop.last %}, {% endif %}{% endfor %});
    Py_INCREF(Py_None);
    python_result = Py_None;
{% else %}
    result = {{ binding.callable.function_pointer_name() }}({% for ffi_argument in binding.callable.call_argument_expressions() %}{{ ffi_argument }}{% if !loop.last %}, {% endif %}{% endfor %});
{% if binding.callable.returns_string() %}
    python_result = boltffi_python_decode_owned_utf8(result);
{% elif binding.callable.returns_record() %}
{% let return_record = binding.callable.return_record().unwrap() %}
    python_result = {{ return_record.boxer_name() }}(result);
{% elif binding.callable.returns_c_style_enum() %}
{% let return_enum = binding.callable.return_c_style_enum().unwrap() %}
    python_result = {{ return_enum.boxer_name() }}(result);
{% elif binding.callable.returns_bytes() %}
    python_result = boltffi_python_decode_owned_bytes(result);
{% elif binding.callable.returns_primitive_vector() %}
{% let return_primitive = binding.callable.return_vector_primitive().unwrap() %}
    python_result = boltffi_python_decode_owned_vec_{{ return_primitive.rust_name() }}(result);
{% elif binding.callable.returns_c_style_enum_vector() %}
{% let return_enum = binding.callable.return_vector_c_style_enum().unwrap() %}
    python_result = {{ return_enum.vector_decoder_name() }}(result);
{% else %}
{% let return_primitive = binding.callable.return_primitive().unwrap() %}
    python_result = {{ return_primitive.boxer_name() }}(result);
{% endif %}
{% endif %}
cleanup:
{% for cleanup_statement in binding.callable.cleanup_statements() %}
    {{ cleanup_statement }}
{% endfor %}
    return python_result;
}

{% endfor %}
static PyMethodDef boltffi_python_methods[] = {
{% if module.has_native_callables() %}
    {"_initialize_loader", (PyCFunction)boltffi_python_initialize_loader, METH_O, NULL},
{% endif %}
{% for record in module.records %}
    {"{{ record.type_ref.registration_function_name() }}", (PyCFunction){{ record.type_ref.registration_wrapper_name() }}, METH_FASTCALL, NULL},
{% endfor %}
{% for enumeration in module.enums %}
    {"{{ enumeration.type_ref.registration_function_name() }}", (PyCFunction){{ enumeration.type_ref.registration_wrapper_name() }}, METH_FASTCALL, NULL},
{% endfor %}
{% for binding in module.native_callables() %}
    {"{{ binding.module_attribute_name }}", (PyCFunction){{ binding.callable.wrapper_name() }}, METH_FASTCALL, NULL},
{% endfor %}
    {NULL, NULL, 0, NULL}
};

static struct PyModuleDef boltffi_python_module = {
    PyModuleDef_HEAD_INIT,
    "{{ module.module_name }}._native",
    NULL,
    -1,
    boltffi_python_methods,
};

PyMODINIT_FUNC PyInit__native(void) {
    return PyModule_Create(&boltffi_python_module);
}
