Source code

Revision control

Copy as Markdown

Other Tools

# Put all the bits inside a class to keep the top-level namespace clean
class {{ trait_impl }}:
# For each method, generate a callback function to pass to Rust
{%- for meth in vtable.methods %}
{%- let callable = meth.callable %}
@{{ meth.ffi_type.type_name }}
def {{ callable.name }}(
uniffi_handle,
{%- for arg in callable.arguments %}
{{ arg.name }},
{%- endfor -%}
{%- if !callable.is_async %}
uniffi_out_return,
uniffi_call_status_ptr,
{%- else %}
uniffi_future_callback,
uniffi_callback_data,
uniffi_out_dropped_callback,
{%- endif %}
):
uniffi_obj = {{ ffi_converter_name }}._handle_map.get(uniffi_handle)
def make_call():
uniffi_args = ({% for arg in callable.arguments %}{{ arg.ty.ffi_converter_name }}.lift({{ arg.name }}), {% endfor %})
uniffi_method = uniffi_obj.{{ callable.name }}
return uniffi_method(*uniffi_args)
{%- match callable.async_data %}
{%- when None %}
{%- match callable.return_type.ty %}
{%- when Some(return_type) %}
def write_return_value(v):
uniffi_out_return[0] = {{ return_type.ffi_converter_name }}.lower(v)
{%- when None %}
write_return_value = lambda v: None
{%- endmatch %}
{%- match callable.throws_type.ty %}
{%- when None %}
_uniffi_trait_interface_call(
uniffi_call_status_ptr.contents,
make_call,
write_return_value,
)
{%- when Some(error) %}
_uniffi_trait_interface_call_with_error(
uniffi_call_status_ptr.contents,
make_call,
write_return_value,
{{ error.type_name }},
{{ error.ffi_converter_name }}.lower,
)
{%- endmatch %}
{%- when Some(async_data) %}
def handle_success(return_value):
uniffi_future_callback(
uniffi_callback_data,
{{ async_data.ffi_foreign_future_result.0 }}(
{%- if let Some(return_type) = callable.return_type.ty %}
{{ return_type.ffi_converter_name }}.lower(return_value),
{%- endif %}
_UniffiRustCallStatus.default()
)
)
def handle_error(status_code, rust_buffer):
uniffi_future_callback(
uniffi_callback_data,
{{ async_data.ffi_foreign_future_result.0 }}(
{%- match callable.return_type.ty %}
{%- when Some(return_type) %}
{{ meth.ffi_default_value }},
{%- when None %}
{%- endmatch %}
_UniffiRustCallStatus(status_code, rust_buffer),
)
)
{%- match callable.throws_type.ty %}
{%- when None %}
_uniffi_trait_interface_call_async(make_call, uniffi_out_dropped_callback, handle_success, handle_error)
{%- when Some(error) %}
_uniffi_trait_interface_call_async_with_error(
make_call,
uniffi_out_dropped_callback,
handle_success,
handle_error,
{{ error.type_name }},
{{ error.ffi_converter_name }}.lower,
)
{%- endmatch %}
{%- endmatch %}
{%- endfor %}
@{{ vtable.free_fn_type.0 }}
def _uniffi_free(uniffi_handle):
{{ ffi_converter_name }}._handle_map.remove(uniffi_handle)
@{{ vtable.clone_fn_type.0 }}
def _uniffi_clone(uniffi_handle):
return {{ ffi_converter_name }}._handle_map.clone(uniffi_handle)
# Generate the FFI VTable. This has a field for each callback interface method.
_uniffi_vtable = {{ vtable.struct_type.type_name }}(
_uniffi_free,
_uniffi_clone,
{%- for meth in vtable.methods %}
{{ meth.callable.name }},
{%- endfor %}
)
# Send Rust a pointer to the VTable. Note: this means we need to keep the struct alive forever,
# or else bad things will happen when Rust tries to access it.
_UniffiLib.{{ vtable.init_fn.0 }}(ctypes.byref(_uniffi_vtable))