JNIEXPORT {{ jni_return_type }} JNICALL {{ jni_name }}(JNIEnv *env, jclass cls{{ jni_params }}) {
bool _boltffi_input_error = false;
{%- for param in params %}
{%- if param.is_string() %}
const char* _{{ param.name }}_c = {{ param.name }} ? (*env)->GetStringUTFChars(env, {{ param.name }}, NULL) : NULL;
if ({{ param.name }} != NULL && _{{ param.name }}_c == NULL) _boltffi_input_error = true;
{%- endif %}
{%- if param.is_primitive_array() %}
uintptr_t _{{ param.name }}_len = (uintptr_t)(*env)->GetArrayLength(env, {{ param.name }});
{{ param.array_c_type() }}* _{{ param.name }}_ptr = ({{ param.array_c_type() }}*)(*env)->{{ param.array_get_elements_fn() }}(env, {{ param.name }}, NULL);
if (_{{ param.name }}_ptr == NULL) { _{{ param.name }}_len = 0; _boltffi_input_error = true; }
{%- endif %}
{%- if param.is_buffer() %}
jlong _{{ param.name }}_size = (*env)->GetDirectBufferCapacity(env, {{ param.name }});
uint8_t* _{{ param.name }}_ptr = (uint8_t*)(*env)->GetDirectBufferAddress(env, {{ param.name }});
uintptr_t _{{ param.name }}_len = (_{{ param.name }}_ptr && _{{ param.name }}_size > 0) ? (uintptr_t)_{{ param.name }}_size : 0;
{%- endif %}
{%- if param.is_composite() %}
jlong _{{ param.name }}_size = (*env)->GetDirectBufferCapacity(env, {{ param.name }});
uint8_t* _{{ param.name }}_ptr = (uint8_t*)(*env)->GetDirectBufferAddress(env, {{ param.name }});
{{ param.composite_c_type() }} _{{ param.name }}_val;
if (_{{ param.name }}_ptr && _{{ param.name }}_size >= (jlong)sizeof({{ param.composite_c_type() }})) {
memcpy(&_{{ param.name }}_val, _{{ param.name }}_ptr, sizeof({{ param.composite_c_type() }}));
} else {
memset(&_{{ param.name }}_val, 0, sizeof({{ param.composite_c_type() }}));
_boltffi_input_error = true;
}
{%- endif %}
{%- endfor %}
{%- if return_is_direct %}
{{ jni_c_return_type }} _result = 0;
{%- elif return_composite_c_type.is_some() %}
{{ return_composite_c_type.as_ref().unwrap() }} _composite_result = {0};
{%- elif !return_is_unit %}
FfiBuf_u8 _buf = {0};
{%- endif %}
if (_boltffi_input_error) goto boltffi_input_cleanup;
{%- if return_is_unit %}
{{ ffi_name }}({% for param in params %}{{ param.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %});
{%- elif return_is_direct %}
_result = {{ ffi_name }}({% for param in params %}{{ param.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %});
{%- elif return_composite_c_type.is_some() %}
_composite_result = {{ ffi_name }}({% for param in params %}{{ param.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %});
{%- else %}
_buf = {{ ffi_name }}({% for param in params %}{{ param.ffi_arg() }}{% if !loop.last %}, {% endif %}{% endfor %});
{%- endif %}
boltffi_input_cleanup:
{%- for param in params %}
{%- if param.is_primitive_array() %}
if (_{{ param.name }}_ptr != NULL) (*env)->{{ param.array_release_elements_fn() }}(env, {{ param.name }}, ({{ param.array_elements_ptr_type() }})_{{ param.name }}_ptr, {{ param.array_release_mode() }});
{%- endif %}
{%- if param.is_string() %}
if (_{{ param.name }}_c) (*env)->ReleaseStringUTFChars(env, {{ param.name }}, _{{ param.name }}_c);
{%- endif %}
{%- endfor %}
{%- if return_is_unit %}
if (_boltffi_input_error) return;
{%- elif return_is_direct %}
if (_boltffi_input_error) return 0;
{%- else %}
if (_boltffi_input_error) return NULL;
{%- endif %}
{%- if return_is_direct %}
return {{ jni_result_cast }}_result;
{%- elif return_composite_c_type.is_some() %}
jsize _comp_size = (jsize)sizeof(_composite_result);
jbyteArray _arr = (*env)->NewByteArray(env, _comp_size);
if (_arr != NULL) (*env)->SetByteArrayRegion(env, _arr, 0, _comp_size, (const jbyte*)&_composite_result);
return _arr;
{%- elif !return_is_unit %}
return boltffi_buf_to_jbytearray(env, _buf);
{%- endif %}
}