summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_bindgen/src/bindings/python/templates/ForeignExecutorTemplate.py
blob: 6a6932fed06fc1d00641e602f2750a00ac5ea991 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# FFI code for the ForeignExecutor type

{{ self.add_import("asyncio") }}

_UNIFFI_RUST_TASK_CALLBACK_SUCCESS = 0
_UNIFFI_RUST_TASK_CALLBACK_CANCELLED = 1
_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS = 0
_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELED = 1
_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_ERROR = 2

class {{ ffi_converter_name }}:
    _pointer_manager = _UniffiPointerManager()

    @classmethod
    def lower(cls, eventloop):
        if not isinstance(eventloop, asyncio.BaseEventLoop):
            raise TypeError("_uniffi_executor_callback: Expected EventLoop instance")
        return cls._pointer_manager.new_pointer(eventloop)

    @classmethod
    def write(cls, eventloop, buf):
        buf.write_c_size_t(cls.lower(eventloop))

    @classmethod
    def read(cls, buf):
        return cls.lift(buf.read_c_size_t())

    @classmethod
    def lift(cls, value):
        return cls._pointer_manager.lookup(value)

@_UNIFFI_FOREIGN_EXECUTOR_CALLBACK_T
def _uniffi_executor_callback(eventloop_address, delay, task_ptr, task_data):
    if task_ptr is None:
        {{ ffi_converter_name }}._pointer_manager.release_pointer(eventloop_address)
        return _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS
    else:
        eventloop = {{ ffi_converter_name }}._pointer_manager.lookup(eventloop_address)
        if eventloop.is_closed():
            return _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_CANCELED

        callback = _UNIFFI_RUST_TASK(task_ptr)
        # FIXME: there's no easy way to get a callback when an eventloop is closed.  This means that
        # if eventloop is called before the `call_soon_threadsafe()` calls are invoked, the call
        # will never happen and we will probably leak a resource.
        if delay == 0:
            # This can be called from any thread, so make sure to use `call_soon_threadsafe'
            eventloop.call_soon_threadsafe(callback, task_data,
                                           _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS)
        else:
            # For delayed tasks, we use `call_soon_threadsafe()` + `call_later()` to make the
            # operation threadsafe
            eventloop.call_soon_threadsafe(eventloop.call_later, delay / 1000.0, callback,
                                           task_data, _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS)
        return _UNIFFI_FOREIGN_EXECUTOR_CALLBACK_SUCCESS

# Register the callback with the scaffolding
{%- match ci.ffi_foreign_executor_callback_set() %}
{%- when Some with (fn) %}
_UniffiLib.{{ fn.name() }}(_uniffi_executor_callback)
{%- when None %}
{#- No foreign executor, we don't set anything #}
{% endmatch %}